Sync'ed JSBSim
Includes the following new features and bug fixes: - The <random> function now uses C++ std::default_random_engine - WGS84 is now used everywhere in JSBSim (previously a mix of spherical/WGS84 earcth was used resulting in inaccuracies). - A new <planet> XML element can be used to tweak the planet characteristics (such as semimajor/smemiminor axes, gravity, etc.) - The FGGroundCallback instance is now managed by FGInertial with a dynamic pointer std::unique_ptr<>. JSBSim was previously using a static pointer which was causing memory access failures when several instances of JSBSim were used or when an instance was replaced by a new one (the structure pointed to by the static pointer was then lost when the old instance was destroyed). - Removed calls to exit() and replaced them by exceptions that can be caught by FlightGear (should avoid FlightGear from being ungracefully stopped by an error found by JSBSim). - Sockets interface: replaced the usage of obsolete functions gethostbyname()/gethostbyaddr() by getaddrinfo(). - FGColumnVector3 and FGMatrix33 can now be initialized by C++ std::initializer_list - Disable the delays implemented in some flight control components during trimming (was sometimes preventing the trim algorithm from converging to a solution). - Fixed the magnetometer initialization (was not updated during the first 1000 time steps) - More conversions to C++11 features (nullptr, override, std::unique_ptr<>, etc.).
This commit is contained in:
parent
f4298d676f
commit
388d66b6a6
71 changed files with 1582 additions and 1026 deletions
|
@ -74,7 +74,7 @@ CLASS IMPLEMENTATION
|
|||
// Constructor
|
||||
|
||||
FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr)
|
||||
: Root(root), FDMctr(fdmctr)
|
||||
: Root(root), RandomEngine(new default_random_engine), FDMctr(fdmctr)
|
||||
{
|
||||
Frame = 0;
|
||||
IC = nullptr;
|
||||
|
@ -197,11 +197,6 @@ FGFDMExec::~FGFDMExec()
|
|||
}
|
||||
|
||||
for (unsigned int i=1; i<ChildFDMList.size(); i++) delete ChildFDMList[i]->exec;
|
||||
ChildFDMList.clear();
|
||||
|
||||
PropertyCatalog.clear();
|
||||
|
||||
SetGroundCallback(0);
|
||||
|
||||
if (FDMctr != 0) (*FDMctr)--;
|
||||
|
||||
|
@ -210,6 +205,25 @@ FGFDMExec::~FGFDMExec()
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGFDMExec::Setsim_time(double cur_time) {
|
||||
sim_time = cur_time;
|
||||
Inertial->SetTime(sim_time);
|
||||
return sim_time;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGFDMExec::IncrTime(void) {
|
||||
if (!holding && !IntegrationSuspended()) {
|
||||
sim_time += dT;
|
||||
Inertial->SetTime(sim_time);
|
||||
Frame++;
|
||||
}
|
||||
return sim_time;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGFDMExec::Allocate(void)
|
||||
{
|
||||
bool result=true;
|
||||
|
@ -221,7 +235,6 @@ bool FGFDMExec::Allocate(void)
|
|||
// Note that this does not affect the order in which the models will be
|
||||
// executed later.
|
||||
Models[eInertial] = new FGInertial(this);
|
||||
SetGroundCallback(new FGDefaultGroundCallback(static_cast<FGInertial*>(Models[eInertial])->GetRefRadius()));
|
||||
|
||||
// See the eModels enum specification in the header file. The order of the
|
||||
// enums specifies the order of execution. The Models[] vector is the primary
|
||||
|
@ -263,13 +276,7 @@ bool FGFDMExec::Allocate(void)
|
|||
LoadPlanetConstants();
|
||||
|
||||
// Initialize models
|
||||
for (unsigned int i = 0; i < Models.size(); i++) {
|
||||
// The Input/Output models must not be initialized prior to IC loading
|
||||
if (i == eInput || i == eOutput) continue;
|
||||
|
||||
LoadInputs(i);
|
||||
Models[i]->InitModel();
|
||||
}
|
||||
InitializeModels();
|
||||
|
||||
IC = new FGInitialCondition(this);
|
||||
IC->bind(instance);
|
||||
|
@ -281,6 +288,19 @@ bool FGFDMExec::Allocate(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGFDMExec::InitializeModels(void)
|
||||
{
|
||||
for (unsigned int i = 0; i < Models.size(); i++) {
|
||||
// The Input/Output models must not be initialized prior to IC loading
|
||||
if (i == eInput || i == eOutput) continue;
|
||||
|
||||
LoadInputs(i);
|
||||
Models[i]->InitModel();
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGFDMExec::DeAllocate(void)
|
||||
{
|
||||
|
||||
|
@ -511,7 +531,7 @@ void FGFDMExec::LoadPlanetConstants(void)
|
|||
Accelerations->in.vOmegaPlanet = Inertial->GetOmegaPlanet();
|
||||
Propagate->in.SemiMajor = Inertial->GetSemimajor();
|
||||
Propagate->in.SemiMinor = Inertial->GetSemiminor();
|
||||
Auxiliary->in.SLGravity = Inertial->SLgravity();
|
||||
Auxiliary->in.StandardGravity = Inertial->GetStandardGravity();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -526,8 +546,6 @@ void FGFDMExec::LoadModelConstants(void)
|
|||
Auxiliary->in.Wingspan = Aircraft->GetWingSpan();
|
||||
Auxiliary->in.Wingchord = Aircraft->Getcbar();
|
||||
GroundReactions->in.vXYZcg = MassBalance->GetXYZcg();
|
||||
|
||||
LoadPlanetConstants();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -587,13 +605,7 @@ void FGFDMExec::ResetToInitialConditions(int mode)
|
|||
|
||||
if (mode == 1) Output->SetStartNewOutput();
|
||||
|
||||
for (unsigned int i = 0; i < Models.size(); i++) {
|
||||
// The Input/Output models will be initialized during the RunIC() execution
|
||||
if (i == eInput || i == eOutput) continue;
|
||||
|
||||
LoadInputs(i);
|
||||
Models[i]->InitModel();
|
||||
}
|
||||
InitializeModels();
|
||||
|
||||
if (Script)
|
||||
Script->ResetEvents();
|
||||
|
@ -705,10 +717,23 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
|
||||
if (IsChild) debug_lvl = 0;
|
||||
|
||||
// Process the planet element. This element is OPTIONAL.
|
||||
element = document->FindElement("planet");
|
||||
if (element) {
|
||||
result = Models[eInertial]->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Planet element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
}
|
||||
// Reload the planet constants and re-initialize the models.
|
||||
LoadPlanetConstants();
|
||||
InitializeModels();
|
||||
}
|
||||
|
||||
// Process the metrics element. This element is REQUIRED.
|
||||
element = document->FindElement("metrics");
|
||||
if (element) {
|
||||
result = ((FGAircraft*)Models[eAircraft])->Load(element);
|
||||
result = Models[eAircraft]->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft metrics element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -721,7 +746,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the mass_balance element. This element is REQUIRED.
|
||||
element = document->FindElement("mass_balance");
|
||||
if (element) {
|
||||
result = ((FGMassBalance*)Models[eMassBalance])->Load(element);
|
||||
result = Models[eMassBalance]->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft mass_balance element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -734,7 +759,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the ground_reactions element. This element is REQUIRED.
|
||||
element = document->FindElement("ground_reactions");
|
||||
if (element) {
|
||||
result = ((FGGroundReactions*)Models[eGroundReactions])->Load(element);
|
||||
result = Models[eGroundReactions]->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << element->ReadFrom()
|
||||
<< "Aircraft ground_reactions element has problems in file "
|
||||
|
@ -749,7 +774,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the external_reactions element. This element is OPTIONAL.
|
||||
element = document->FindElement("external_reactions");
|
||||
if (element) {
|
||||
result = ((FGExternalReactions*)Models[eExternalReactions])->Load(element);
|
||||
result = Models[eExternalReactions]->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft external_reactions element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -759,7 +784,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the buoyant_forces element. This element is OPTIONAL.
|
||||
element = document->FindElement("buoyant_forces");
|
||||
if (element) {
|
||||
result = ((FGBuoyantForces*)Models[eBuoyantForces])->Load(element);
|
||||
result = Models[eBuoyantForces]->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft buoyant_forces element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -769,19 +794,20 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the propulsion element. This element is OPTIONAL.
|
||||
element = document->FindElement("propulsion");
|
||||
if (element) {
|
||||
result = ((FGPropulsion*)Models[ePropulsion])->Load(element);
|
||||
auto propulsion = static_cast<FGPropulsion*>(Models[ePropulsion]);
|
||||
result = propulsion->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft propulsion element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
}
|
||||
for (unsigned int i=0; i<((FGPropulsion*)Models[ePropulsion])->GetNumEngines(); i++)
|
||||
for (unsigned int i=0; i < propulsion->GetNumEngines(); i++)
|
||||
((FGFCS*)Models[eSystems])->AddThrottle();
|
||||
}
|
||||
|
||||
// Process the system element[s]. This element is OPTIONAL, and there may be more than one.
|
||||
element = document->FindElement("system");
|
||||
while (element) {
|
||||
result = ((FGFCS*)Models[eSystems])->Load(element);
|
||||
result = Models[eSystems]->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft system element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -792,7 +818,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the autopilot element. This element is OPTIONAL.
|
||||
element = document->FindElement("autopilot");
|
||||
if (element) {
|
||||
result = ((FGFCS*)Models[eSystems])->Load(element);
|
||||
result = Models[eSystems]->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft autopilot element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -802,7 +828,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the flight_control element. This element is OPTIONAL.
|
||||
element = document->FindElement("flight_control");
|
||||
if (element) {
|
||||
result = ((FGFCS*)Models[eSystems])->Load(element);
|
||||
result = Models[eSystems]->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft flight_control element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -812,7 +838,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the aerodynamics element. This element is OPTIONAL, but almost always expected.
|
||||
element = document->FindElement("aerodynamics");
|
||||
if (element) {
|
||||
result = ((FGAerodynamics*)Models[eAerodynamics])->Load(element);
|
||||
result = Models[eAerodynamics]->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft aerodynamics element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -1145,6 +1171,7 @@ void FGFDMExec::SRand(int sr)
|
|||
{
|
||||
RandomSeed = sr;
|
||||
gaussian_random_number_phase = 0;
|
||||
RandomEngine->seed(sr);
|
||||
srand(RandomSeed);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@ SENTRY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <memory>
|
||||
#include <random>
|
||||
|
||||
#include "models/FGPropagate.h"
|
||||
#include "models/FGOutput.h"
|
||||
#include "math/FGTemplateFunc.h"
|
||||
|
@ -84,7 +87,7 @@ CLASS DOCUMENTATION
|
|||
executive is subsequently directed to load the chosen aircraft specification
|
||||
file:
|
||||
|
||||
@code
|
||||
@code{.cpp}
|
||||
fdmex = new FGFDMExec( ... );
|
||||
result = fdmex->LoadModel( ... );
|
||||
@endcode
|
||||
|
@ -100,7 +103,7 @@ CLASS DOCUMENTATION
|
|||
from JSBSim. The state variables are used to drive the instrument displays
|
||||
and to place the vehicle model in world space for visual rendering:
|
||||
|
||||
@code
|
||||
@code{.cpp}
|
||||
copy_to_JSBsim(); // copy control inputs to JSBSim
|
||||
fdmex->RunIC(); // loop JSBSim once w/o integrating
|
||||
copy_from_JSBsim(); // update the bus
|
||||
|
@ -108,7 +111,7 @@ CLASS DOCUMENTATION
|
|||
|
||||
Once initialization is complete, cyclic execution proceeds:
|
||||
|
||||
@code
|
||||
@code{.cpp}
|
||||
copy_to_JSBsim(); // copy control inputs to JSBSim
|
||||
fdmex->Run(); // execute JSBSim
|
||||
copy_from_JSBsim(); // update the bus
|
||||
|
@ -123,7 +126,7 @@ CLASS DOCUMENTATION
|
|||
file can be supplied to the stub program. Scripting (see FGScript) provides
|
||||
a way to supply command inputs to the simulation:
|
||||
|
||||
@code
|
||||
@code{.cpp}
|
||||
FDMExec = new JSBSim::FGFDMExec();
|
||||
FDMExec->LoadScript( ScriptName ); // the script loads the aircraft and ICs
|
||||
result = FDMExec->Run();
|
||||
|
@ -249,15 +252,6 @@ public:
|
|||
@return true if successful */
|
||||
bool RunIC(void);
|
||||
|
||||
/** Sets the ground callback pointer. For optimal memory management, a shared
|
||||
pointer is used internally that maintains a reference counter. The calling
|
||||
application must therefore use FGGroundCallback_ptr 'smart pointers' to
|
||||
manage their copy of the ground callback.
|
||||
@param gc A pointer to a ground callback object
|
||||
@see FGGroundCallback
|
||||
*/
|
||||
void SetGroundCallback(FGGroundCallback* gc) { FGLocation::SetGroundCallback(gc); }
|
||||
|
||||
/** Loads an aircraft model.
|
||||
@param AircraftPath path to the aircraft/ directory. For instance:
|
||||
"aircraft". Under aircraft, then, would be directories for various
|
||||
|
@ -361,12 +355,6 @@ public:
|
|||
FGInput* GetInput(void) {return (FGInput*)Models[eInput];}
|
||||
/// Returns the FGOutput pointer.
|
||||
FGOutput* GetOutput(void) {return (FGOutput*)Models[eOutput];}
|
||||
/** Get a pointer to the ground callback currently used. It is recommanded
|
||||
to store the returned pointer in a 'smart pointer' FGGroundCallback_ptr.
|
||||
@return A pointer to the current ground callback object.
|
||||
@see FGGroundCallback
|
||||
*/
|
||||
FGGroundCallback* GetGroundCallback(void) {return FGLocation::GetGroundCallback();}
|
||||
/// Retrieves the script object
|
||||
FGScript* GetScript(void) {return Script;}
|
||||
/// Returns a pointer to the FGInitialCondition object
|
||||
|
@ -536,17 +524,14 @@ public:
|
|||
/** Sets the current sim time.
|
||||
@param cur_time the current time
|
||||
@return the current simulation time. */
|
||||
double Setsim_time(double cur_time) {
|
||||
sim_time = cur_time;
|
||||
GetGroundCallback()->SetTime(sim_time);
|
||||
return sim_time;
|
||||
}
|
||||
double Setsim_time(double cur_time);
|
||||
|
||||
/** Sets the integration time step for the simulation executive.
|
||||
@param delta_t the time step in seconds. */
|
||||
void Setdt(double delta_t) { dT = delta_t; }
|
||||
|
||||
/** Sets the root directory where JSBSim starts looking for its system directories.
|
||||
/** Sets the root directory where JSBSim starts looking for its system
|
||||
directories.
|
||||
@param rootDir the string containing the root directory. */
|
||||
void SetRootDir(const SGPath& rootDir) {RootDir = rootDir;}
|
||||
|
||||
|
@ -557,14 +542,7 @@ public:
|
|||
/** Increments the simulation time if not in Holding mode. The Frame counter
|
||||
is also incremented.
|
||||
@return the new simulation time. */
|
||||
double IncrTime(void) {
|
||||
if (!holding && !IntegrationSuspended()) {
|
||||
sim_time += dT;
|
||||
GetGroundCallback()->SetTime(sim_time);
|
||||
Frame++;
|
||||
}
|
||||
return sim_time;
|
||||
}
|
||||
double IncrTime(void);
|
||||
|
||||
/** Retrieves the current frame count. */
|
||||
unsigned int GetFrame(void) const {return Frame;}
|
||||
|
@ -595,6 +573,9 @@ public:
|
|||
TemplateFunctions[name] = new FGTemplateFunc(this, el);
|
||||
}
|
||||
|
||||
const std::shared_ptr<std::default_random_engine>& GetRandomEngine(void) const
|
||||
{ return RandomEngine; }
|
||||
|
||||
private:
|
||||
unsigned int Frame;
|
||||
unsigned int IdFDM;
|
||||
|
@ -606,7 +587,6 @@ private:
|
|||
bool holding;
|
||||
bool IncrementThenHolding;
|
||||
int TimeStepsUntilHold;
|
||||
int RandomSeed;
|
||||
bool Constructing;
|
||||
bool modelLoaded;
|
||||
bool IsChild;
|
||||
|
@ -651,6 +631,9 @@ private:
|
|||
|
||||
bool HoldDown;
|
||||
|
||||
int RandomSeed;
|
||||
std::shared_ptr<std::default_random_engine> RandomEngine;
|
||||
|
||||
// The FDM counter is used to give each child FDM an unique ID. The root FDM
|
||||
// has the ID 0
|
||||
unsigned int* FDMctr;
|
||||
|
@ -670,6 +653,7 @@ private:
|
|||
void LoadModelConstants(void);
|
||||
bool Allocate(void);
|
||||
bool DeAllocate(void);
|
||||
void InitializeModels(void);
|
||||
int GetDisperse(void) const {return disperse;}
|
||||
SGPath GetFullPath(const SGPath& name) {
|
||||
if (name.isRelative())
|
||||
|
|
|
@ -113,23 +113,6 @@ public:
|
|||
return agl;
|
||||
}
|
||||
|
||||
double GetTerrainGeoCentRadius(double t, const FGLocation& l) const override {
|
||||
double contact[3], normal[3], vel[3], angularVel[3];
|
||||
mInterface->get_agl_ft(t, l, SG_METER_TO_FEET*2, contact,
|
||||
normal, vel, angularVel);
|
||||
return sqrt(contact[0]*contact[0]+contact[1]*contact[1]+contact[2]*contact[2]);
|
||||
}
|
||||
|
||||
double GetSeaLevelRadius(const FGLocation& l) const override {
|
||||
double seaLevelRadius, latGeoc;
|
||||
|
||||
sgGeodToGeoc(l.GetGeodLatitudeRad(), l.GetGeodAltitude(),
|
||||
&seaLevelRadius, &latGeoc);
|
||||
|
||||
return seaLevelRadius * SG_METER_TO_FEET;
|
||||
}
|
||||
|
||||
void SetTerrainGeoCentRadius(double radius) override {}
|
||||
private:
|
||||
FGJSBsim* mInterface;
|
||||
};
|
||||
|
@ -200,9 +183,6 @@ FGJSBsim::FGJSBsim( double dt )
|
|||
fdmex = new FGFDMExec( PropertyManager );
|
||||
fdmex->Hold();
|
||||
|
||||
// Register ground callback.
|
||||
fdmex->SetGroundCallback( new FGFSGroundCallback(this) );
|
||||
|
||||
Atmosphere = fdmex->GetAtmosphere();
|
||||
Winds = fdmex->GetWinds();
|
||||
FCS = fdmex->GetFCS();
|
||||
|
@ -216,6 +196,9 @@ FGJSBsim::FGJSBsim( double dt )
|
|||
GroundReactions = fdmex->GetGroundReactions();
|
||||
Accelerations = fdmex->GetAccelerations();
|
||||
|
||||
// Register ground callback.
|
||||
Inertial->SetGroundCallback( new FGFSGroundCallback(this) );
|
||||
|
||||
fgic=fdmex->GetIC();
|
||||
needTrim=true;
|
||||
|
||||
|
|
|
@ -92,12 +92,12 @@ void FGInitialCondition::ResetIC(double u0, double v0, double w0,
|
|||
|
||||
InitializeIC();
|
||||
|
||||
vPQR_body = FGColumnVector3(p0, q0, r0);
|
||||
vPQR_body = {p0, q0, r0};
|
||||
alpha = alpha0; beta = beta0;
|
||||
|
||||
position.SetLongitude(lonRad0);
|
||||
position.SetLatitude(latRad0);
|
||||
position.SetAltitudeAGL(altAGLFt0);
|
||||
fdmex->GetInertial()->SetAltitudeAGL(position, altAGLFt0);
|
||||
lastLatitudeSet = setgeoc;
|
||||
lastAltitudeSet = setagl;
|
||||
|
||||
|
@ -108,9 +108,9 @@ void FGInitialCondition::ResetIC(double u0, double v0, double w0,
|
|||
vt = vUVW_NED.Magnitude();
|
||||
lastSpeedSet = setuvw;
|
||||
|
||||
Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
|
||||
sbeta, cbeta, 0.0,
|
||||
salpha*cbeta, -salpha*sbeta, calpha);
|
||||
Tw2b = { calpha*cbeta, -calpha*sbeta, -salpha,
|
||||
sbeta, cbeta, 0.0,
|
||||
salpha*cbeta, -salpha*sbeta, calpha };
|
||||
Tb2w = Tw2b.Transposed();
|
||||
|
||||
SetFlightPathAngleRadIC(gamma0);
|
||||
|
@ -122,10 +122,9 @@ void FGInitialCondition::InitializeIC(void)
|
|||
{
|
||||
alpha = beta = 0.0;
|
||||
epa = 0.0;
|
||||
a = fdmex->GetInertial()->GetSemimajor();
|
||||
|
||||
double a = fdmex->GetInertial()->GetSemimajor();
|
||||
double b = fdmex->GetInertial()->GetSemiminor();
|
||||
double ec = b/a;
|
||||
e2 = 1.0 - ec*ec;
|
||||
|
||||
position.SetEllipse(a, b);
|
||||
|
||||
|
@ -138,8 +137,8 @@ void FGInitialCondition::InitializeIC(void)
|
|||
|
||||
targetNlfIC = 1.0;
|
||||
|
||||
Tw2b.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
|
||||
Tb2w.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
|
||||
Tw2b = { 1., 0., 0., 0., 1., 0., 0., 0., 1. };
|
||||
Tb2w = { 1., 0., 0., 0., 1., 0., 0., 0., 1. };
|
||||
|
||||
lastSpeedSet = setvt;
|
||||
lastAltitudeSet = setasl;
|
||||
|
@ -152,7 +151,7 @@ void FGInitialCondition::InitializeIC(void)
|
|||
|
||||
void FGInitialCondition::SetVequivalentKtsIC(double ve)
|
||||
{
|
||||
double altitudeASL = position.GetAltitudeASL();
|
||||
double altitudeASL = GetAltitudeASLFtIC();
|
||||
double rho = Atmosphere->GetDensity(altitudeASL);
|
||||
double rhoSL = Atmosphere->GetDensitySL();
|
||||
SetVtrueFpsIC(ve*ktstofps*sqrt(rhoSL/rho));
|
||||
|
@ -163,7 +162,7 @@ void FGInitialCondition::SetVequivalentKtsIC(double ve)
|
|||
|
||||
void FGInitialCondition::SetMachIC(double mach)
|
||||
{
|
||||
double altitudeASL = position.GetAltitudeASL();
|
||||
double altitudeASL = GetAltitudeASLFtIC();
|
||||
double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
||||
SetVtrueFpsIC(mach*soundSpeed);
|
||||
lastSpeedSet = setmach;
|
||||
|
@ -173,7 +172,7 @@ void FGInitialCondition::SetMachIC(double mach)
|
|||
|
||||
void FGInitialCondition::SetVcalibratedKtsIC(double vcas)
|
||||
{
|
||||
double altitudeASL = position.GetAltitudeASL();
|
||||
double altitudeASL = GetAltitudeASLFtIC();
|
||||
double pressure = Atmosphere->GetPressure(altitudeASL);
|
||||
double mach = MachFromVcalibrated(fabs(vcas)*ktstofps, pressure);
|
||||
double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
||||
|
@ -223,9 +222,9 @@ void FGInitialCondition::calcAeroAngles(const FGColumnVector3& _vt_NED)
|
|||
sbeta = va / vt;
|
||||
}
|
||||
|
||||
Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
|
||||
sbeta, cbeta, 0.0,
|
||||
salpha*cbeta, -salpha*sbeta, calpha);
|
||||
Tw2b = { calpha*cbeta, -calpha*sbeta, -salpha,
|
||||
sbeta, cbeta, 0.0,
|
||||
salpha*cbeta, -salpha*sbeta, calpha };
|
||||
Tb2w = Tw2b.Transposed();
|
||||
}
|
||||
|
||||
|
@ -340,7 +339,7 @@ void FGInitialCondition::calcThetaBeta(double alfa, const FGColumnVector3& _vt_N
|
|||
|
||||
FGColumnVector3 v0 = Tpsi * _vt_NED;
|
||||
FGColumnVector3 n = (Talpha * Tphi).Transposed() * FGColumnVector3(0., 0., 1.);
|
||||
FGColumnVector3 y = FGColumnVector3(0., 1., 0.);
|
||||
FGColumnVector3 y = {0., 1., 0.};
|
||||
FGColumnVector3 u = y - DotProduct(y, n) * n;
|
||||
FGColumnVector3 p = y * n;
|
||||
|
||||
|
@ -383,9 +382,9 @@ void FGInitialCondition::calcThetaBeta(double alfa, const FGColumnVector3& _vt_N
|
|||
cbeta = v2(eU) / vt;
|
||||
sbeta = v2(eV) / vt;
|
||||
}
|
||||
Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
|
||||
sbeta, cbeta, 0.0,
|
||||
salpha*cbeta, -salpha*sbeta, calpha);
|
||||
Tw2b = { calpha*cbeta, -calpha*sbeta, -salpha,
|
||||
sbeta, cbeta, 0.0,
|
||||
salpha*cbeta, -salpha*sbeta, calpha };
|
||||
Tb2w = Tw2b.Transposed();
|
||||
}
|
||||
|
||||
|
@ -409,9 +408,9 @@ void FGInitialCondition::SetBetaRadIC(double bta)
|
|||
0., cphi,-sphi,
|
||||
0., sphi, cphi);
|
||||
|
||||
Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
|
||||
sbeta, cbeta, 0.0,
|
||||
salpha*cbeta, -salpha*sbeta, calpha);
|
||||
Tw2b = { calpha*cbeta, -calpha*sbeta, -salpha,
|
||||
sbeta, cbeta, 0.0,
|
||||
salpha*cbeta, -salpha*sbeta, calpha };
|
||||
Tb2w = Tw2b.Transposed();
|
||||
|
||||
FGColumnVector3 vf = TphiInv * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||
|
@ -603,7 +602,7 @@ void FGInitialCondition::SetWindMagKtsIC(double mag)
|
|||
if (windMag > 0.001)
|
||||
_vHEAD *= (mag*ktstofps) / windMag;
|
||||
else
|
||||
_vHEAD = FGColumnVector3((mag*ktstofps), 0., 0.);
|
||||
_vHEAD = {mag*ktstofps, 0., 0.};
|
||||
|
||||
_vWIND_NED(eU) = _vHEAD(eU);
|
||||
_vWIND_NED(eV) = _vHEAD(eV);
|
||||
|
@ -639,8 +638,7 @@ void FGInitialCondition::SetWindDirDegIC(double dir)
|
|||
void FGInitialCondition::SetTerrainElevationFtIC(double elev)
|
||||
{
|
||||
double agl = GetAltitudeAGLFtIC();
|
||||
|
||||
fdmex->GetGroundCallback()->SetTerrainGeoCentRadius(elev + position.GetSeaLevelRadius());
|
||||
fdmex->GetInertial()->SetTerrainElevation(elev);
|
||||
|
||||
if (lastAltitudeSet == setagl)
|
||||
SetAltitudeAGLFtIC(agl);
|
||||
|
@ -648,25 +646,94 @@ void FGInitialCondition::SetTerrainElevationFtIC(double elev)
|
|||
|
||||
//******************************************************************************
|
||||
|
||||
double FGInitialCondition::GetAltitudeAGLFtIC(void) const
|
||||
double FGInitialCondition::GetAltitudeASLFtIC(void) const
|
||||
{
|
||||
return position.GetAltitudeAGL();
|
||||
return position.GetRadius() - position.GetSeaLevelRadius();
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
|
||||
double FGInitialCondition::GetAltitudeAGLFtIC(void) const
|
||||
{
|
||||
return fdmex->GetInertial()->GetAltitudeAGL(position);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
|
||||
double FGInitialCondition::GetTerrainElevationFtIC(void) const
|
||||
{
|
||||
return position.GetTerrainRadius() - position.GetSeaLevelRadius();
|
||||
FGLocation contact;
|
||||
FGColumnVector3 normal, v, w;
|
||||
fdmex->GetInertial()->GetContactPoint(position, contact, normal, v, w);
|
||||
return contact.GetGeodAltitude();
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
|
||||
void FGInitialCondition::SetAltitudeAGLFtIC(double agl)
|
||||
{
|
||||
double terrainElevation = position.GetTerrainRadius()
|
||||
- position.GetSeaLevelRadius();
|
||||
SetAltitudeASLFtIC(agl + terrainElevation);
|
||||
double altitudeASL = GetAltitudeASLFtIC();
|
||||
double pressure = Atmosphere->GetPressure(altitudeASL);
|
||||
double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
||||
double rho = Atmosphere->GetDensity(altitudeASL);
|
||||
double rhoSL = Atmosphere->GetDensitySL();
|
||||
|
||||
double mach0 = vt / soundSpeed;
|
||||
double vc0 = VcalibratedFromMach(mach0, pressure);
|
||||
double ve0 = vt * sqrt(rho/rhoSL);
|
||||
|
||||
switch(lastLatitudeSet) {
|
||||
case setgeod:
|
||||
fdmex->GetInertial()->SetAltitudeAGL(position, agl);
|
||||
break;
|
||||
case setgeoc:
|
||||
{
|
||||
double a = fdmex->GetInertial()->GetSemimajor();
|
||||
double b = fdmex->GetInertial()->GetSemiminor();
|
||||
double e2 = 1.0-b*b/(a*a);
|
||||
double tanlat = tan(position.GetLatitude());
|
||||
double n = e2;
|
||||
double prev_n = 1.0;
|
||||
int iter = 0;
|
||||
double longitude = position.GetLongitude();
|
||||
double alt = position.GetGeodAltitude();
|
||||
double h = -2.0*max(a,b);
|
||||
double geodLat;
|
||||
while ((fabs(n-prev_n) > 1E-15 || fabs(h-agl) > 1E-10) && iter < 10) {
|
||||
geodLat = atan(tanlat/(1-n));
|
||||
position.SetPositionGeodetic(longitude, geodLat, alt);
|
||||
h = GetAltitudeAGLFtIC();
|
||||
alt += agl-h;
|
||||
double sinGeodLat = sin(geodLat);
|
||||
double N = a/sqrt(1-e2*sinGeodLat*sinGeodLat);
|
||||
prev_n = n;
|
||||
n = e2*N/(N+alt);
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
altitudeASL = GetAltitudeASLFtIC();
|
||||
soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
||||
rho = Atmosphere->GetDensity(altitudeASL);
|
||||
pressure = Atmosphere->GetPressure(altitudeASL);
|
||||
|
||||
switch(lastSpeedSet) {
|
||||
case setvc:
|
||||
mach0 = MachFromVcalibrated(vc0, pressure);
|
||||
SetVtrueFpsIC(mach0 * soundSpeed);
|
||||
break;
|
||||
case setmach:
|
||||
SetVtrueFpsIC(mach0 * soundSpeed);
|
||||
break;
|
||||
case setve:
|
||||
SetVtrueFpsIC(ve0 * sqrt(rhoSL/rho));
|
||||
break;
|
||||
default: // Make the compiler stop complaining about missing enums
|
||||
break;
|
||||
}
|
||||
|
||||
lastAltitudeSet = setagl;
|
||||
}
|
||||
|
||||
|
@ -677,7 +744,7 @@ void FGInitialCondition::SetAltitudeAGLFtIC(double agl)
|
|||
|
||||
void FGInitialCondition::SetAltitudeASLFtIC(double alt)
|
||||
{
|
||||
double altitudeASL = position.GetAltitudeASL();
|
||||
double altitudeASL = GetAltitudeASLFtIC();
|
||||
double pressure = Atmosphere->GetPressure(altitudeASL);
|
||||
double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
||||
double rho = Atmosphere->GetDensity(altitudeASL);
|
||||
|
@ -687,15 +754,71 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt)
|
|||
double vc0 = VcalibratedFromMach(mach0, pressure);
|
||||
double ve0 = vt * sqrt(rho/rhoSL);
|
||||
|
||||
double geodLatitude = position.GetGeodLatitudeRad();
|
||||
altitudeASL=alt;
|
||||
position.SetAltitudeASL(alt);
|
||||
|
||||
// The call to SetAltitudeASL has most likely modified the geodetic latitude
|
||||
// so we need to restore it to its initial value.
|
||||
if (lastLatitudeSet == setgeod)
|
||||
SetGeodLatitudeRadIC(geodLatitude);
|
||||
switch(lastLatitudeSet) {
|
||||
case setgeod:
|
||||
{
|
||||
// Given an altitude above the mean sea level (or a position radius which
|
||||
// is the same) and a geodetic latitude, compute the geodetic altitude.
|
||||
double a = fdmex->GetInertial()->GetSemimajor();
|
||||
double b = fdmex->GetInertial()->GetSemiminor();
|
||||
double e2 = 1.0-b*b/(a*a);
|
||||
double geodLatitude = position.GetGeodLatitudeRad();
|
||||
double cosGeodLat = cos(geodLatitude);
|
||||
double sinGeodLat = sin(geodLatitude);
|
||||
double N = a/sqrt(1-e2*sinGeodLat*sinGeodLat);
|
||||
double geodAlt = 0.0;
|
||||
double n = e2;
|
||||
double prev_n = 1.0;
|
||||
int iter = 0;
|
||||
// Use tan or cotan to solve the geodetic altitude to avoid floating point
|
||||
// exceptions.
|
||||
if (cosGeodLat > fabs(sinGeodLat)) { // tan() can safely be used.
|
||||
double tanGeodLat = sinGeodLat/cosGeodLat;
|
||||
double x0 = N*e2*cosGeodLat;
|
||||
double x = 0.0;
|
||||
while (fabs(n-prev_n) > 1E-15 && iter < 10) {
|
||||
double tanLat = (1-n)*tanGeodLat; // See Stevens & Lewis 1.6-14
|
||||
double cos2Lat = 1./(1.+tanLat*tanLat);
|
||||
double slr = b/sqrt(1.-e2*cos2Lat);
|
||||
double R = slr + alt;
|
||||
x = R*sqrt(cos2Lat); // OK, cos(latitude) is always positive.
|
||||
prev_n = n;
|
||||
n = x0/x;
|
||||
iter++;
|
||||
}
|
||||
geodAlt = x/cosGeodLat-N;
|
||||
}
|
||||
else { // better use cotan (i.e. 1./tan())
|
||||
double cotanGeodLat = cosGeodLat/sinGeodLat;
|
||||
double z0 = N*e2*sinGeodLat;
|
||||
double z = 0.0;
|
||||
while (fabs(n-prev_n) > 1E-15 && iter < 10) {
|
||||
double cotanLat = cotanGeodLat/(1-n);
|
||||
double sin2Lat = 1./(1.+cotanLat*cotanLat);
|
||||
double cos2Lat = 1.-sin2Lat;
|
||||
double slr = b/sqrt(1.-e2*cos2Lat);
|
||||
double R = slr + alt;
|
||||
z = R*sign(cotanLat)*sqrt(sin2Lat);
|
||||
prev_n = n;
|
||||
n = z0/(z0+z);
|
||||
iter++;
|
||||
}
|
||||
geodAlt = z/sinGeodLat-N*(1-e2);
|
||||
}
|
||||
|
||||
double longitude = position.GetLongitude();
|
||||
position.SetPositionGeodetic(longitude, geodLatitude, geodAlt);
|
||||
}
|
||||
break;
|
||||
case setgeoc:
|
||||
{
|
||||
double slr = position.GetSeaLevelRadius();
|
||||
position.SetRadius(slr+alt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
altitudeASL = position.GetGeodAltitude();
|
||||
soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
||||
rho = Atmosphere->GetDensity(altitudeASL);
|
||||
pressure = Atmosphere->GetPressure(altitudeASL);
|
||||
|
@ -722,11 +845,26 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt)
|
|||
|
||||
void FGInitialCondition::SetGeodLatitudeRadIC(double geodLatitude)
|
||||
{
|
||||
double h = ComputeGeodAltitude(geodLatitude);
|
||||
double lon = position.GetLongitude();
|
||||
|
||||
position.SetPositionGeodetic(lon, geodLatitude, h);
|
||||
lastLatitudeSet = setgeod;
|
||||
|
||||
switch (lastAltitudeSet)
|
||||
{
|
||||
case setagl:
|
||||
{
|
||||
double agl = GetAltitudeAGLFtIC();
|
||||
position.SetPositionGeodetic(lon, geodLatitude, 0.);
|
||||
fdmex->GetInertial()->SetAltitudeAGL(position, agl);
|
||||
}
|
||||
break;
|
||||
case setasl:
|
||||
{
|
||||
double asl = GetAltitudeASLFtIC();
|
||||
position.SetPositionGeodetic(lon, geodLatitude, 0.);
|
||||
SetAltitudeASLFtIC(asl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
|
@ -744,7 +882,9 @@ void FGInitialCondition::SetLatitudeRadIC(double lat)
|
|||
SetAltitudeAGLFtIC(altitude);
|
||||
break;
|
||||
default:
|
||||
altitude = GetAltitudeASLFtIC();
|
||||
position.SetLatitude(lat);
|
||||
SetAltitudeASLFtIC(altitude);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -762,9 +902,7 @@ void FGInitialCondition::SetLongitudeRadIC(double lon)
|
|||
SetAltitudeAGLFtIC(altitude);
|
||||
break;
|
||||
default:
|
||||
altitude = position.GetAltitudeASL();
|
||||
position.SetLongitude(lon);
|
||||
position.SetAltitudeASL(altitude);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -819,7 +957,7 @@ double FGInitialCondition::GetBodyWindFpsIC(int idx) const
|
|||
|
||||
double FGInitialCondition::GetVcalibratedKtsIC(void) const
|
||||
{
|
||||
double altitudeASL = position.GetAltitudeASL();
|
||||
double altitudeASL = GetAltitudeASLFtIC();
|
||||
double pressure = Atmosphere->GetPressure(altitudeASL);
|
||||
double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
||||
double mach = vt / soundSpeed;
|
||||
|
@ -831,7 +969,7 @@ double FGInitialCondition::GetVcalibratedKtsIC(void) const
|
|||
|
||||
double FGInitialCondition::GetVequivalentKtsIC(void) const
|
||||
{
|
||||
double altitudeASL = position.GetAltitudeASL();
|
||||
double altitudeASL = GetAltitudeASLFtIC();
|
||||
double rho = Atmosphere->GetDensity(altitudeASL);
|
||||
double rhoSL = Atmosphere->GetDensitySL();
|
||||
return fpstokts * vt * sqrt(rho/rhoSL);
|
||||
|
@ -841,7 +979,7 @@ double FGInitialCondition::GetVequivalentKtsIC(void) const
|
|||
|
||||
double FGInitialCondition::GetMachIC(void) const
|
||||
{
|
||||
double altitudeASL = position.GetAltitudeASL();
|
||||
double altitudeASL = GetAltitudeASLFtIC();
|
||||
double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
||||
return vt / soundSpeed;
|
||||
}
|
||||
|
@ -909,23 +1047,6 @@ bool FGInitialCondition::Load(const SGPath& rstfile, bool useStoredPath)
|
|||
return result;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Given an altitude above the mean sea level (or a position radius which is the
|
||||
// same) and a geodetic latitude, compute the geodetic altitude.
|
||||
//
|
||||
// TODO: extend the routine to the case where lastAltitudeSet is equal to
|
||||
// setagl.
|
||||
|
||||
double FGInitialCondition::ComputeGeodAltitude(double geodLatitude)
|
||||
{
|
||||
double R = position.GetRadius();
|
||||
double slat = sin(geodLatitude);
|
||||
double RN = a / sqrt(1.0 - e2*slat*slat);
|
||||
double p1 = e2*RN*slat*slat;
|
||||
double p2 = e2*e2*RN*RN*slat*slat-R*R;
|
||||
return p1 + sqrt(p1*p1-p2) - RN;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
|
||||
bool FGInitialCondition::LoadLatitude(Element* position_el)
|
||||
|
@ -952,10 +1073,12 @@ bool FGInitialCondition::LoadLatitude(Element* position_el)
|
|||
|
||||
string lat_type = latitude_el->GetAttributeValue("type");
|
||||
|
||||
if (lat_type == "geod" || lat_type == "geodetic")
|
||||
if (lat_type == "geod" || lat_type == "geodetic") {
|
||||
SetGeodLatitudeRadIC(latitude);
|
||||
lastLatitudeSet = setgeod;
|
||||
}
|
||||
else {
|
||||
position.SetLatitude(latitude);
|
||||
SetLatitudeRadIC(latitude);
|
||||
lastLatitudeSet = setgeoc;
|
||||
}
|
||||
}
|
||||
|
@ -1060,10 +1183,9 @@ bool FGInitialCondition::Load_v1(Element* document)
|
|||
// This is the rotation rate of the "Local" frame, expressed in the local frame.
|
||||
const FGMatrix33& Tl2b = orientation.GetT();
|
||||
double radInv = 1.0 / position.GetRadius();
|
||||
FGColumnVector3 vOmegaLocal = FGColumnVector3(
|
||||
radInv*vUVW_NED(eEast),
|
||||
-radInv*vUVW_NED(eNorth),
|
||||
-radInv*vUVW_NED(eEast)*position.GetTanLatitude() );
|
||||
FGColumnVector3 vOmegaLocal = {radInv*vUVW_NED(eEast),
|
||||
-radInv*vUVW_NED(eNorth),
|
||||
-radInv*vUVW_NED(eEast)*tan(position.GetLatitude())};
|
||||
|
||||
vPQR_body = Tl2b * vOmegaLocal;
|
||||
|
||||
|
@ -1096,8 +1218,9 @@ bool FGInitialCondition::Load_v2(Element* document)
|
|||
}
|
||||
FGColumnVector3 vOmegaEarth = fdmex->GetInertial()->GetOmegaPlanet();
|
||||
|
||||
if (document->FindElement("elevation"))
|
||||
fdmex->GetGroundCallback()->SetTerrainGeoCentRadius(document->FindElementValueAsNumberConvertTo("elevation", "FT")+position.GetSeaLevelRadius());
|
||||
if (document->FindElement("elevation")) {
|
||||
fdmex->GetInertial()->SetTerrainElevation(document->FindElementValueAsNumberConvertTo("elevation", "FT"));
|
||||
}
|
||||
|
||||
// Initialize vehicle position
|
||||
//
|
||||
|
@ -1113,21 +1236,22 @@ bool FGInitialCondition::Load_v2(Element* document)
|
|||
position = Ti2ec * position_el->FindElementTripletConvertTo("FT");
|
||||
} else if (frame == "ecef") {
|
||||
if (!position_el->FindElement("x") && !position_el->FindElement("y") && !position_el->FindElement("z")) {
|
||||
if (position_el->FindElement("longitude"))
|
||||
position.SetLongitude(position_el->FindElementValueAsNumberConvertTo("longitude", "RAD"));
|
||||
|
||||
if (position_el->FindElement("longitude")) {
|
||||
SetLongitudeRadIC(position_el->FindElementValueAsNumberConvertTo("longitude", "RAD"));
|
||||
}
|
||||
if (position_el->FindElement("radius")) {
|
||||
position.SetRadius(position_el->FindElementValueAsNumberConvertTo("radius", "FT"));
|
||||
} else if (position_el->FindElement("altitudeAGL")) {
|
||||
position.SetAltitudeAGL(position_el->FindElementValueAsNumberConvertTo("altitudeAGL", "FT"));
|
||||
SetAltitudeAGLFtIC(position_el->FindElementValueAsNumberConvertTo("altitudeAGL", "FT"));
|
||||
} else if (position_el->FindElement("altitudeMSL")) {
|
||||
position.SetAltitudeASL(position_el->FindElementValueAsNumberConvertTo("altitudeMSL", "FT"));
|
||||
SetAltitudeASLFtIC(position_el->FindElementValueAsNumberConvertTo("altitudeMSL", "FT"));
|
||||
} else {
|
||||
cerr << endl << " No altitude or radius initial condition is given." << endl;
|
||||
result = false;
|
||||
}
|
||||
|
||||
result = LoadLatitude(position_el);
|
||||
if (result)
|
||||
result = LoadLatitude(position_el);
|
||||
|
||||
} else {
|
||||
position = position_el->FindElementTripletConvertTo("FT");
|
||||
|
@ -1229,7 +1353,6 @@ bool FGInitialCondition::Load_v2(Element* document)
|
|||
// The vehicle will be defaulted to (0,0,0) in the Body frame if nothing is provided.
|
||||
|
||||
Element* velocity_el = document->FindElement("velocity");
|
||||
FGColumnVector3 vInitVelocity = FGColumnVector3(0.0, 0.0, 0.0);
|
||||
FGMatrix33 mTec2l = position.GetTec2l();
|
||||
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||
|
||||
|
@ -1262,7 +1385,7 @@ bool FGInitialCondition::Load_v2(Element* document)
|
|||
|
||||
} else {
|
||||
|
||||
vUVW_NED = Tb2l * vInitVelocity;
|
||||
vUVW_NED.InitMatrix();
|
||||
|
||||
}
|
||||
|
||||
|
@ -1282,10 +1405,9 @@ bool FGInitialCondition::Load_v2(Element* document)
|
|||
// Refer to Stevens and Lewis, 1.5-14a, pg. 49.
|
||||
// This is the rotation rate of the "Local" frame, expressed in the local frame.
|
||||
double radInv = 1.0 / position.GetRadius();
|
||||
FGColumnVector3 vOmegaLocal = FGColumnVector3(
|
||||
radInv*vUVW_NED(eEast),
|
||||
-radInv*vUVW_NED(eNorth),
|
||||
-radInv*vUVW_NED(eEast)*position.GetTanLatitude() );
|
||||
FGColumnVector3 vOmegaLocal = { radInv*vUVW_NED(eEast),
|
||||
-radInv*vUVW_NED(eNorth),
|
||||
-radInv*vUVW_NED(eEast)*tan(position.GetLatitude())};
|
||||
|
||||
if (attrate_el) {
|
||||
|
||||
|
|
|
@ -377,7 +377,7 @@ public:
|
|||
|
||||
/** Gets the initial altitude above sea level.
|
||||
@return Initial altitude in feet. */
|
||||
double GetAltitudeASLFtIC(void) const { return position.GetAltitudeASL(); }
|
||||
double GetAltitudeASLFtIC(void) const;
|
||||
|
||||
/** Gets the initial altitude above ground level.
|
||||
@return Initial altitude AGL in feet */
|
||||
|
@ -694,8 +694,7 @@ private:
|
|||
double targetNlfIC;
|
||||
|
||||
FGMatrix33 Tw2b, Tb2w;
|
||||
double alpha, beta;
|
||||
double a, e2;
|
||||
double alpha, beta;
|
||||
double epa;
|
||||
|
||||
speedset lastSpeedSet;
|
||||
|
|
|
@ -397,7 +397,9 @@ void FGTrim::trimOnGround(void)
|
|||
|
||||
FGColumnVector3 normal, vDummy;
|
||||
FGLocation lDummy;
|
||||
double height = gearLoc.GetContactPoint(lDummy, normal, vDummy, vDummy);
|
||||
double height = fdmex->GetInertial()->GetContactPoint(gearLoc, lDummy,
|
||||
normal, vDummy,
|
||||
vDummy);
|
||||
|
||||
if (gear->IsBogey() && !GroundReactions->GetSolid())
|
||||
continue;
|
||||
|
|
|
@ -44,12 +44,16 @@ double FGDefaultGroundCallback::GetAGLevel(double t, const FGLocation& loc,
|
|||
{
|
||||
vel.InitMatrix();
|
||||
angularVel.InitMatrix();
|
||||
normal = FGColumnVector3(loc).Normalize();
|
||||
double loc_radius = loc.GetRadius(); // Get the radius of the given location
|
||||
// (e.g. the CG)
|
||||
double agl = loc_radius - mTerrainLevelRadius;
|
||||
contact = (mTerrainLevelRadius/loc_radius)*FGColumnVector3(loc);
|
||||
return agl;
|
||||
FGLocation l = loc;
|
||||
l.SetEllipse(a,b);
|
||||
double latitude = l.GetGeodLatitudeRad();
|
||||
double cosLat = cos(latitude);
|
||||
double longitude = l.GetLongitude();
|
||||
normal = FGColumnVector3(cosLat*cos(longitude), cosLat*sin(longitude),
|
||||
sin(latitude));
|
||||
contact.SetEllipse(a, b);
|
||||
contact.SetPositionGeodetic(longitude, latitude, mTerrainElevation);
|
||||
return l.GetGeodAltitude() - mTerrainElevation;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -38,8 +38,6 @@ SENTRY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "simgear/structure/SGSharedPtr.hxx"
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
class FGLocation;
|
||||
|
@ -61,7 +59,7 @@ CLASS DOCUMENTATION
|
|||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGGroundCallback : public SGReferenced
|
||||
class FGGroundCallback
|
||||
{
|
||||
public:
|
||||
|
||||
|
@ -97,37 +95,29 @@ public:
|
|||
FGColumnVector3& w) const
|
||||
{ return GetAGLevel(time, location, contact, normal, v, w); }
|
||||
|
||||
/** Compute the local terrain radius
|
||||
@param t simulation time
|
||||
@param location location
|
||||
*/
|
||||
virtual double GetTerrainGeoCentRadius(double t, const FGLocation& location) const = 0;
|
||||
|
||||
/** Compute the local terrain radius
|
||||
@param location location
|
||||
*/
|
||||
virtual double GetTerrainGeoCentRadius(const FGLocation& location) const
|
||||
{ return GetTerrainGeoCentRadius(time, location); }
|
||||
|
||||
/** Return the sea level radius
|
||||
@param location location
|
||||
*/
|
||||
virtual double GetSeaLevelRadius(const FGLocation& location) const = 0;
|
||||
|
||||
/** Set the local terrain radius.
|
||||
/** Set the terrain elevation.
|
||||
Only needs to be implemented if JSBSim should be allowed
|
||||
to modify the local terrain radius (see the default implementation)
|
||||
*/
|
||||
virtual void SetTerrainGeoCentRadius(double radius) {}
|
||||
virtual void SetTerrainElevation(double h) {}
|
||||
|
||||
/** Set the planet semimajor and semiminor axes.
|
||||
Only needs to be implemented if JSBSim should be allowed to modify
|
||||
the planet dimensions.
|
||||
*/
|
||||
virtual void SetEllipse(double semimajor, double semiminor) {}
|
||||
|
||||
/** Set the simulation time.
|
||||
The elapsed time can be used by the ground callbck to assess the planet
|
||||
rotation or the movement of objects.
|
||||
@param _time elapsed time in seconds since the simulation started.
|
||||
*/
|
||||
void SetTime(double _time) { time = _time; }
|
||||
|
||||
protected:
|
||||
double time;
|
||||
};
|
||||
|
||||
typedef SGSharedPtr<FGGroundCallback> FGGroundCallback_ptr;
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// The default sphere earth implementation:
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -135,25 +125,23 @@ typedef SGSharedPtr<FGGroundCallback> FGGroundCallback_ptr;
|
|||
class FGDefaultGroundCallback : public FGGroundCallback
|
||||
{
|
||||
public:
|
||||
explicit FGDefaultGroundCallback(double referenceRadius) :
|
||||
mSeaLevelRadius(referenceRadius), mTerrainLevelRadius(referenceRadius) {}
|
||||
explicit FGDefaultGroundCallback(double semiMajor, double semiMinor) :
|
||||
a(semiMajor), b(semiMinor) {}
|
||||
|
||||
double GetAGLevel(double t, const FGLocation& location,
|
||||
FGLocation& contact,
|
||||
FGColumnVector3& normal, FGColumnVector3& v,
|
||||
FGColumnVector3& w) const override;
|
||||
|
||||
void SetTerrainGeoCentRadius(double radius) override
|
||||
{ mTerrainLevelRadius = radius;}
|
||||
double GetTerrainGeoCentRadius(double t, const FGLocation& location) const override
|
||||
{ return mTerrainLevelRadius; }
|
||||
void SetTerrainElevation(double h) override
|
||||
{ mTerrainElevation = h; }
|
||||
|
||||
double GetSeaLevelRadius(const FGLocation& location) const override
|
||||
{return mSeaLevelRadius; }
|
||||
void SetEllipse(double semimajor, double semiminor) override
|
||||
{ a = semimajor; b = semiminor; }
|
||||
|
||||
private:
|
||||
double mSeaLevelRadius;
|
||||
double mTerrainLevelRadius;
|
||||
double a, b;
|
||||
double mTerrainElevation = 0.0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -66,21 +66,21 @@ public:
|
|||
FGInputSocket(FGFDMExec* fdmex);
|
||||
|
||||
/** Destructor. */
|
||||
~FGInputSocket();
|
||||
~FGInputSocket() override;
|
||||
|
||||
/** Init the input directives from an XML file.
|
||||
@param element XML Element that is pointing to the input directives
|
||||
*/
|
||||
bool Load(Element* el);
|
||||
bool Load(Element* el) override;
|
||||
|
||||
/** Initializes the instance. This method basically opens the socket to which
|
||||
inputs will be directed.
|
||||
@result true if the execution succeeded.
|
||||
*/
|
||||
bool InitModel(void);
|
||||
bool InitModel(void) override;
|
||||
|
||||
/// Generates the input.
|
||||
void Read(bool Holding);
|
||||
void Read(bool Holding) override;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ void FGInputType::SetIdx(unsigned int idx)
|
|||
bool FGInputType::Load(Element* element)
|
||||
{
|
||||
// Perform base class Load.
|
||||
if(!FGModel::Load(element, true))
|
||||
if(!FGModel::Upload(element, true))
|
||||
return false;
|
||||
|
||||
// no common attributes yet (see FGOutputType for example
|
||||
|
|
|
@ -79,7 +79,7 @@ public:
|
|||
FGInputType(FGFDMExec* fdmex);
|
||||
|
||||
/// Destructor
|
||||
virtual ~FGInputType();
|
||||
~FGInputType() override;
|
||||
|
||||
/** Set the idx for this input instance
|
||||
@param idx ID of the input instance that is constructed
|
||||
|
@ -89,10 +89,10 @@ public:
|
|||
/** Init the input directives from an XML file (implement the FGModel interface).
|
||||
@param element XML Element that is pointing to the input directives
|
||||
*/
|
||||
virtual bool Load(Element* el);
|
||||
bool Load(Element* el) override;
|
||||
|
||||
/// Init the input model according to its configitation.
|
||||
virtual bool InitModel(void);
|
||||
bool InitModel(void) override;
|
||||
|
||||
/** Executes the input directives (implement the FGModel interface).
|
||||
This method checks that the current time step matches the input
|
||||
|
@ -100,7 +100,7 @@ public:
|
|||
generation and finally the "post" functions.
|
||||
@result false if no error.
|
||||
*/
|
||||
bool Run(bool Holding);
|
||||
bool Run(bool Holding) override;
|
||||
|
||||
/** Generate the input. This is a pure method so it must be implemented by
|
||||
the classes that inherits from FGInputType. The Read name may not be
|
||||
|
@ -132,7 +132,7 @@ protected:
|
|||
unsigned int InputIdx;
|
||||
bool enabled;
|
||||
|
||||
void Debug(int from);
|
||||
void Debug(int from) override;
|
||||
};
|
||||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -57,7 +57,7 @@ Element_ptr FGModelLoader::Open(Element *el)
|
|||
|
||||
if (!fname.empty()) {
|
||||
FGXMLFileRead XMLFileRead;
|
||||
SGPath path(SGPath::fromUtf8(fname));
|
||||
SGPath path(SGPath::fromUtf8(fname.c_str()));
|
||||
|
||||
if (path.isRelative())
|
||||
path = model->FindFullPathName(path);
|
||||
|
|
|
@ -66,15 +66,15 @@ public:
|
|||
/// Constructor
|
||||
FGOutputFG(FGFDMExec* fdmex);
|
||||
|
||||
virtual void Print(void);
|
||||
void Print(void) override;
|
||||
|
||||
/** Evaluate the output directives from an XML file.
|
||||
@param element XML Element that is pointing to the output directives
|
||||
*/
|
||||
virtual bool Load(Element*);
|
||||
bool Load(Element*) override;
|
||||
|
||||
protected:
|
||||
virtual void PrintHeaders(void) {};
|
||||
void PrintHeaders(void) override {};
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -74,18 +74,18 @@ public:
|
|||
FGOutputFile(FGFDMExec* fdmex);
|
||||
|
||||
/// Destructor : closes the file.
|
||||
virtual ~FGOutputFile() { CloseFile(); }
|
||||
~FGOutputFile() override { CloseFile(); }
|
||||
|
||||
/** Init the output directives from an XML file.
|
||||
@param element XML Element that is pointing to the output directives
|
||||
*/
|
||||
bool Load(Element* el);
|
||||
bool Load(Element* el) override;
|
||||
|
||||
/** Initializes the instance. This method basically opens the file to which
|
||||
outputs will be directed.
|
||||
@result true if the execution succeeded.
|
||||
*/
|
||||
bool InitModel(void);
|
||||
bool InitModel(void) override;
|
||||
/** Reset the output prior to a restart of the simulation. This method should
|
||||
be called when the simulation is restarted with, for example, new initial
|
||||
conditions. The current file is closed and reopened with a new name. The
|
||||
|
@ -93,13 +93,13 @@ public:
|
|||
constructor or SetOutputName() and is appended with an underscore _ and
|
||||
an ID that is incremented at each call to this method.
|
||||
*/
|
||||
void SetStartNewOutput(void);
|
||||
void SetStartNewOutput(void) override;
|
||||
/** Overwrites the name identifier under which the output will be logged.
|
||||
For this method to take effect, it must be called prior to
|
||||
FGFDMExec::RunIC(). If it is called after, it will not take effect before
|
||||
the next call to SetStartNewOutput().
|
||||
@param name new name */
|
||||
void SetOutputName(const std::string& fname) {
|
||||
void SetOutputName(const std::string& fname) override {
|
||||
Name = (FDMExec->GetRootDir()/fname).utf8Str();
|
||||
runID_postfix = -1;
|
||||
Filename = SGPath();
|
||||
|
@ -107,7 +107,7 @@ public:
|
|||
/** Generate the output. This is a pure method so it must be implemented by
|
||||
the classes that inherits from FGOutputFile.
|
||||
*/
|
||||
void Print(void) = 0;
|
||||
void Print(void) override = 0;
|
||||
|
||||
protected:
|
||||
SGPath Filename;
|
||||
|
|
|
@ -70,7 +70,7 @@ public:
|
|||
FGOutputSocket(FGFDMExec* fdmex);
|
||||
|
||||
/** Destructor. */
|
||||
~FGOutputSocket();
|
||||
~FGOutputSocket() override;
|
||||
|
||||
/** Overwrites the name identifier under which the output will be logged.
|
||||
This method is taken into account if it is called before
|
||||
|
@ -80,20 +80,20 @@ public:
|
|||
hostname could be an ip, port a numerical value and
|
||||
proto should be UDP or TCP (the default if omitted)
|
||||
*/
|
||||
virtual void SetOutputName(const std::string& name);
|
||||
void SetOutputName(const std::string& name) override;
|
||||
|
||||
/** Init the output directives from an XML file.
|
||||
@param element XML Element that is pointing to the output directives
|
||||
*/
|
||||
virtual bool Load(Element* el);
|
||||
bool Load(Element* el) override;
|
||||
|
||||
/** Initializes the instance. This method basically opens the socket to which
|
||||
outputs will be directed.
|
||||
@result true if the execution succeeded.
|
||||
*/
|
||||
bool InitModel(void);
|
||||
bool InitModel(void) override;
|
||||
/// Generates the output.
|
||||
void Print(void);
|
||||
void Print(void) override;
|
||||
|
||||
/** Outputs a status thru the socket. This method issues a message prepended
|
||||
by the string "<STATUS>" to the socket.
|
||||
|
|
|
@ -77,17 +77,17 @@ public:
|
|||
/** Init the output directives from an XML file.
|
||||
@param element XML Element that is pointing to the output directives
|
||||
*/
|
||||
virtual bool Load(Element* el);
|
||||
bool Load(Element* el) override;
|
||||
|
||||
/// Generates the output to the text file.
|
||||
virtual void Print(void);
|
||||
void Print(void) override;
|
||||
|
||||
protected:
|
||||
std::string delimeter;
|
||||
sg_ofstream datafile;
|
||||
|
||||
virtual bool OpenFile(void);
|
||||
virtual void CloseFile(void) { if (datafile.is_open()) datafile.close(); }
|
||||
bool OpenFile(void) override;
|
||||
void CloseFile(void) override { if (datafile.is_open()) datafile.close(); }
|
||||
};
|
||||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -96,7 +96,7 @@ public:
|
|||
FGOutputType(FGFDMExec* fdmex);
|
||||
|
||||
/// Destructor
|
||||
virtual ~FGOutputType();
|
||||
~FGOutputType() override;
|
||||
|
||||
/** Set the idx for this output instance
|
||||
@param idx ID of the output instance that is constructed
|
||||
|
@ -135,10 +135,10 @@ public:
|
|||
/** Init the output directives from an XML file (implement the FGModel interface).
|
||||
@param element XML Element that is pointing to the output directives
|
||||
*/
|
||||
virtual bool Load(Element* el);
|
||||
bool Load(Element* el) override;
|
||||
|
||||
/// Init the output model according to its configitation.
|
||||
virtual bool InitModel(void);
|
||||
bool InitModel(void) override;
|
||||
|
||||
/** Executes the output directives (implement the FGModel interface).
|
||||
This method checks that the current time step matches the output
|
||||
|
@ -209,7 +209,7 @@ protected:
|
|||
FGExternalReactions* ExternalReactions;
|
||||
FGBuoyantForces* BuoyantForces;
|
||||
|
||||
void Debug(int from);
|
||||
void Debug(int from) override;
|
||||
};
|
||||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -66,10 +66,10 @@ public:
|
|||
/** Reads the property names from an XML file.
|
||||
@param element The root XML Element of the input file.
|
||||
*/
|
||||
bool Load(Element* el);
|
||||
bool Load(Element* el) override;
|
||||
|
||||
/// Reads the socket and updates properties accordingly.
|
||||
void Read(bool Holding);
|
||||
void Read(bool Holding) override;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <sstream> // for assembling the error messages / what of exceptions.
|
||||
#include <stdexcept> // using domain_error, invalid_argument, and length_error.
|
||||
#include "FGXMLElement.h"
|
||||
#include "FGJSBBase.h"
|
||||
|
||||
|
@ -162,6 +164,9 @@ Element::Element(const string& nm)
|
|||
// Density
|
||||
convert["KG/L"]["LBS/GAL"] = 8.3454045;
|
||||
convert["LBS/GAL"]["KG/L"] = 1.0/convert["KG/L"]["LBS/GAL"];
|
||||
// Gravitational
|
||||
convert["FT3/SEC2"]["M3/SEC2"] = convert["FT3"]["M3"];
|
||||
convert["M3/SEC2"]["FT3/SEC2"] = convert["M3"]["FT3"];
|
||||
|
||||
// Length
|
||||
convert["M"]["M"] = 1.00;
|
||||
|
@ -235,6 +240,9 @@ Element::Element(const string& nm)
|
|||
// Density
|
||||
convert["KG/L"]["KG/L"] = 1.0;
|
||||
convert["LBS/GAL"]["LBS/GAL"] = 1.0;
|
||||
// Gravitational
|
||||
convert["FT3/SEC2"]["FT3/SEC2"] = 1.0;
|
||||
convert["M3/SEC2"]["M3/SEC2"] = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -272,18 +280,20 @@ double Element::GetAttributeValueAsNumber(const string& attr)
|
|||
string attribute = GetAttributeValue(attr);
|
||||
|
||||
if (attribute.empty()) {
|
||||
cerr << ReadFrom() << "Expecting numeric attribute value, but got no data"
|
||||
<< endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << ReadFrom() << "Expecting numeric attribute value, but got no data";
|
||||
cerr << s.str() << endl;
|
||||
throw length_error(s.str());
|
||||
}
|
||||
else {
|
||||
double number=0;
|
||||
if (is_number(trim(attribute)))
|
||||
number = atof(attribute.c_str());
|
||||
else {
|
||||
cerr << ReadFrom() << "Expecting numeric attribute value, but got: "
|
||||
<< attribute << endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << ReadFrom() << "Expecting numeric attribute value, but got: " << attribute;
|
||||
cerr << s.str() << endl;
|
||||
throw invalid_argument(s.str());
|
||||
}
|
||||
|
||||
return (number);
|
||||
|
@ -334,22 +344,29 @@ double Element::GetDataAsNumber(void)
|
|||
if (is_number(trim(data_lines[0])))
|
||||
number = atof(data_lines[0].c_str());
|
||||
else {
|
||||
cerr << ReadFrom() << "Expected numeric value, but got: " << data_lines[0]
|
||||
<< endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << ReadFrom() << "Expected numeric value, but got: " << data_lines[0];
|
||||
cerr << s.str() << endl;
|
||||
throw invalid_argument(s.str());
|
||||
}
|
||||
|
||||
return number;
|
||||
} else if (data_lines.size() == 0) {
|
||||
cerr << ReadFrom() << "Expected numeric value, but got no data" << endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << ReadFrom() << "Expected numeric value, but got no data";
|
||||
cerr << s.str() << endl;
|
||||
throw length_error(s.str());
|
||||
} else {
|
||||
cerr << ReadFrom() << "Attempting to get single data value in element "
|
||||
<< "<" << name << ">" << endl
|
||||
<< " from multiple lines:" << endl;
|
||||
for(unsigned int i=0; i<data_lines.size(); ++i)
|
||||
cerr << data_lines[i] << endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << ReadFrom() << "Attempting to get single data value in element "
|
||||
<< "<" << name << ">"
|
||||
<< " from multiple lines (" << data_lines.size() << ").";
|
||||
throw length_error(s.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,9 +433,10 @@ double Element::FindElementValueAsNumber(const string& el)
|
|||
value = DisperseValue(element, value);
|
||||
return value;
|
||||
} else {
|
||||
cerr << ReadFrom() << "Attempting to get non-existent element " << el
|
||||
<< endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << ReadFrom() << "Attempting to get non-existent element " << el;
|
||||
cerr << s.str() << endl;
|
||||
throw length_error(s.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,24 +481,28 @@ double Element::FindElementValueAsNumberConvertTo(const string& el, const string
|
|||
Element* element = FindElement(el);
|
||||
|
||||
if (!element) {
|
||||
cerr << ReadFrom() << "Attempting to get non-existent element " << el
|
||||
<< endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << ReadFrom() << "Attempting to get non-existent element " << el;
|
||||
cerr << s.str() << endl;
|
||||
throw length_error(s.str());
|
||||
}
|
||||
|
||||
string supplied_units = element->GetAttributeValue("unit");
|
||||
|
||||
if (!supplied_units.empty()) {
|
||||
if (convert.find(supplied_units) == convert.end()) {
|
||||
cerr << element->ReadFrom() << "Supplied unit: \""
|
||||
<< supplied_units << "\" does not exist (typo?)." << endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << element->ReadFrom() << "Supplied unit: \"" << supplied_units
|
||||
<< "\" does not exist (typo?).";
|
||||
cerr << s.str() << endl;
|
||||
throw invalid_argument(s.str());
|
||||
}
|
||||
if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
|
||||
cerr << element->ReadFrom() << "Supplied unit: \""
|
||||
<< supplied_units << "\" cannot be converted to " << target_units
|
||||
<< endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << element->ReadFrom() << "Supplied unit: \"" << supplied_units
|
||||
<< "\" cannot be converted to " << target_units;
|
||||
cerr << s.str() << endl;
|
||||
throw invalid_argument(s.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -528,21 +550,26 @@ double Element::FindElementValueAsNumberConvertFromTo( const string& el,
|
|||
Element* element = FindElement(el);
|
||||
|
||||
if (!element) {
|
||||
cerr << "Attempting to get non-existent element " << el << endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << ReadFrom() << "Attempting to get non-existent element " << el;
|
||||
cerr << s.str() << endl;
|
||||
throw length_error(s.str());
|
||||
}
|
||||
|
||||
if (!supplied_units.empty()) {
|
||||
if (convert.find(supplied_units) == convert.end()) {
|
||||
cerr << element->ReadFrom() << "Supplied unit: \""
|
||||
<< supplied_units << "\" does not exist (typo?)." << endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << element->ReadFrom() << "Supplied unit: \"" << supplied_units
|
||||
<< "\" does not exist (typo?).";
|
||||
cerr << s.str() << endl;
|
||||
throw invalid_argument(s.str());
|
||||
}
|
||||
if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
|
||||
cerr << element->ReadFrom() << "Supplied unit: \""
|
||||
<< supplied_units << "\" cannot be converted to " << target_units
|
||||
<< endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << element->ReadFrom() << "Supplied unit: \"" << supplied_units
|
||||
<< "\" cannot be converted to " << target_units;
|
||||
cerr << s.str() << endl;
|
||||
throw invalid_argument(s.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -567,15 +594,18 @@ FGColumnVector3 Element::FindElementTripletConvertTo( const string& target_units
|
|||
|
||||
if (!supplied_units.empty()) {
|
||||
if (convert.find(supplied_units) == convert.end()) {
|
||||
cerr << ReadFrom() << "Supplied unit: \""
|
||||
<< supplied_units << "\" does not exist (typo?)." << endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << ReadFrom() << "Supplied unit: \"" << supplied_units
|
||||
<< "\" does not exist (typo?).";
|
||||
cerr << s.str() << endl;
|
||||
throw invalid_argument(s.str());
|
||||
}
|
||||
if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
|
||||
cerr << ReadFrom() << "Supplied unit: \""
|
||||
<< supplied_units << "\" cannot be converted to " << target_units
|
||||
<< endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << ReadFrom() << "Supplied unit: \"" << supplied_units
|
||||
<< "\" cannot be converted to " << target_units;
|
||||
cerr << s.str() << endl;
|
||||
throw invalid_argument(s.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -650,8 +680,10 @@ double Element::DisperseValue(Element *e, double val, const std::string& supplie
|
|||
value = (val + disp * urn)*(fabs(urn)/urn);
|
||||
}
|
||||
} else {
|
||||
cerr << ReadFrom() << "Unknown dispersion type" << attType << endl;
|
||||
exit(-1);
|
||||
std::stringstream s;
|
||||
s << ReadFrom() << "Unknown dispersion type" << attType;
|
||||
cerr << s.str() << endl;
|
||||
throw domain_error(s.str());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,21 +9,21 @@
|
|||
------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
the terms of the GNU Lesser 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 Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
Further information about the GNU Lesser General Public License can also be
|
||||
found on the world wide web at http://www.gnu.org.
|
||||
|
||||
FUNCTIONAL DESCRIPTION
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -42,13 +42,12 @@ INCLUDES
|
|||
#include <WS2tcpip.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include "FGfdmSocket.h"
|
||||
#include "string_utilities.h"
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
|
@ -82,46 +81,53 @@ FGfdmSocket::FGfdmSocket(const string& address, int port, int protocol)
|
|||
sckt = sckt_in = 0;
|
||||
Protocol = (ProtocolType)protocol;
|
||||
connected = false;
|
||||
struct addrinfo *addr = nullptr;
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
if (!LoadWinSockDLL(debug_lvl)) return;
|
||||
#endif
|
||||
|
||||
if (!is_number(address)) {
|
||||
host = gethostbyname(address.c_str());
|
||||
if (host == NULL) {
|
||||
cerr << "Could not get host net address by name..." << endl;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
unsigned long ip = inet_addr(address.c_str());
|
||||
host = gethostbyaddr((char*)&ip, sizeof(ip), PF_INET);
|
||||
if (host == NULL) {
|
||||
cerr << "Could not get host net address by number..." << endl;
|
||||
return;
|
||||
}
|
||||
struct addrinfo hints = { 0 };
|
||||
hints.ai_family = AF_INET;
|
||||
if (protocol == ptUDP)
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
else
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = 0;
|
||||
if (!is_number(address))
|
||||
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
|
||||
else
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
|
||||
int failure = getaddrinfo(address.c_str(), NULL, &hints, &addr);
|
||||
if (failure || !addr) {
|
||||
cerr << "Could not get host net address " << address;
|
||||
|
||||
if (hints.ai_flags == AI_NUMERICHOST)
|
||||
cerr << " by number..." << endl;
|
||||
else
|
||||
cerr << " by name..." << endl;
|
||||
|
||||
cerr << gai_strerror(failure) << endl;
|
||||
|
||||
freeaddrinfo(addr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (protocol == ptUDP) { //use udp protocol
|
||||
sckt = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
sckt = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
|
||||
if (debug_lvl > 0)
|
||||
if (debug_lvl > 0) {
|
||||
if (protocol == ptUDP) //use udp protocol
|
||||
cout << "Creating UDP socket on port " << port << endl;
|
||||
}
|
||||
else { //use tcp protocol
|
||||
sckt = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (debug_lvl > 0)
|
||||
else //use tcp protocol
|
||||
cout << "Creating TCP socket on port " << port << endl;
|
||||
}
|
||||
|
||||
if (sckt >= 0) { // successful
|
||||
memset(&scktName, 0, sizeof(struct sockaddr_in));
|
||||
scktName.sin_family = AF_INET;
|
||||
scktName.sin_port = htons(port);
|
||||
memcpy(&scktName.sin_addr, host->h_addr_list[0], host->h_length);
|
||||
|
||||
int len = sizeof(struct sockaddr_in);
|
||||
memcpy(&scktName, addr->ai_addr, len);
|
||||
scktName.sin_port = htons(port);
|
||||
|
||||
if (connect(sckt, (struct sockaddr*)&scktName, len) == 0) { // successful
|
||||
if (debug_lvl > 0)
|
||||
cout << "Successfully connected to socket for output ..." << endl;
|
||||
|
@ -131,6 +137,8 @@ FGfdmSocket::FGfdmSocket(const string& address, int port, int protocol)
|
|||
} else // unsuccessful
|
||||
cerr << "Could not create socket for FDM output, error = " << errno << endl;
|
||||
|
||||
freeaddrinfo(addr);
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,21 +7,21 @@
|
|||
------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
the terms of the GNU Lesser 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 Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
Further information about the GNU Lesser General Public License can also be
|
||||
found on the world wide web at http://www.gnu.org.
|
||||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -39,26 +39,13 @@ SENTRY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <sys/types.h>
|
||||
#include "FGJSBBase.h"
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#include <winsock.h>
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma comment (lib,"WSock32.lib")
|
||||
#endif
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -106,8 +93,13 @@ public:
|
|||
enum ProtocolType {ptUDP, ptTCP};
|
||||
|
||||
private:
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
SOCKET sckt;
|
||||
SOCKET sckt_in;
|
||||
#else
|
||||
int sckt;
|
||||
int sckt_in;
|
||||
#endif
|
||||
ProtocolType Protocol;
|
||||
struct sockaddr_in scktName;
|
||||
struct hostent *host;
|
||||
|
|
|
@ -4,24 +4,24 @@ Header: FGColumnVector3.h
|
|||
Author: Originally by Tony Peden [formatted and adapted here by Jon Berndt]
|
||||
Date started: Unknown
|
||||
|
||||
------------- Copyright (C) 2001 by Tony Peden and Jon S. Berndt (jon@jsbsim.org)
|
||||
------ Copyright (C) 2001 by Tony Peden and Jon S. Berndt (jon@jsbsim.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
the terms of the GNU Lesser 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 Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
Further information about the GNU Lesser General Public License can also be
|
||||
found on the world wide web at http://www.gnu.org.
|
||||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -139,6 +139,17 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
/** Assignment operator.
|
||||
@param lv initializer list of at most 3 values (i.e. {x, y, Z})
|
||||
Copy the content of the list into *this. */
|
||||
FGColumnVector3& operator=(std::initializer_list<double> lv) {
|
||||
double *v = data;
|
||||
for(auto &x : lv)
|
||||
*(v++) = x;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Comparison operator.
|
||||
@param b other vector.
|
||||
Returns true if both vectors are exactly the same. */
|
||||
|
@ -178,12 +189,14 @@ public:
|
|||
|
||||
/// Addition operator.
|
||||
FGColumnVector3 operator+(const FGColumnVector3& B) const {
|
||||
return FGColumnVector3( data[0] + B.data[0], data[1] + B.data[1], data[2] + B.data[2] );
|
||||
return FGColumnVector3( data[0] + B.data[0], data[1] + B.data[1],
|
||||
data[2] + B.data[2] );
|
||||
}
|
||||
|
||||
/// Subtraction operator.
|
||||
FGColumnVector3 operator-(const FGColumnVector3& B) const {
|
||||
return FGColumnVector3( data[0] - B.data[0], data[1] - B.data[1], data[2] - B.data[2] );
|
||||
return FGColumnVector3( data[0] - B.data[0], data[1] - B.data[1],
|
||||
data[2] - B.data[2] );
|
||||
}
|
||||
|
||||
/// Subtract an other vector.
|
||||
|
|
|
@ -29,6 +29,9 @@ INCLUDES
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#include "simgear/misc/strutils.hxx"
|
||||
#include "FGFDMExec.h"
|
||||
|
@ -38,6 +41,7 @@ INCLUDES
|
|||
#include "input_output/FGXMLElement.h"
|
||||
#include "math/FGFunctionValue.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
@ -47,7 +51,7 @@ CLASS IMPLEMENTATION
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
const double invlog2val = 1.0/log10(2.0);
|
||||
const unsigned int MaxArgs = 9999;
|
||||
constexpr unsigned int MaxArgs = 9999;
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
@ -68,13 +72,13 @@ private:
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
template<typename func_t, unsigned int Nmin, unsigned int Nmax=Nmin,
|
||||
FGFunction::OddEven odd_even=FGFunction::OddEven::Either>
|
||||
template<typename func_t, unsigned int Nmin>
|
||||
class aFunc: public FGFunction
|
||||
{
|
||||
public:
|
||||
aFunc(const func_t& _f, FGFDMExec* fdmex, Element* el,
|
||||
const string& prefix, FGPropertyValue* v)
|
||||
const string& prefix, FGPropertyValue* v, unsigned int Nmax=Nmin,
|
||||
FGFunction::OddEven odd_even=FGFunction::OddEven::Either)
|
||||
: FGFunction(fdmex->GetPropertyManager()), f(_f)
|
||||
{
|
||||
Load(el, v, fdmex, prefix);
|
||||
|
@ -83,10 +87,64 @@ public:
|
|||
CheckOddOrEvenArguments(el, odd_even);
|
||||
}
|
||||
|
||||
double GetValue(void) const {
|
||||
double GetValue(void) const override {
|
||||
return cached ? cachedValue : f(Parameters);
|
||||
}
|
||||
|
||||
protected:
|
||||
void bind(Element* el, const string& Prefix) override {
|
||||
string nName = CreateOutputNode(el, Prefix);
|
||||
if (!nName.empty())
|
||||
PropertyManager->Tie(nName, this, &aFunc<func_t, Nmin>::GetValue);
|
||||
}
|
||||
|
||||
private:
|
||||
const func_t f;
|
||||
};
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Template specialization for functions without parameters.
|
||||
|
||||
template<typename func_t>
|
||||
class aFunc<func_t, 0>: public FGFunction
|
||||
{
|
||||
public:
|
||||
aFunc(const func_t& _f, FGPropertyManager* pm, Element* el,
|
||||
const string& Prefix)
|
||||
: FGFunction(pm), f(_f)
|
||||
{
|
||||
if (el->GetNumElements() != 0) {
|
||||
ostringstream buffer;
|
||||
buffer << el->ReadFrom() << fgred << highint
|
||||
<< "<" << el->GetName() << "> should have no arguments." << reset
|
||||
<< endl;
|
||||
throw WrongNumberOfArguments(buffer.str(), Parameters, el);
|
||||
}
|
||||
|
||||
bind(el, Prefix);
|
||||
}
|
||||
|
||||
double GetValue(void) const override {
|
||||
double result = cached ? cachedValue : f();
|
||||
if (pNode) pNode->setDoubleValue(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Functions without parameters are assumed to be non-const
|
||||
bool IsConstant(void) const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
// The method GetValue() is not bound for functions without parameters because
|
||||
// we do not want the property to return a different value each time it is
|
||||
// read.
|
||||
void bind(Element* el, const string& Prefix) override {
|
||||
CreateOutputNode(el, Prefix);
|
||||
// Initialize the node to a sensible value.
|
||||
if (pNode) pNode->setDoubleValue(f());
|
||||
}
|
||||
|
||||
private:
|
||||
const func_t f;
|
||||
};
|
||||
|
@ -129,7 +187,7 @@ FGParameter_ptr VarArgsFn(const func_t& _f, FGFDMExec* fdmex, Element* el,
|
|||
const string& prefix, FGPropertyValue* v)
|
||||
{
|
||||
try {
|
||||
return new aFunc<func_t, 2, MaxArgs>(_f, fdmex, el, prefix, v);
|
||||
return new aFunc<func_t, 2>(_f, fdmex, el, prefix, v, MaxArgs);
|
||||
}
|
||||
catch(WrongNumberOfArguments& e) {
|
||||
if ((e.GetElement() == el) && (e.NumberOfArguments() == 1)) {
|
||||
|
@ -234,11 +292,27 @@ void FGFunction::CheckOddOrEvenArguments(Element* el, OddEven odd_even)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
shared_ptr<default_random_engine> makeRandomEngine(Element *el, FGFDMExec* fdmex)
|
||||
{
|
||||
string seed_attr = el->GetAttributeValue("seed");
|
||||
unsigned int seed;
|
||||
if (seed_attr.empty())
|
||||
return fdmex->GetRandomEngine();
|
||||
else if (seed_attr == "time_now")
|
||||
seed = chrono::system_clock::now().time_since_epoch().count();
|
||||
else
|
||||
seed = atoi(seed_attr.c_str());
|
||||
return make_shared<default_random_engine>(seed);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGFunction::Load(Element* el, FGPropertyValue* var, FGFDMExec* fdmex,
|
||||
const string& Prefix)
|
||||
{
|
||||
Name = el->GetAttributeValue("name");
|
||||
Element* element = el->GetElement();
|
||||
|
||||
auto sum = [](const decltype(Parameters)& Parameters)->double {
|
||||
double temp = 0.0;
|
||||
|
||||
|
@ -358,7 +432,8 @@ void FGFunction::Load(Element* el, FGPropertyValue* var, FGFDMExec* fdmex,
|
|||
|
||||
return 1.0;
|
||||
};
|
||||
Parameters.push_back(new aFunc<decltype(f), 2, MaxArgs>(f, fdmex, element, Prefix, var));
|
||||
Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix,
|
||||
var, MaxArgs));
|
||||
} else if (operation == "or") {
|
||||
string ctxMsg = element->ReadFrom();
|
||||
auto f = [ctxMsg](const decltype(Parameters)& Parameters)->double {
|
||||
|
@ -369,7 +444,8 @@ void FGFunction::Load(Element* el, FGPropertyValue* var, FGFDMExec* fdmex,
|
|||
|
||||
return 0.0;
|
||||
};
|
||||
Parameters.push_back(new aFunc<decltype(f), 2, MaxArgs>(f, fdmex, element, Prefix, var));
|
||||
Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix,
|
||||
var, MaxArgs));
|
||||
} else if (operation == "quotient") {
|
||||
auto f = [](const decltype(Parameters)& p)->double {
|
||||
double y = p[1]->GetValue();
|
||||
|
@ -515,15 +591,37 @@ void FGFunction::Load(Element* el, FGPropertyValue* var, FGFDMExec* fdmex,
|
|||
};
|
||||
Parameters.push_back(new aFunc<decltype(f), 3>(f, fdmex, element, Prefix, var));
|
||||
} else if (operation == "random") {
|
||||
auto f = [](const decltype(Parameters)& p)->double {
|
||||
return GaussianRandomNumber();
|
||||
double mean = 0.0;
|
||||
double stddev = 1.0;
|
||||
string mean_attr = element->GetAttributeValue("mean");
|
||||
string stddev_attr = element->GetAttributeValue("stddev");
|
||||
if (!mean_attr.empty())
|
||||
mean = atof(mean_attr.c_str());
|
||||
if (!stddev_attr.empty())
|
||||
stddev = atof(stddev_attr.c_str());
|
||||
auto distribution = make_shared<normal_distribution<double>>(mean, stddev);
|
||||
auto generator(makeRandomEngine(element, fdmex));
|
||||
auto f = [generator, distribution]()->double {
|
||||
return (*distribution.get())(*generator);
|
||||
};
|
||||
Parameters.push_back(new aFunc<decltype(f), 0>(f, fdmex, element, Prefix, var));
|
||||
Parameters.push_back(new aFunc<decltype(f), 0>(f, PropertyManager, element,
|
||||
Prefix));
|
||||
} else if (operation == "urandom") {
|
||||
auto f = [](const decltype(Parameters)& p)->double {
|
||||
return -1.0 + (((double)rand()/double(RAND_MAX))*2.0);
|
||||
double lower = -1.0;
|
||||
double upper = 1.0;
|
||||
string lower_attr = element->GetAttributeValue("lower");
|
||||
string upper_attr = element->GetAttributeValue("upper");
|
||||
if (!lower_attr.empty())
|
||||
lower = atof(lower_attr.c_str());
|
||||
if (!upper_attr.empty())
|
||||
upper = atof(upper_attr.c_str());
|
||||
auto distribution = make_shared<uniform_real_distribution<double>>(lower, upper);
|
||||
auto generator(makeRandomEngine(element, fdmex));
|
||||
auto f = [generator, distribution]()->double {
|
||||
return (*distribution.get())(*generator);
|
||||
};
|
||||
Parameters.push_back(new aFunc<decltype(f), 0>(f, fdmex, element, Prefix, var));
|
||||
Parameters.push_back(new aFunc<decltype(f), 0>(f, PropertyManager, element,
|
||||
Prefix));
|
||||
} else if (operation == "switch") {
|
||||
string ctxMsg = element->ReadFrom();
|
||||
auto f = [ctxMsg](const decltype(Parameters)& p)->double {
|
||||
|
@ -548,7 +646,8 @@ void FGFunction::Load(Element* el, FGPropertyValue* var, FGFDMExec* fdmex,
|
|||
throw("Fatal error");
|
||||
}
|
||||
};
|
||||
Parameters.push_back(new aFunc<decltype(f), 2, MaxArgs>(f, fdmex, element, Prefix, var));
|
||||
Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix,
|
||||
var, MaxArgs));
|
||||
} else if (operation == "interpolate1d") {
|
||||
auto f = [](const decltype(Parameters)& p)->double {
|
||||
// This is using the bisection algorithm. Special care has been
|
||||
|
@ -584,7 +683,8 @@ void FGFunction::Load(Element* el, FGPropertyValue* var, FGFDMExec* fdmex,
|
|||
|
||||
return ymin + (x-xmin)*(ymax-ymin)/(xmax-xmin);
|
||||
};
|
||||
Parameters.push_back(new aFunc<decltype(f), 5, MaxArgs, OddEven::Odd>(f, fdmex, element, Prefix, var));
|
||||
Parameters.push_back(new aFunc<decltype(f), 5>(f, fdmex, element, Prefix,
|
||||
var, MaxArgs, OddEven::Odd));
|
||||
} else if (operation == "rotation_alpha_local") {
|
||||
// Calculates local angle of attack for skydiver body component.
|
||||
// Euler angles from the intermediate body frame to the local body frame
|
||||
|
@ -802,9 +902,6 @@ FGFunction::~FGFunction()
|
|||
|
||||
bool FGFunction::IsConstant(void) const
|
||||
{
|
||||
// Functions without parameters are assumed to be non-const
|
||||
if (Parameters.empty()) return false;
|
||||
|
||||
for (auto p: Parameters) {
|
||||
if (!p->IsConstant())
|
||||
return false;
|
||||
|
@ -850,10 +947,11 @@ string FGFunction::GetValueAsString(void) const
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGFunction::bind(Element* el, const string& Prefix)
|
||||
string FGFunction::CreateOutputNode(Element* el, const string& Prefix)
|
||||
{
|
||||
string nName;
|
||||
|
||||
if ( !Name.empty() ) {
|
||||
string nName;
|
||||
if (Prefix.empty())
|
||||
nName = PropertyManager->mkPropertyName(Name, false);
|
||||
else {
|
||||
|
@ -878,9 +976,19 @@ void FGFunction::bind(Element* el, const string& Prefix)
|
|||
<< "Property " << nName << " has already been successfully bound (late)." << endl;
|
||||
throw("Failed to bind the property to an existing already tied node.");
|
||||
}
|
||||
|
||||
PropertyManager->Tie(nName, this, &FGFunction::GetValue);
|
||||
}
|
||||
|
||||
return nName;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGFunction::bind(Element* el, const string& Prefix)
|
||||
{
|
||||
string nName = CreateOutputNode(el, Prefix);
|
||||
|
||||
if (!nName.empty())
|
||||
PropertyManager->Tie(nName, this, &FGFunction::GetValue);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -679,7 +679,6 @@ refers to one or more instances of a property, value, or table.
|
|||
</switch>
|
||||
|
||||
Example: if flight-mode is 2, the switch function returns 0.50
|
||||
|
||||
<switch>
|
||||
<p> executive/flight-mode </p>
|
||||
<v> 0.25 </v>
|
||||
|
@ -688,11 +687,32 @@ refers to one or more instances of a property, value, or table.
|
|||
<v> 1.00 </v>
|
||||
</switch>
|
||||
@endcode
|
||||
- @b random Takes no arguments and returns a Gaussian distributed random number
|
||||
@code <random/> @endcode
|
||||
- @b urandom, Takes no arguments and returns a uniformly distributed random
|
||||
number between -1 and +1
|
||||
@code<urandom/>@endcode
|
||||
- @b random Returns a normal distributed random number.
|
||||
The function, without parameters, returns a normal distributed
|
||||
random value with a distribution defined by the parameters
|
||||
mean = 0.0 and standard deviation (stddev) = 1.0
|
||||
The Mean of the distribution (its expected value, μ).
|
||||
Which coincides with the location of its peak.
|
||||
Standard deviation (σ): The square root of variance,
|
||||
representing the dispersion of values from the distribution mean.
|
||||
This shall be a positive value (σ>0).
|
||||
@code
|
||||
<random/>
|
||||
<random seed="1234"/>
|
||||
<random seed="time_now"/>
|
||||
<random seed="time_now" mean="0.0" stddev="1.0"/>
|
||||
@endcode
|
||||
- @b urandom Returns a uniformly distributed random number.
|
||||
The function, without parameters, returns a random value
|
||||
between the minimum value -1.0 and the maximum value of 1.0
|
||||
The two maximum and minimum values can be modified using the
|
||||
lower and upper parameters.
|
||||
@code
|
||||
<urandom/>
|
||||
<random seed="1234"/>
|
||||
<random seed="time_now"/>
|
||||
<random seed="time_now" lower="-1.0" upper="1.0"/>
|
||||
@endcode
|
||||
- @b pi Takes no argument and returns the value of Pi
|
||||
@code<pi/>@endcode
|
||||
- @b interpolate1d returns the result from a 1-dimensional interpolation of the
|
||||
|
@ -734,8 +754,8 @@ class FGFunction : public FGParameter, public FGJSBBase
|
|||
public:
|
||||
/// Default constructor.
|
||||
FGFunction()
|
||||
: cached(false), cachedValue(-HUGE_VAL), pNode(nullptr), pCopyTo(nullptr),
|
||||
PropertyManager(nullptr) {}
|
||||
: cached(false), cachedValue(-HUGE_VAL), PropertyManager(nullptr),
|
||||
pNode(nullptr), pCopyTo(nullptr) {}
|
||||
|
||||
explicit FGFunction(FGPropertyManager* pm)
|
||||
: FGFunction()
|
||||
|
@ -797,6 +817,8 @@ protected:
|
|||
bool cached;
|
||||
double cachedValue;
|
||||
std::vector <FGParameter_ptr> Parameters;
|
||||
FGPropertyManager* PropertyManager;
|
||||
FGPropertyNode_ptr pNode;
|
||||
|
||||
void Load(Element* element, FGPropertyValue* var, FGFDMExec* fdmex,
|
||||
const std::string& prefix="");
|
||||
|
@ -804,12 +826,11 @@ protected:
|
|||
void CheckMinArguments(Element* el, unsigned int _min);
|
||||
void CheckMaxArguments(Element* el, unsigned int _max);
|
||||
void CheckOddOrEvenArguments(Element* el, OddEven odd_even);
|
||||
std::string CreateOutputNode(Element* el, const string& Prefix);
|
||||
|
||||
private:
|
||||
std::string Name;
|
||||
FGPropertyNode_ptr pNode;
|
||||
FGPropertyNode_ptr pCopyTo; // Property node for CopyTo property string
|
||||
FGPropertyManager* PropertyManager;
|
||||
|
||||
void Debug(int from);
|
||||
};
|
||||
|
|
|
@ -10,21 +10,21 @@
|
|||
------- (C) 2011 Ola Røer Thorsen (ola@silentwings.no) -----------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
the terms of the GNU Lesser 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 Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
Further information about the GNU Lesser General Public License can also be
|
||||
found on the world wide web at http://www.gnu.org.
|
||||
|
||||
FUNCTIONAL DESCRIPTION
|
||||
------------------------------------------------------------------------------
|
||||
|
@ -47,9 +47,6 @@ INCLUDES
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
// Set up the default ground callback object.
|
||||
FGGroundCallback_ptr FGLocation::GroundCallback = NULL;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
@ -85,9 +82,9 @@ FGLocation::FGLocation(double lon, double lat, double radius)
|
|||
double cosLat = cos(lat);
|
||||
double sinLon = sin(lon);
|
||||
double cosLon = cos(lon);
|
||||
mECLoc = FGColumnVector3( radius*cosLat*cosLon,
|
||||
radius*cosLat*sinLon,
|
||||
radius*sinLat );
|
||||
mECLoc = { radius*cosLat*cosLon,
|
||||
radius*cosLat*sinLon,
|
||||
radius*sinLat };
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -115,6 +112,7 @@ FGLocation::FGLocation(const FGLocation& l)
|
|||
c = l.c;
|
||||
ec = l.ec;
|
||||
ec2 = l.ec2;
|
||||
mEllipseSet = l.mEllipseSet;
|
||||
|
||||
/*ag
|
||||
* if the cache is not valid, all of the following values are unset.
|
||||
|
@ -137,10 +135,11 @@ FGLocation::FGLocation(const FGLocation& l)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
const FGLocation& FGLocation::operator=(const FGLocation& l)
|
||||
FGLocation& FGLocation::operator=(const FGLocation& l)
|
||||
{
|
||||
mECLoc = l.mECLoc;
|
||||
mCacheValid = l.mCacheValid;
|
||||
mEllipseSet = l.mEllipseSet;
|
||||
|
||||
a = l.a;
|
||||
e2 = l.e2;
|
||||
|
@ -232,15 +231,16 @@ void FGLocation::SetPosition(double lon, double lat, double radius)
|
|||
double sinLon = sin(lon);
|
||||
double cosLon = cos(lon);
|
||||
|
||||
mECLoc = FGColumnVector3( radius*cosLat*cosLon,
|
||||
radius*cosLat*sinLon,
|
||||
radius*sinLat );
|
||||
mECLoc = { radius*cosLat*cosLon,
|
||||
radius*cosLat*sinLon,
|
||||
radius*sinLat };
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGLocation::SetPositionGeodetic(double lon, double lat, double height)
|
||||
{
|
||||
assert(mEllipseSet);
|
||||
mCacheValid = false;
|
||||
|
||||
double slat = sin(lat);
|
||||
|
@ -257,6 +257,7 @@ void FGLocation::SetPositionGeodetic(double lon, double lat, double height)
|
|||
void FGLocation::SetEllipse(double semimajor, double semiminor)
|
||||
{
|
||||
mCacheValid = false;
|
||||
mEllipseSet = true;
|
||||
|
||||
a = semimajor;
|
||||
ec = semiminor/a;
|
||||
|
@ -267,6 +268,16 @@ void FGLocation::SetEllipse(double semimajor, double semiminor)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGLocation::GetSeaLevelRadius(void) const
|
||||
{
|
||||
assert(mEllipseSet);
|
||||
ComputeDerived();
|
||||
double cosLat = cos(mLat);
|
||||
return a*ec/sqrt(1.0-e2*cosLat*cosLat);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGLocation::ComputeDerivedUnconditional(void) const
|
||||
{
|
||||
// The radius is just the Euclidean norm of the vector.
|
||||
|
@ -274,49 +285,80 @@ void FGLocation::ComputeDerivedUnconditional(void) const
|
|||
|
||||
// The distance of the location to the Z-axis, which is the axis
|
||||
// through the poles.
|
||||
double r02 = mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY);
|
||||
double rxy = sqrt(r02);
|
||||
double rxy = mECLoc.Magnitude(eX, eY);
|
||||
|
||||
// Compute the sin/cos values of the longitude
|
||||
// Compute the longitude and its sin/cos values.
|
||||
double sinLon, cosLon;
|
||||
if (rxy == 0.0) {
|
||||
sinLon = 0.0;
|
||||
cosLon = 1.0;
|
||||
mLon = 0.0;
|
||||
} else {
|
||||
sinLon = mECLoc(eY)/rxy;
|
||||
cosLon = mECLoc(eX)/rxy;
|
||||
mLon = atan2(mECLoc(eY), mECLoc(eX));
|
||||
}
|
||||
|
||||
// Compute the sin/cos values of the latitude
|
||||
// Compute the geocentric & geodetic latitudes.
|
||||
double sinLat, cosLat;
|
||||
if (mRadius == 0.0) {
|
||||
mLat = 0.0;
|
||||
sinLat = 0.0;
|
||||
cosLat = 1.0;
|
||||
} else {
|
||||
sinLat = mECLoc(eZ)/mRadius;
|
||||
cosLat = rxy/mRadius;
|
||||
if (mEllipseSet) {
|
||||
mGeodLat = 0.0;
|
||||
GeodeticAltitude = -a;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the longitude and latitude itself
|
||||
if ( mECLoc( eX ) == 0.0 && mECLoc( eY ) == 0.0 )
|
||||
mLon = 0.0;
|
||||
else
|
||||
mLon = atan2( mECLoc( eY ), mECLoc( eX ) );
|
||||
|
||||
if ( rxy == 0.0 && mECLoc( eZ ) == 0.0 )
|
||||
mLat = 0.0;
|
||||
else
|
||||
else {
|
||||
mLat = atan2( mECLoc(eZ), rxy );
|
||||
|
||||
// Calculate the geodetic latitude based on "Transformation from Cartesian to
|
||||
// geodetic coordinates accelerated by Halley's method", Fukushima T. (2006)
|
||||
// Journal of Geodesy, Vol. 79, pp. 689-693
|
||||
// Unlike I. Sofair's method which uses a closed form solution, Fukushima's
|
||||
// method is an iterative method whose convergence is so fast that only one
|
||||
// iteration suffices. In addition, Fukushima's method has a much better
|
||||
// numerical stability over Sofair's method at the North and South poles and
|
||||
// it also gives the correct result for a spherical Earth.
|
||||
if (mEllipseSet) {
|
||||
double s0 = fabs(mECLoc(eZ));
|
||||
double zc = ec * s0;
|
||||
double c0 = ec * rxy;
|
||||
double c02 = c0 * c0;
|
||||
double s02 = s0 * s0;
|
||||
double a02 = c02 + s02;
|
||||
double a0 = sqrt(a02);
|
||||
double a03 = a02 * a0;
|
||||
double s1 = zc*a03 + c*s02*s0;
|
||||
double c1 = rxy*a03 - c*c02*c0;
|
||||
double cs0c0 = c*c0*s0;
|
||||
double b0 = 1.5*cs0c0*((rxy*s0-zc*c0)*a0-cs0c0);
|
||||
s1 = s1*a03-b0*s0;
|
||||
double cc = ec*(c1*a03-b0*c0);
|
||||
mGeodLat = sign(mECLoc(eZ))*atan(s1 / cc);
|
||||
double s12 = s1 * s1;
|
||||
double cc2 = cc * cc;
|
||||
double norm = sqrt(s12 + cc2);
|
||||
cosLat = cc / norm;
|
||||
sinLat = sign(mECLoc(eZ)) * s1 / norm;
|
||||
GeodeticAltitude = (rxy*cc + s0*s1 - a*sqrt(ec2*s12 + cc2)) / norm;
|
||||
}
|
||||
else {
|
||||
sinLat = mECLoc(eZ)/mRadius;
|
||||
cosLat = rxy/mRadius;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the transform matrices from and to the earth centered frame.
|
||||
// See Stevens and Lewis, "Aircraft Control and Simulation", Second Edition,
|
||||
// Eqn. 1.4-13, page 40. In Stevens and Lewis notation, this is C_n/e - the
|
||||
// orientation of the navigation (local) frame relative to the ECEF frame,
|
||||
// and a transformation from ECEF to nav (local) frame.
|
||||
|
||||
mTec2l = FGMatrix33( -cosLon*sinLat, -sinLon*sinLat, cosLat,
|
||||
-sinLon , cosLon , 0.0 ,
|
||||
-cosLon*cosLat, -sinLon*cosLat, -sinLat );
|
||||
mTec2l = { -cosLon*sinLat, -sinLon*sinLat, cosLat,
|
||||
-sinLon , cosLon , 0.0 ,
|
||||
-cosLon*cosLat, -sinLon*cosLat, -sinLat };
|
||||
|
||||
// In Stevens and Lewis notation, this is C_e/n - the
|
||||
// orientation of the ECEF frame relative to the nav (local) frame,
|
||||
|
@ -324,34 +366,6 @@ void FGLocation::ComputeDerivedUnconditional(void) const
|
|||
|
||||
mTl2ec = mTec2l.Transposed();
|
||||
|
||||
// Calculate the geodetic latitude based on "Transformation from Cartesian
|
||||
// to geodetic coordinates accelerated by Halley's method", Fukushima T. (2006)
|
||||
// Journal of Geodesy, Vol. 79, pp. 689-693
|
||||
// Unlike I. Sofair's method which uses a closed form solution, Fukushima's
|
||||
// method is an iterative method whose convergence is so fast that only one
|
||||
// iteration suffices. In addition, Fukushima's method has a much better
|
||||
// numerical stability over Sofair's method at the North and South poles and
|
||||
// it also gives the correct result for a spherical Earth.
|
||||
|
||||
double s0 = fabs(mECLoc(eZ));
|
||||
double zc = ec * s0;
|
||||
double c0 = ec * rxy;
|
||||
double c02 = c0 * c0;
|
||||
double s02 = s0 * s0;
|
||||
double a02 = c02 + s02;
|
||||
double a0 = sqrt(a02);
|
||||
double a03 = a02 * a0;
|
||||
double s1 = zc*a03 + c*s02*s0;
|
||||
double c1 = rxy*a03 - c*c02*c0;
|
||||
double cs0c0 = c*c0*s0;
|
||||
double b0 = 1.5*cs0c0*((rxy*s0-zc*c0)*a0-cs0c0);
|
||||
s1 = s1*a03-b0*s0;
|
||||
double cc = ec*(c1*a03-b0*c0);
|
||||
mGeodLat = sign(mECLoc(eZ))*atan(s1 / cc);
|
||||
double s12 = s1 * s1;
|
||||
double cc2 = cc * cc;
|
||||
GeodeticAltitude = (rxy*cc + s0*s1 - a*sqrt(ec2*s12 + cc2)) / sqrt(s12 + cc2);
|
||||
|
||||
// Mark the cached values as valid
|
||||
mCacheValid = true;
|
||||
}
|
||||
|
@ -377,11 +391,12 @@ void FGLocation::ComputeDerivedUnconditional(void) const
|
|||
double FGLocation::GetDistanceTo(double target_longitude,
|
||||
double target_latitude) const
|
||||
{
|
||||
double delta_lat_rad = target_latitude - GetLatitude();
|
||||
double delta_lon_rad = target_longitude - GetLongitude();
|
||||
ComputeDerived();
|
||||
double delta_lat_rad = target_latitude - mLat;
|
||||
double delta_lon_rad = target_longitude - mLon;
|
||||
|
||||
double distance_a = pow(sin(0.5*delta_lat_rad), 2.0)
|
||||
+ (GetCosLatitude() * cos(target_latitude)
|
||||
+ (cos(mLat) * cos(target_latitude)
|
||||
* (pow(sin(0.5*delta_lon_rad), 2.0)));
|
||||
|
||||
return 2.0 * GetRadius() * atan2(sqrt(distance_a), sqrt(1.0 - distance_a));
|
||||
|
@ -406,11 +421,12 @@ double FGLocation::GetDistanceTo(double target_longitude,
|
|||
double FGLocation::GetHeadingTo(double target_longitude,
|
||||
double target_latitude) const
|
||||
{
|
||||
double delta_lon_rad = target_longitude - GetLongitude();
|
||||
ComputeDerived();
|
||||
double delta_lon_rad = target_longitude - mLon;
|
||||
|
||||
double Y = sin(delta_lon_rad) * cos(target_latitude);
|
||||
double X = GetCosLatitude() * sin(target_latitude)
|
||||
- GetSinLatitude() * cos(target_latitude) * cos(delta_lon_rad);
|
||||
double X = cos(mLat) * sin(target_latitude)
|
||||
- sin(mLat) * cos(target_latitude) * cos(delta_lon_rad);
|
||||
|
||||
double heading_to_waypoint_rad = atan2(Y, X);
|
||||
if (heading_to_waypoint_rad < 0) heading_to_waypoint_rad += 2.0*M_PI;
|
||||
|
|
|
@ -42,10 +42,16 @@ SENTRY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "FGJSBBase.h"
|
||||
#include "FGColumnVector3.h"
|
||||
#include "FGMatrix33.h"
|
||||
#include "input_output/FGGroundCallback.h"
|
||||
|
||||
/* Setting the -ffast-math compilation flag is highly discouraged */
|
||||
#ifdef __FAST_MATH__
|
||||
#error Usage of -ffast-math is strongly discouraged
|
||||
#endif
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -58,9 +64,9 @@ CLASS DOCUMENTATION
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/** FGLocation holds an arbitrary location in the Earth centered Earth fixed
|
||||
reference frame (ECEF). The coordinate frame ECEF has its center in the middle
|
||||
of the earth. The X-axis points from the center of the Earth towards a
|
||||
location with zero latitude and longitude on the Earth surface. The Y-axis
|
||||
reference frame (ECEF). The coordinate frame ECEF has its center in the
|
||||
middle of the earth. The X-axis points from the center of the Earth towards
|
||||
a location with zero latitude and longitude on the Earth surface. The Y-axis
|
||||
points from the center of the Earth towards a location with zero latitude
|
||||
and 90 deg East longitude on the Earth surface. The Z-axis points from the
|
||||
Earth center to the geographic north pole.
|
||||
|
@ -72,46 +78,39 @@ CLASS DOCUMENTATION
|
|||
It is common to associate a parent frame with a location. This frame is
|
||||
usually called the local horizontal frame or simply the local frame. It is
|
||||
also called the NED frame (North, East, Down), as well as the Navigation
|
||||
frame. This frame has its X/Y plane parallel to the surface of the Earth
|
||||
(with the assumption of a spherical Earth). The X-axis points towards north,
|
||||
the Y-axis points east and the Z-axis points to the center of the Earth.
|
||||
frame. This frame has its X/Y plane parallel to the surface of the Earth.
|
||||
The X-axis points towards north, the Y-axis points east and the Z-axis
|
||||
is normal to the reference spheroid (WGS84 for Earth).
|
||||
|
||||
Since the local frame is determined by the location (and NOT by the
|
||||
orientation of the vehicle IN any frame), this class also provides the
|
||||
orientation of the vehicle IN any frame), this class also provides the
|
||||
rotation matrices required to transform from the Earth centered (ECEF) frame
|
||||
to the local horizontal frame and back. This class also "owns" the
|
||||
transformations that go from the inertial frame (Earth-centered Inertial, or
|
||||
ECI) to and from the ECEF frame, as well as to and from the local frame.
|
||||
Again, this is because the ECI, ECEF, and local frames do not involve the
|
||||
actual orientation of the vehicle - only the location on the Earth surface,
|
||||
and the angular difference between the ECI and ECEF frames. There are
|
||||
conversion functions for conversion of position vectors given in the one
|
||||
to the local horizontal frame and back. This class "owns" the
|
||||
transformations that go from the ECEF frame to and from the local frame.
|
||||
Again, this is because the ECEF, and local frames do not involve the actual
|
||||
orientation of the vehicle - only the location on the Earth surface. There
|
||||
are conversion functions for conversion of position vectors given in the one
|
||||
frame to positions in the other frame.
|
||||
|
||||
To keep the transformation matrices between the ECI and ECEF frames up to
|
||||
date, the Earth angular position must be updated by calling
|
||||
SetEarthPositionAngle() or IncrementEarthPositionAngle(). This must be done
|
||||
prior to any conversion from and to the ECI frame.
|
||||
|
||||
The Earth centered reference frame is NOT an inertial frame since it rotates
|
||||
with the Earth.
|
||||
|
||||
The cartesian coordinates (X,Y,Z) in the Earth centered frame are the master values. All other
|
||||
values are computed from these master values and are cached as long as the
|
||||
location is changed by access through a non-const member function. Values
|
||||
are cached to improve performance. It is best practice to work with a
|
||||
natural set of master values. Other parameters that are derived from these
|
||||
master values are calculated only when needed, and IF they are needed and
|
||||
calculated, then they are cached (stored and remembered) so they do not need
|
||||
to be re-calculated until the master values they are derived from are
|
||||
themselves changed (and become stale).
|
||||
The cartesian coordinates (X,Y,Z) in the Earth centered frame are the master
|
||||
values. All other values are computed from these master values and are
|
||||
cached as long as the location is changed by access through a non-const
|
||||
member function. Values are cached to improve performance. It is best
|
||||
practice to work with a natural set of master values. Other parameters that
|
||||
are derived from these master values are calculated only when needed, and IF
|
||||
they are needed and calculated, then they are cached (stored and remembered)
|
||||
so they do not need to be re-calculated until the master values they are
|
||||
derived from are themselves changed (and become stale).
|
||||
|
||||
Accuracy and round off
|
||||
|
||||
Given,
|
||||
|
||||
- that we model a vehicle near the Earth
|
||||
- that the Earth surface radius is about 2*10^7, ft
|
||||
- that the Earth surface average radius is about 2*10^7, ft
|
||||
- that we use double values for the representation of the location
|
||||
|
||||
we have an accuracy of about
|
||||
|
@ -136,9 +135,8 @@ CLASS DOCUMENTATION
|
|||
change is of the same magnitude for all components in this representation
|
||||
which is an advantage for numerical stability in implicit time-stepping.
|
||||
|
||||
Note: The latitude is a GEOCENTRIC value. FlightGear converts latitude to a
|
||||
geodetic value and uses that. In order to get best matching relative to a
|
||||
map, geocentric latitude must be converted to geodetic.
|
||||
Note: Both GEOCENTRIC and GEODETIC latitudes can be used. In order to get
|
||||
best matching relative to a map, geodetic latitude must be used.
|
||||
|
||||
@see Stevens and Lewis, "Aircraft Control and Simulation", Second edition
|
||||
@see W. C. Durham "Aircraft Dynamics & Control", section 2.2
|
||||
|
@ -174,39 +172,40 @@ public:
|
|||
|
||||
/** Set the longitude.
|
||||
@param longitude Longitude in rad to set.
|
||||
Sets the longitude of the location represented with this class
|
||||
instance to the value of the given argument. The value is meant
|
||||
to be in rad. The latitude and the radius value are preserved
|
||||
with this call with the exception of radius being equal to
|
||||
zero. If the radius is previously set to zero it is changed to be
|
||||
equal to 1.0 past this call. Longitude is positive east and negative west. */
|
||||
Sets the longitude of the location represented with this class instance to
|
||||
the value of the given argument. The value is meant to be in rad. The
|
||||
latitude and the radius value are preserved with this call with the
|
||||
exception of radius being equal to zero. If the radius is previously set
|
||||
to zero it is changed to be equal to 1.0 past this call.
|
||||
Longitude is positive east and negative west.
|
||||
The arguments should be within the bounds of -pi <= lon <= pi.
|
||||
The behavior of this function with arguments outside this range is left as
|
||||
an exercise to the gentle reader ... */
|
||||
void SetLongitude(double longitude);
|
||||
|
||||
/** Set the latitude.
|
||||
@param latitude Latitude in rad to set.
|
||||
Sets the latitude of the location represented with this class
|
||||
instance to the value of the given argument. The value is meant
|
||||
to be in rad. The longitude and the radius value are preserved
|
||||
with this call with the exception of radius being equal to
|
||||
zero. If the radius is previously set to zero it is changed to be
|
||||
equal to 1.0 past this call.
|
||||
/** Set the GEOCENTRIC latitude.
|
||||
@param latitude GEOCENTRIC latitude in rad to set.
|
||||
Sets the latitude of the location represented with this class instance to
|
||||
the value of the given argument. The value is meant to be in rad. The
|
||||
longitude and the radius value are preserved with this call with the
|
||||
exception of radius being equal to zero. If the radius is previously set
|
||||
to zero it is changed to be equal to 1.0 past this call.
|
||||
Latitude is positive north and negative south.
|
||||
The arguments should be within the bounds of -pi/2 <= lat <= pi/2.
|
||||
The behavior of this function with arguments outside this range is
|
||||
left as an exercise to the gentle reader ... */
|
||||
The behavior of this function with arguments outside this range is left as
|
||||
an exercise to the gentle reader ... */
|
||||
void SetLatitude(double latitude);
|
||||
|
||||
/** Set the distance from the center of the earth.
|
||||
@param radius Radius in ft to set.
|
||||
Sets the radius of the location represented with this class
|
||||
instance to the value of the given argument. The value is meant
|
||||
to be in ft. The latitude and longitude values are preserved
|
||||
with this call with the exception of radius being equal to
|
||||
zero. If the radius is previously set to zero, latitude and
|
||||
longitude is set equal to zero past this call.
|
||||
Sets the radius of the location represented with this class instance to
|
||||
the value of the given argument. The value is meant to be in ft. The
|
||||
latitude and longitude values are preserved with this call with the
|
||||
exception of radius being equal to zero. If the radius is previously set
|
||||
to zero, latitude and longitude is set equal to zero past this call.
|
||||
The argument should be positive.
|
||||
The behavior of this function called with a negative argument is
|
||||
left as an exercise to the gentle reader ... */
|
||||
The behavior of this function called with a negative argument is left as
|
||||
an exercise to the gentle reader ... */
|
||||
void SetRadius(double radius);
|
||||
|
||||
/** Sets the longitude, latitude and the distance from the center of the earth.
|
||||
|
@ -215,7 +214,7 @@ public:
|
|||
@param radius distance from center of earth to vehicle in feet*/
|
||||
void SetPosition(double lon, double lat, double radius);
|
||||
|
||||
/** Sets the longitude, latitude and the distance above the reference ellipsoid.
|
||||
/** Sets the longitude, latitude and the distance above the reference spheroid.
|
||||
@param lon longitude in radians
|
||||
@param lat GEODETIC latitude in radians
|
||||
@param height distance above the reference ellipsoid to vehicle in feet*/
|
||||
|
@ -223,7 +222,9 @@ public:
|
|||
|
||||
/** Sets the semimajor and semiminor axis lengths for this planet.
|
||||
The eccentricity and flattening are calculated from the semimajor
|
||||
and semiminor axis lengths */
|
||||
and semiminor axis lengths.
|
||||
@param semimajor planet semi-major axis in ft.
|
||||
@param semiminor planet semi-minor axis in ft.*/
|
||||
void SetEllipse(double semimajor, double semiminor);
|
||||
|
||||
/** Get the longitude.
|
||||
|
@ -244,137 +245,51 @@ public:
|
|||
/** Get the cosine of Longitude. */
|
||||
double GetCosLongitude() const { ComputeDerived(); return mTec2l(2,2); }
|
||||
|
||||
/** Get the latitude.
|
||||
@return the latitude in rad of the location represented with this
|
||||
class instance. The returned values are in the range between
|
||||
/** Get the GEOCENTRIC latitude in radians.
|
||||
@return the geocentric latitude in rad of the location represented with
|
||||
this class instance. The returned values are in the range between
|
||||
-pi/2 <= lon <= pi/2. Latitude is positive north and negative south. */
|
||||
double GetLatitude() const { ComputeDerived(); return mLat; }
|
||||
|
||||
/** Get the geodetic latitude.
|
||||
/** Get the GEODETIC latitude in radians.
|
||||
@return the geodetic latitude in rad of the location represented with this
|
||||
class instance. The returned values are in the range between
|
||||
-pi/2 <= lon <= pi/2. Latitude is positive north and negative south. */
|
||||
double GetGeodLatitudeRad(void) const { ComputeDerived(); return mGeodLat; }
|
||||
double GetGeodLatitudeRad(void) const {
|
||||
assert(mEllipseSet);
|
||||
ComputeDerived(); return mGeodLat;
|
||||
}
|
||||
|
||||
/** Get the latitude.
|
||||
@return the latitude in deg of the location represented with this
|
||||
class instance. The returned value is in the range between
|
||||
/** Get the GEOCENTRIC latitude in degrees.
|
||||
@return the geocentric latitude in deg of the location represented with
|
||||
this class instance. The returned value is in the range between
|
||||
-90 <= lon <= 90. Latitude is positive north and negative south. */
|
||||
double GetLatitudeDeg() const { ComputeDerived(); return radtodeg*mLat; }
|
||||
|
||||
/** Get the geodetic latitude in degrees.
|
||||
/** Get the GEODETIC latitude in degrees.
|
||||
@return the geodetic latitude in degrees of the location represented by
|
||||
this class instance. The returned value is in the range between
|
||||
-90 <= lon <= 90. Latitude is positive north and negative south. */
|
||||
double GetGeodLatitudeDeg(void) const { ComputeDerived(); return radtodeg*mGeodLat; }
|
||||
|
||||
/** Gets the geodetic altitude in feet. */
|
||||
double GetGeodAltitude(void) const {ComputeDerived(); return GeodeticAltitude;}
|
||||
|
||||
/** Get the sine of Latitude. */
|
||||
double GetSinLatitude() const { ComputeDerived(); return -mTec2l(3,3); }
|
||||
|
||||
/** Get the cosine of Latitude. */
|
||||
double GetCosLatitude() const { ComputeDerived(); return mTec2l(1,3); }
|
||||
|
||||
/** Get the cosine of Latitude. */
|
||||
double GetTanLatitude() const {
|
||||
ComputeDerived();
|
||||
double cLat = mTec2l(1,3);
|
||||
if (cLat == 0.0)
|
||||
return 0.0;
|
||||
else
|
||||
return -mTec2l(3,3)/cLat;
|
||||
double GetGeodLatitudeDeg(void) const {
|
||||
assert(mEllipseSet);
|
||||
ComputeDerived(); return radtodeg*mGeodLat;
|
||||
}
|
||||
|
||||
/** Get the distance from the center of the earth.
|
||||
/** Gets the geodetic altitude in feet. */
|
||||
double GetGeodAltitude(void) const {
|
||||
assert(mEllipseSet);
|
||||
ComputeDerived(); return GeodeticAltitude;
|
||||
}
|
||||
|
||||
/** Get the sea level radius in feet below the current location. */
|
||||
double GetSeaLevelRadius(void) const;
|
||||
|
||||
/** Get the distance from the center of the earth in feet.
|
||||
@return the distance of the location represented with this class
|
||||
instance to the center of the earth in ft. The radius value is
|
||||
always positive. */
|
||||
//double GetRadius() const { return mECLoc.Magnitude(); } // may not work with FlightGear
|
||||
double GetRadius() const { ComputeDerived(); return mRadius; }
|
||||
|
||||
/** @name Functions that rely on the ground callback
|
||||
The following functions allow to set and get the vehicle position above
|
||||
the sea or the ground. The sea and the ground levels are obtained by
|
||||
interrogating an FGGroundCallback instance. A ground callback must
|
||||
therefore be set with SetGroundCallback() before calling any of these
|
||||
functions. */
|
||||
///@{
|
||||
/** Set the altitude above sea level.
|
||||
@param altitudeASL altitude above Sea Level in feet.
|
||||
@see SetGroundCallback */
|
||||
void SetAltitudeASL(double altitudeASL)
|
||||
{ SetRadius(GetSeaLevelRadius() + altitudeASL); }
|
||||
|
||||
/** Set the altitude above ground level.
|
||||
@param altitudeAGL altitude above Ground Level in feet.
|
||||
@see SetGroundCallback */
|
||||
void SetAltitudeAGL(double altitudeAGL)
|
||||
{ SetRadius(GetTerrainRadius() + altitudeAGL); }
|
||||
|
||||
/** Get the local sea level radius
|
||||
@return the sea level radius at the location in feet.
|
||||
@see SetGroundCallback */
|
||||
double GetSeaLevelRadius(void) const
|
||||
{ ComputeDerived(); return GroundCallback->GetSeaLevelRadius(*this); }
|
||||
|
||||
/** Get the local terrain radius
|
||||
@return the terrain level radius at the location in feet.
|
||||
@see SetGroundCallback */
|
||||
double GetTerrainRadius(void) const
|
||||
{ ComputeDerived(); return GroundCallback->GetTerrainGeoCentRadius(*this); }
|
||||
|
||||
/** Get the altitude above sea level.
|
||||
@return the altitude ASL in feet.
|
||||
@see SetGroundCallback */
|
||||
double GetAltitudeASL(void) const
|
||||
{ return GetRadius() - GetSeaLevelRadius(); }
|
||||
|
||||
/** Get the altitude above ground level.
|
||||
@return the altitude AGL in feet.
|
||||
@see SetGroundCallback */
|
||||
double GetAltitudeAGL(void) const {
|
||||
FGLocation c;
|
||||
FGColumnVector3 n,v,w;
|
||||
return GetContactPoint(c,n,v,w);
|
||||
}
|
||||
|
||||
/** Get terrain contact point information below the current location.
|
||||
@param contact Contact point location
|
||||
@param normal Terrain normal vector in contact point (ECEF frame)
|
||||
@param v Terrain linear velocity in contact point (ECEF frame)
|
||||
@param w Terrain angular velocity in contact point (ECEF frame)
|
||||
@return Location altitude above contact point (AGL) in feet.
|
||||
@see SetGroundCallback */
|
||||
double GetContactPoint(FGLocation& contact, FGColumnVector3& normal,
|
||||
FGColumnVector3& v, FGColumnVector3& w) const
|
||||
{ ComputeDerived(); return GroundCallback->GetAGLevel(*this, contact, normal, v, w); }
|
||||
///@}
|
||||
|
||||
/** Sets the ground callback pointer. The FGGroundCallback instance will be
|
||||
interrogated by FGLocation each time some terrain informations are needed.
|
||||
This will mainly occur when altitudes above the sea level or above the
|
||||
ground level are needed. A 'smart pointer' is used internally to prevent
|
||||
the FGGroundCallback instance against accidental deletion. This can only
|
||||
work if the calling application also make use of FGGroundCallback_ptr
|
||||
'smart pointers' to manage their copy of the ground callback.
|
||||
@param gc A pointer to a ground callback object
|
||||
@see FGGroundCallback
|
||||
*/
|
||||
static void SetGroundCallback(FGGroundCallback* gc) { GroundCallback = gc; }
|
||||
|
||||
/** Get a pointer to the ground callback currently used. Since the
|
||||
FGGroundcallback instance might have been created outside JSBSim, it is
|
||||
recommanded to store the returned pointer in a 'smart pointer'
|
||||
FGGroundCallback_ptr. This pointer maintains a reference counter and
|
||||
protects the returned pointer against an accidental deletion of the object
|
||||
it is pointing to.
|
||||
@return A pointer to the current ground callback object.
|
||||
@see FGGroundCallback
|
||||
*/
|
||||
static FGGroundCallback* GetGroundCallback(void) { return GroundCallback; }
|
||||
|
||||
/** Transform matrix from local horizontal to earth centered frame.
|
||||
@return a const reference to the rotation matrix of the transform from
|
||||
the local horizontal frame to the earth centered frame. */
|
||||
|
@ -388,16 +303,16 @@ public:
|
|||
/** Get the geodetic distance between the current location and a given
|
||||
location. This corresponds to the shortest distance between the two
|
||||
locations. Earth curvature is taken into account.
|
||||
@param target_longitude the target longitude
|
||||
@param target_latitude the target latitude
|
||||
@param target_longitude the target longitude in radians
|
||||
@param target_latitude the target latitude in radians
|
||||
@return The geodetic distance between the two locations */
|
||||
double GetDistanceTo(double target_longitude, double target_latitude) const;
|
||||
|
||||
/** Get the heading that should be followed from the current location to
|
||||
a given location along the shortest path. Earth curvature is
|
||||
taken into account.
|
||||
@param target_longitude the target longitude
|
||||
@param target_latitude the target latitude
|
||||
a given location along the shortest path. Earth curvature is taken into
|
||||
account.
|
||||
@param target_longitude the target longitude in radians
|
||||
@param target_latitude the target latitude in radians
|
||||
@return The heading that should be followed to reach the targeted
|
||||
location along the shortest path */
|
||||
double GetHeadingTo(double target_longitude, double target_latitude) const;
|
||||
|
@ -477,9 +392,9 @@ public:
|
|||
}
|
||||
|
||||
/** Sets this location via the supplied location object.
|
||||
@param v A location object reference.
|
||||
@param l A location object reference.
|
||||
@return a reference to the FGLocation object. */
|
||||
const FGLocation& operator=(const FGLocation& l);
|
||||
FGLocation& operator=(const FGLocation& l);
|
||||
|
||||
/** This operator returns true if the ECEF location vectors for the two
|
||||
location objects are equal. */
|
||||
|
@ -533,14 +448,18 @@ public:
|
|||
A new object is returned that defines a position which is the sum of the
|
||||
cartesian coordinates of the two positions provided. */
|
||||
FGLocation operator+(const FGLocation& l) const {
|
||||
return FGLocation(mECLoc + l.mECLoc);
|
||||
FGLocation result(mECLoc + l.mECLoc);
|
||||
if (mEllipseSet) result.SetEllipse(a, ec*a);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** This operator substracts two ECEF position vectors.
|
||||
A new object is returned that defines a position which is the difference
|
||||
of the cartesian coordinates of the two positions provided. */
|
||||
FGLocation operator-(const FGLocation& l) const {
|
||||
return FGLocation(mECLoc - l.mECLoc);
|
||||
FGLocation result(mECLoc - l.mECLoc);
|
||||
if (mEllipseSet) result.SetEllipse(a, ec*a);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** This operator scales an ECEF position vector.
|
||||
|
@ -548,7 +467,9 @@ public:
|
|||
coordinates of the provided ECEF position scaled by the supplied scalar
|
||||
value. */
|
||||
FGLocation operator*(double scalar) const {
|
||||
return FGLocation(scalar*mECLoc);
|
||||
FGLocation result(scalar*mECLoc);
|
||||
if (mEllipseSet) result.SetEllipse(a, ec*a);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Cast to a simple 3d vector */
|
||||
|
@ -607,9 +528,9 @@ private:
|
|||
The C++ keyword "mutable" tells the compiler that the data member is
|
||||
allowed to change during a const member function. */
|
||||
mutable bool mCacheValid;
|
||||
|
||||
/** The ground callback object pointer */
|
||||
static FGGroundCallback_ptr GroundCallback;
|
||||
// Flag that checks that geodetic methods are called after SetEllipse() has
|
||||
// been called.
|
||||
bool mEllipseSet = false;
|
||||
};
|
||||
|
||||
/** Scalar multiplication.
|
||||
|
|
|
@ -7,21 +7,21 @@ Date started: Unknown
|
|||
------------- Copyright (C) 2001 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
the terms of the GNU Lesser 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 Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
Further information about the GNU Lesser General Public License can also be
|
||||
found on the world wide web at http://www.gnu.org.
|
||||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -51,7 +51,6 @@ FORWARD DECLARATIONS
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
class FGColumnVector3;
|
||||
class FGQuaternion;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -157,7 +156,8 @@ public:
|
|||
|
||||
/** Prints the contents of the matrix.
|
||||
@param delimeter the item separator (tab or comma, etc.)
|
||||
@param prefix an additional prefix that is used to indent the 3X3 matrix printout
|
||||
@param prefix an additional prefix that is used to indent the 3X3 matrix
|
||||
printout
|
||||
@return a string with the delimeter-separated contents of the matrix */
|
||||
std::string Dump(const std::string& delimiter, const std::string& prefix) const;
|
||||
|
||||
|
@ -230,8 +230,8 @@ public:
|
|||
unsigned int Cols(void) const { return eColumns; }
|
||||
|
||||
/** Transposed matrix.
|
||||
This function only returns the transpose of this matrix. This matrix itself
|
||||
remains unchanged.
|
||||
This function only returns the transpose of this matrix. This matrix
|
||||
itself remains unchanged.
|
||||
@return the transposed matrix.
|
||||
*/
|
||||
FGMatrix33 Transposed(void) const {
|
||||
|
@ -318,6 +318,24 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
/** Assignment operator.
|
||||
|
||||
@param lv initializer list of at most 9 values.
|
||||
|
||||
Copy the content of the list into *this. */
|
||||
FGMatrix33& operator=(std::initializer_list<double> lv)
|
||||
{
|
||||
double *v = data;
|
||||
for(auto& x: lv) {
|
||||
*v = x;
|
||||
v += 3;
|
||||
if (v-data > 8)
|
||||
v -= 8;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Matrix vector multiplication.
|
||||
|
||||
@param v vector to multiply with.
|
||||
|
|
|
@ -329,7 +329,7 @@ bool FGAerodynamics::Load(Element *document)
|
|||
Name = "Aerodynamics Model: " + document->GetAttributeValue("name");
|
||||
|
||||
// Perform base class Pre-Load
|
||||
if (!FGModel::Load(document, true))
|
||||
if (!FGModel::Upload(document, true))
|
||||
return false;
|
||||
|
||||
DetermineAxisSystem(document); // Determine if Lift/Side/Drag, etc. is used.
|
||||
|
|
|
@ -7,21 +7,21 @@
|
|||
------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
the terms of the GNU Lesser 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 Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
Further information about the GNU Lesser General Public License can also be
|
||||
found on the world wide web at http://www.gnu.org.
|
||||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -63,7 +63,8 @@ CLASS DOCUMENTATION
|
|||
as ground effect, aerodynamic reference point shift, and maximum lift curve
|
||||
tailoff are handled.
|
||||
|
||||
@code
|
||||
<h3>Configuration File Format for \<aerodynamics> Section:</h3>
|
||||
@code{.xml}
|
||||
<aerodynamics>
|
||||
<alphalimits unit="{RAD | DEG}">
|
||||
<min> {number} </min>
|
||||
|
@ -90,12 +91,12 @@ CLASS DOCUMENTATION
|
|||
|
||||
Optionally two other coordinate systems may be used.<br><br>
|
||||
1) Body coordinate system:
|
||||
@code
|
||||
@code{.xml}
|
||||
<axis name="{X | Y | Z}">
|
||||
@endcode
|
||||
<br>
|
||||
2) Axial-Normal coordinate system:
|
||||
@code
|
||||
@code{.xml}
|
||||
<axis name="{AXIAL | NORMAL | SIDE}">
|
||||
@endcode
|
||||
<br>
|
||||
|
@ -117,9 +118,9 @@ public:
|
|||
@param Executive a pointer to the parent executive object */
|
||||
FGAerodynamics(FGFDMExec* Executive);
|
||||
/// Destructor
|
||||
~FGAerodynamics();
|
||||
~FGAerodynamics() override;
|
||||
|
||||
bool InitModel(void);
|
||||
bool InitModel(void) override;
|
||||
|
||||
/** Runs the Aerodynamics model; called by the Executive
|
||||
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
||||
|
@ -128,14 +129,14 @@ public:
|
|||
model, which may need to be active to listen on a socket for the
|
||||
"Resume" command to be given.
|
||||
@return false if no error */
|
||||
bool Run(bool Holding);
|
||||
bool Run(bool Holding) override;
|
||||
|
||||
/** Loads the Aerodynamics model.
|
||||
The Load function for this class expects the XML parser to
|
||||
have found the aerodynamics keyword in the configuration file.
|
||||
@param element pointer to the current XML element for aerodynamics parameters.
|
||||
@return true if successful */
|
||||
virtual bool Load(Element* element);
|
||||
bool Load(Element* element) override;
|
||||
|
||||
/** Gets the total aerodynamic force vector.
|
||||
@return a force vector reference. */
|
||||
|
@ -282,7 +283,7 @@ private:
|
|||
void bind(void);
|
||||
void BuildStabilityTransformMatrices(void);
|
||||
|
||||
void Debug(int from);
|
||||
void Debug(int from) override;
|
||||
};
|
||||
|
||||
} // namespace JSBSim
|
||||
|
|
|
@ -118,7 +118,7 @@ bool FGAircraft::Load(Element* el)
|
|||
string element_name;
|
||||
Element* element;
|
||||
|
||||
if (!FGModel::Load(el, true)) return false;
|
||||
if (!FGModel::Upload(el, true)) return false;
|
||||
|
||||
if (el->FindElement("wingarea"))
|
||||
WingArea = el->FindElementValueAsNumberConvertTo("wingarea", "FT2");
|
||||
|
|
|
@ -7,21 +7,21 @@
|
|||
------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
the terms of the GNU Lesser 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 Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
Further information about the GNU Lesser General Public License can also be
|
||||
found on the world wide web at http://www.gnu.org.
|
||||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -62,7 +62,7 @@ CLASS DOCUMENTATION
|
|||
<p> The \<metrics> section of the aircraft configuration file is read here, and
|
||||
the metrical information is held by this class.
|
||||
<h3>Configuration File Format for \<metrics> Section:</h3>
|
||||
@code
|
||||
@code{.xml}
|
||||
<metrics>
|
||||
<wingarea unit="{FT2 | M2}"> {number} </wingarea>
|
||||
<wingspan unit="{FT | M}"> {number} </wingspan>
|
||||
|
@ -106,7 +106,7 @@ public:
|
|||
FGAircraft(FGFDMExec *Executive);
|
||||
|
||||
/// Destructor
|
||||
~FGAircraft();
|
||||
~FGAircraft() override;
|
||||
|
||||
/** Runs the Aircraft model; called by the Executive
|
||||
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
||||
|
@ -116,15 +116,15 @@ public:
|
|||
"Resume" command to be given.
|
||||
@see JSBSim.cpp documentation
|
||||
@return false if no error */
|
||||
bool Run(bool Holding);
|
||||
bool Run(bool Holding) override;
|
||||
|
||||
bool InitModel(void);
|
||||
bool InitModel(void) override;
|
||||
|
||||
/** Loads the aircraft.
|
||||
The executive calls this method to load the aircraft into JSBSim.
|
||||
@param el a pointer to the element tree
|
||||
@return true if successful */
|
||||
virtual bool Load(Element* el);
|
||||
bool Load(Element* el) override;
|
||||
|
||||
/** Gets the aircraft name
|
||||
@return the name of the aircraft as a string type */
|
||||
|
@ -150,6 +150,8 @@ public:
|
|||
double GetMoments(int idx) const { return vMoments(idx); }
|
||||
const FGColumnVector3& GetForces(void) const { return vForces; }
|
||||
double GetForces(int idx) const { return vForces(idx); }
|
||||
/** Gets the the aero reference point (RP) coordinates.
|
||||
@return a vector containing the RP coordinates in the structural frame. */
|
||||
const FGColumnVector3& GetXYZrp(void) const { return vXYZrp; }
|
||||
const FGColumnVector3& GetXYZvrp(void) const { return vXYZvrp; }
|
||||
const FGColumnVector3& GetXYZep(void) const { return vXYZep; }
|
||||
|
@ -162,9 +164,6 @@ public:
|
|||
|
||||
void SetWingArea(double S) {WingArea = S;}
|
||||
|
||||
void bind(void);
|
||||
void unbind(void);
|
||||
|
||||
struct Inputs {
|
||||
FGColumnVector3 AeroForce;
|
||||
FGColumnVector3 PropForce;
|
||||
|
@ -191,7 +190,9 @@ private:
|
|||
double lbarh,lbarv,vbarh,vbarv;
|
||||
std::string AircraftName;
|
||||
|
||||
void Debug(int from);
|
||||
void bind(void);
|
||||
void unbind(void);
|
||||
void Debug(int from) override;
|
||||
};
|
||||
|
||||
} // namespace JSBSim
|
||||
|
|
|
@ -46,6 +46,7 @@ INCLUDES
|
|||
#include "initialization/FGInitialCondition.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
#include "FGInertial.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -202,7 +203,7 @@ bool FGAuxiliary::Run(bool Holding)
|
|||
vcas = veas = 0.0;
|
||||
|
||||
vPilotAccel.InitMatrix();
|
||||
vNcg = in.vBodyAccel/in.SLGravity;
|
||||
vNcg = in.vBodyAccel/in.StandardGravity;
|
||||
// Nz is Acceleration in "g's", along normal axis (-Z body axis)
|
||||
Nz = -vNcg(eZ);
|
||||
Ny = vNcg(eY);
|
||||
|
@ -213,7 +214,7 @@ bool FGAuxiliary::Run(bool Holding)
|
|||
vNwcg = mTb2w * vNcg;
|
||||
vNwcg(eZ) = 1.0 - vNwcg(eZ);
|
||||
|
||||
vPilotAccelN = vPilotAccel / in.SLGravity;
|
||||
vPilotAccelN = vPilotAccel / in.StandardGravity;
|
||||
|
||||
// VRP computation
|
||||
vLocationVRP = in.vLocation.LocalToLocation( in.Tb2l * in.VRPBody );
|
||||
|
@ -279,33 +280,25 @@ double FGAuxiliary::GetNlf(void) const
|
|||
|
||||
double FGAuxiliary::GetLongitudeRelativePosition(void) const
|
||||
{
|
||||
FGLocation source(FDMExec->GetIC()->GetLongitudeRadIC(),
|
||||
FDMExec->GetIC()->GetLatitudeRadIC(),
|
||||
in.vLocation.GetSeaLevelRadius());
|
||||
return source.GetDistanceTo(in.vLocation.GetLongitude(),
|
||||
FDMExec->GetIC()->GetLatitudeRadIC()) * fttom;
|
||||
return in.vLocation.GetDistanceTo(FDMExec->GetIC()->GetLongitudeRadIC(),
|
||||
in.vLocation.GetLatitude())* fttom;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGAuxiliary::GetLatitudeRelativePosition(void) const
|
||||
{
|
||||
FGLocation source(FDMExec->GetIC()->GetLongitudeRadIC(),
|
||||
FDMExec->GetIC()->GetLatitudeRadIC(),
|
||||
in.vLocation.GetSeaLevelRadius());
|
||||
return source.GetDistanceTo(FDMExec->GetIC()->GetLongitudeRadIC(),
|
||||
in.vLocation.GetLatitude()) * fttom;
|
||||
return in.vLocation.GetDistanceTo(in.vLocation.GetLongitude(),
|
||||
FDMExec->GetIC()->GetLatitudeRadIC())* fttom;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGAuxiliary::GetDistanceRelativePosition(void) const
|
||||
{
|
||||
FGLocation source(FDMExec->GetIC()->GetLongitudeRadIC(),
|
||||
FDMExec->GetIC()->GetLatitudeRadIC(),
|
||||
in.vLocation.GetSeaLevelRadius());
|
||||
return source.GetDistanceTo(in.vLocation.GetLongitude(),
|
||||
in.vLocation.GetLatitude()) * fttom;
|
||||
FGInitialCondition *ic = FDMExec->GetIC();
|
||||
return in.vLocation.GetDistanceTo(ic->GetLongitudeRadIC(),
|
||||
ic->GetLatitudeRadIC())* fttom;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -262,7 +262,7 @@ public:
|
|||
double DistanceAGL;
|
||||
double Wingspan;
|
||||
double Wingchord;
|
||||
double SLGravity;
|
||||
double StandardGravity;
|
||||
double Mass;
|
||||
FGMatrix33 Tl2b;
|
||||
FGMatrix33 Tb2l;
|
||||
|
|
|
@ -117,7 +117,7 @@ bool FGBuoyantForces::Load(Element *document)
|
|||
Debug(2);
|
||||
|
||||
// Perform base class Pre-Load
|
||||
if (!FGModel::Load(document, true))
|
||||
if (!FGModel::Upload(document, true))
|
||||
return false;
|
||||
|
||||
gas_cell_element = document->FindElement("gas_cell");
|
||||
|
@ -168,7 +168,7 @@ const FGMatrix33& FGBuoyantForces::GetGasMassInertia(void)
|
|||
|
||||
if (size == 0) return gasCellJ;
|
||||
|
||||
gasCellJ = FGMatrix33();
|
||||
gasCellJ.InitMatrix();
|
||||
|
||||
for (unsigned int i=0; i < size; i++) {
|
||||
gasCellJ += Cells[i]->GetInertia();
|
||||
|
|
|
@ -103,9 +103,9 @@ public:
|
|||
@param Executive a pointer to the parent executive object */
|
||||
FGBuoyantForces(FGFDMExec* Executive);
|
||||
/// Destructor
|
||||
~FGBuoyantForces();
|
||||
~FGBuoyantForces() override;
|
||||
|
||||
bool InitModel(void);
|
||||
bool InitModel(void) override;
|
||||
|
||||
/** Runs the Buoyant forces model; called by the Executive
|
||||
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
||||
|
@ -114,14 +114,14 @@ public:
|
|||
model, which may need to be active to listen on a socket for the
|
||||
"Resume" command to be given.
|
||||
@return false if no error */
|
||||
bool Run(bool Holding);
|
||||
bool Run(bool Holding) override;
|
||||
|
||||
/** Loads the Buoyant forces model.
|
||||
The Load function for this class expects the XML parser to
|
||||
have found the Buoyant_forces keyword in the configuration file.
|
||||
@param element pointer to the current XML element for Buoyant forces parameters.
|
||||
@return true if successful */
|
||||
virtual bool Load(Element* element);
|
||||
bool Load(Element* element) override;
|
||||
|
||||
/** Gets the total Buoyant force vector.
|
||||
@return a force vector in lbs. */
|
||||
|
@ -181,7 +181,7 @@ private:
|
|||
|
||||
void bind(void);
|
||||
|
||||
void Debug(int from);
|
||||
void Debug(int from) override;
|
||||
};
|
||||
|
||||
} // namespace JSBSim
|
||||
|
|
|
@ -52,6 +52,42 @@ class FGParameter;
|
|||
class Element;
|
||||
class FGPropertyManager;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGPropertyVector3
|
||||
{
|
||||
public:
|
||||
FGPropertyVector3(void) {}
|
||||
FGPropertyVector3(FGPropertyManager* pm, const std::string& baseName,
|
||||
const std::string& xcmp, const std::string& ycmp,
|
||||
const std::string& zcmp);
|
||||
|
||||
FGPropertyVector3& operator=(const FGColumnVector3& v) {
|
||||
data[0] = v(1);
|
||||
data[1] = v(2);
|
||||
data[2] = v(3);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator FGColumnVector3() const {
|
||||
return FGColumnVector3(data[0], data[1], data[2]);
|
||||
}
|
||||
|
||||
FGColumnVector3 operator*(double a) const {
|
||||
return FGColumnVector3(a * data[0], a * data[1], a * data[2]);
|
||||
}
|
||||
|
||||
private:
|
||||
SGPropObjDouble data[3];
|
||||
};
|
||||
|
||||
inline FGColumnVector3 operator*(double a, const FGPropertyVector3& v) {
|
||||
return v*a;
|
||||
}
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
@ -169,42 +205,6 @@ CLASS DOCUMENTATION
|
|||
@endcode
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGPropertyVector3
|
||||
{
|
||||
public:
|
||||
FGPropertyVector3(void) {}
|
||||
FGPropertyVector3(FGPropertyManager* pm, const std::string& baseName,
|
||||
const std::string& xcmp, const std::string& ycmp,
|
||||
const std::string& zcmp);
|
||||
|
||||
FGPropertyVector3& operator=(const FGColumnVector3& v) {
|
||||
data[0] = v(1);
|
||||
data[1] = v(2);
|
||||
data[2] = v(3);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator FGColumnVector3() const {
|
||||
return FGColumnVector3(data[0], data[1], data[2]);
|
||||
}
|
||||
|
||||
FGColumnVector3 operator*(double a) const {
|
||||
return FGColumnVector3(a * data[0], a * data[1], a * data[2]);
|
||||
}
|
||||
|
||||
private:
|
||||
SGPropObjDouble data[3];
|
||||
};
|
||||
|
||||
inline FGColumnVector3 operator*(double a, const FGPropertyVector3& v) {
|
||||
return v*a;
|
||||
}
|
||||
|
||||
class FGExternalForce : public FGForce
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -58,7 +58,7 @@ FGExternalReactions::FGExternalReactions(FGFDMExec* fdmex) : FGModel(fdmex)
|
|||
bool FGExternalReactions::Load(Element* el)
|
||||
{
|
||||
// Call the base class Load() function to load interface properties.
|
||||
if (!FGModel::Load(el, true))
|
||||
if (!FGModel::Upload(el, true))
|
||||
return false;
|
||||
|
||||
Debug(2);
|
||||
|
|
|
@ -130,9 +130,9 @@ public:
|
|||
Within the destructor the Forces and interface_properties vectors are
|
||||
cleared out and the items pointed to are deleted.
|
||||
*/
|
||||
~FGExternalReactions(void);
|
||||
~FGExternalReactions(void) override;
|
||||
|
||||
bool InitModel(void);
|
||||
bool InitModel(void) override;
|
||||
|
||||
/** Sum all the constituent forces for this cycle.
|
||||
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
||||
|
@ -141,7 +141,7 @@ public:
|
|||
model, which may need to be active to listen on a socket for the
|
||||
"Resume" command to be given.
|
||||
@return true always. */
|
||||
bool Run(bool Holding);
|
||||
bool Run(bool Holding) override;
|
||||
|
||||
/** Loads the external forces from the XML configuration file.
|
||||
If the external_reactions section is encountered in the vehicle configuration
|
||||
|
@ -149,7 +149,7 @@ public:
|
|||
a FGExternalForce object will be instantiated for each force definition.
|
||||
@param el a pointer to the XML element holding the external reactions definition.
|
||||
*/
|
||||
virtual bool Load(Element* el);
|
||||
bool Load(Element* el) override;
|
||||
|
||||
/** Retrieves the total forces defined in the external reactions.
|
||||
@return the total force in pounds.
|
||||
|
@ -171,7 +171,7 @@ private:
|
|||
FGColumnVector3 vTotalMoments;
|
||||
|
||||
void bind(void);
|
||||
void Debug(int from);
|
||||
void Debug(int from) override;
|
||||
};
|
||||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -482,7 +482,7 @@ bool FGFCS::Load(Element* document)
|
|||
}
|
||||
|
||||
// Load interface properties from document
|
||||
if (!FGModel::Load(document, true))
|
||||
if (!FGModel::Upload(document, true))
|
||||
return false;
|
||||
|
||||
Name += document->GetAttributeValue("name");
|
||||
|
|
|
@ -192,9 +192,9 @@ public:
|
|||
@param Executive a pointer to the parent executive object */
|
||||
FGFCS(FGFDMExec*);
|
||||
/// Destructor
|
||||
~FGFCS();
|
||||
~FGFCS() override;
|
||||
|
||||
bool InitModel(void);
|
||||
bool InitModel(void) override;
|
||||
|
||||
/** Runs the Flight Controls model; called by the Executive
|
||||
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
||||
|
@ -203,7 +203,7 @@ public:
|
|||
model, which may need to be active to listen on a socket for the
|
||||
"Resume" command to be given.
|
||||
@return false if no error */
|
||||
bool Run(bool Holding);
|
||||
bool Run(bool Holding) override;
|
||||
|
||||
/// @name Pilot input command retrieval
|
||||
//@{
|
||||
|
@ -536,9 +536,9 @@ public:
|
|||
Load() is called from FGFDMExec.
|
||||
@param el pointer to the Element instance
|
||||
@return true if succesful */
|
||||
virtual bool Load(Element* el);
|
||||
bool Load(Element* el) override;
|
||||
|
||||
SGPath FindFullPathName(const SGPath& path) const;
|
||||
SGPath FindFullPathName(const SGPath& path) const override;
|
||||
|
||||
void AddThrottle(void);
|
||||
double GetDt(void) const;
|
||||
|
@ -573,7 +573,7 @@ private:
|
|||
Channels SystemChannels;
|
||||
void bind(void);
|
||||
void bindThrottle(unsigned int);
|
||||
void Debug(int from);
|
||||
void Debug(int from) override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -67,9 +67,6 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, unsigned int num,
|
|||
FGPropertyManager* PropertyManager = exec->GetPropertyManager();
|
||||
MassBalance = exec->GetMassBalance();
|
||||
|
||||
gasCellJ = FGMatrix33();
|
||||
gasCellM = FGColumnVector3();
|
||||
|
||||
Buoyancy = MaxVolume = MaxOverpressure = Temperature = Pressure =
|
||||
Contents = Volume = dVolumeIdeal = 0.0;
|
||||
Xradius = Yradius = Zradius = Xwidth = Ywidth = Zwidth = 0.0;
|
||||
|
@ -361,13 +358,13 @@ void FGGasCell::Calculate(double dt)
|
|||
// Note: This is gross buoyancy. The weight of the gas itself and
|
||||
// any ballonets is not deducted here as the effects of the gas mass
|
||||
// is handled by FGMassBalance.
|
||||
vFn.InitMatrix(0.0, 0.0, - Buoyancy);
|
||||
vFn = {0.0, 0.0, - Buoyancy};
|
||||
|
||||
// Compute the inertia of the gas cell.
|
||||
// Consider the gas cell as a shape of uniform density.
|
||||
// FIXME: If the cell isn't ellipsoid or cylindrical the inertia will
|
||||
// be wrong.
|
||||
gasCellJ = FGMatrix33();
|
||||
gasCellJ.InitMatrix();
|
||||
const double mass = Contents * M_gas();
|
||||
double Ixx, Iyy, Izz;
|
||||
if ((Xradius != 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&
|
||||
|
@ -507,8 +504,6 @@ FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, unsigned int num,
|
|||
FGPropertyManager* PropertyManager = exec->GetPropertyManager();
|
||||
MassBalance = exec->GetMassBalance();
|
||||
|
||||
ballonetJ = FGMatrix33();
|
||||
|
||||
MaxVolume = MaxOverpressure = Temperature = Pressure =
|
||||
Contents = Volume = dVolumeIdeal = dU = 0.0;
|
||||
Xradius = Yradius = Zradius = Xwidth = Ywidth = Zwidth = 0.0;
|
||||
|
@ -743,7 +738,7 @@ void FGBallonet::Calculate(double dt)
|
|||
// Consider the ballonet as a shape of uniform density.
|
||||
// FIXME: If the ballonet isn't ellipsoid or cylindrical the inertia will
|
||||
// be wrong.
|
||||
ballonetJ = FGMatrix33();
|
||||
ballonetJ.InitMatrix();
|
||||
const double mass = Contents * M_air;
|
||||
double Ixx, Iyy, Izz;
|
||||
if ((Xradius != 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&
|
||||
|
|
|
@ -152,7 +152,7 @@ bool FGGroundReactions::Load(Element* document)
|
|||
Debug(2);
|
||||
|
||||
// Perform base class Pre-Load
|
||||
if (!FGModel::Load(document, true))
|
||||
if (!FGModel::Upload(document, true))
|
||||
return false;
|
||||
|
||||
unsigned int numContacts = document->GetNumElements("contact");
|
||||
|
|
|
@ -7,21 +7,21 @@
|
|||
------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
the terms of the GNU Lesser 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 Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
Further information about the GNU Lesser General Public License can also be
|
||||
found on the world wide web at http://www.gnu.org.
|
||||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -60,7 +60,7 @@ CLASS DOCUMENTATION
|
|||
moments so that these may be provided to FGPropagate. Parses the
|
||||
\<ground_reactions> section of the aircraft configuration file.
|
||||
<h3>Configuration File Format of \<ground_reactions> Section:</h3>
|
||||
@code
|
||||
@code{.xml}
|
||||
<ground_reactions>
|
||||
<contact>
|
||||
... {see FGLGear for specifics of this format}
|
||||
|
@ -80,9 +80,9 @@ class FGGroundReactions : public FGModel, public FGSurface
|
|||
{
|
||||
public:
|
||||
FGGroundReactions(FGFDMExec*);
|
||||
~FGGroundReactions(void);
|
||||
~FGGroundReactions(void) override;
|
||||
|
||||
bool InitModel(void);
|
||||
bool InitModel(void) override;
|
||||
/** Runs the Ground Reactions model; called by the Executive
|
||||
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
||||
@param Holding if true, the executive has been directed to hold the sim from
|
||||
|
@ -90,8 +90,8 @@ public:
|
|||
model, which may need to be active to listen on a socket for the
|
||||
"Resume" command to be given.
|
||||
@return false if no error */
|
||||
bool Run(bool Holding);
|
||||
virtual bool Load(Element* el);
|
||||
bool Run(bool Holding) override;
|
||||
bool Load(Element* el) override;
|
||||
const FGColumnVector3& GetForces(void) const {return vForces;}
|
||||
double GetForces(int idx) const {return vForces(idx);}
|
||||
const FGColumnVector3& GetMoments(void) const {return vMoments;}
|
||||
|
@ -100,6 +100,8 @@ public:
|
|||
std::string GetGroundReactionValues(std::string delimeter) const;
|
||||
bool GetWOW(void) const;
|
||||
|
||||
/** Gets the number of gears.
|
||||
@return the number of gears of the aircraft.*/
|
||||
int GetNumGearUnits(void) const { return (int)lGear.size(); }
|
||||
|
||||
/** Gets a gear instance
|
||||
|
@ -128,7 +130,7 @@ private:
|
|||
double DsCmd;
|
||||
|
||||
void bind(void);
|
||||
void Debug(int from);
|
||||
void Debug(int from) override;
|
||||
};
|
||||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -36,6 +36,7 @@ INCLUDES
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGInertial.h"
|
||||
#include "input_output/FGXMLElement.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -46,35 +47,30 @@ CLASS IMPLEMENTATION
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
|
||||
FGInertial::FGInertial(FGFDMExec* fgex) : FGModel(fgex)
|
||||
FGInertial::FGInertial(FGFDMExec* fgex)
|
||||
: FGModel(fgex)
|
||||
{
|
||||
Name = "FGInertial";
|
||||
Name = "Earth";
|
||||
|
||||
// Earth defaults
|
||||
double RotationRate = 0.00007292115;
|
||||
// RotationRate = 0.000072921151467;
|
||||
GM = 14.0764417572E15; // WGS84 value
|
||||
C2_0 = -4.84165371736E-04; // WGS84 value for the C2,0 coefficient
|
||||
J2 = 1.08262982E-03; // WGS84 value for J2
|
||||
a = 20925646.32546; // WGS84 semimajor axis length in feet
|
||||
// a = 20902254.5305; // Effective Earth radius for a sphere
|
||||
b = 20855486.5951; // WGS84 semiminor axis length in feet
|
||||
RadiusReference = a;
|
||||
gravType = gtWGS84;
|
||||
|
||||
// Lunar defaults
|
||||
/*
|
||||
double RotationRate = 0.0000026617;
|
||||
GM = 1.7314079E14; // Lunar GM
|
||||
RadiusReference = 5702559.05; // Equatorial radius
|
||||
C2_0 = 0; // value for the C2,0 coefficient
|
||||
J2 = 2.033542482111609E-4; // value for J2
|
||||
a = 5702559.05; // semimajor axis length in feet
|
||||
b = 5695439.63; // semiminor axis length in feet
|
||||
*/
|
||||
|
||||
vOmegaPlanet = FGColumnVector3( 0.0, 0.0, RotationRate );
|
||||
gAccelReference = GetGAccel(RadiusReference);
|
||||
vOmegaPlanet = { 0.0, 0.0, RotationRate };
|
||||
GroundCallback.reset(new FGDefaultGroundCallback(a, b));
|
||||
|
||||
bind();
|
||||
|
||||
|
@ -90,6 +86,40 @@ FGInertial::~FGInertial(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGInertial::Load(Element* el)
|
||||
{
|
||||
if (!Upload(el, true)) return false;
|
||||
|
||||
Name = el->GetAttributeValue("name");
|
||||
|
||||
if (el->FindElement("semimajor_axis"))
|
||||
a = el->FindElementValueAsNumberConvertTo("semimajor_axis", "FT");
|
||||
if (el->FindElement("semiminor_axis"))
|
||||
b = el->FindElementValueAsNumberConvertTo("semiminor_axis", "FT");
|
||||
if (el->FindElement("rotation_rate")) {
|
||||
double RotationRate = el->FindElementValueAsNumberConvertTo("rotation_rate", "RAD/SEC");
|
||||
vOmegaPlanet = {0., 0., RotationRate};
|
||||
}
|
||||
if (el->FindElement("GM"))
|
||||
GM = el->FindElementValueAsNumberConvertTo("GM", "FT3/SEC2");
|
||||
if (el->FindElement("J2"))
|
||||
J2 = el->FindElementValueAsNumber("J2"); // Dimensionless
|
||||
|
||||
GroundCallback->SetEllipse(a, b);
|
||||
|
||||
// Messages to warn the user about possible inconsistencies.
|
||||
if (a != b && J2 == 0.0)
|
||||
cout << "Gravitational constant J2 is null for a non-spherical planet." << endl;
|
||||
if (a == b && J2 != 0.0)
|
||||
cout << "Gravitational constant J2 is non-zero for a spherical planet." << endl;
|
||||
|
||||
Debug(2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGInertial::Run(bool Holding)
|
||||
{
|
||||
// Fast return if we have nothing to do ...
|
||||
|
@ -114,6 +144,36 @@ bool FGInertial::Run(bool Holding)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGMatrix33 FGInertial::GetTl2ec(const FGLocation& location) const
|
||||
{
|
||||
FGColumnVector3 North, Down, East{-location(eY), location(eX), 0.};
|
||||
|
||||
switch (gravType) {
|
||||
case gtStandard:
|
||||
{
|
||||
Down = location;
|
||||
Down *= -1.0;
|
||||
}
|
||||
break;
|
||||
case gtWGS84:
|
||||
{
|
||||
FGLocation sea_level = location;
|
||||
sea_level.SetPositionGeodetic(location.GetLongitude(),
|
||||
location.GetGeodLatitudeRad(), 0.0);
|
||||
Down = GetGravityJ2(location);
|
||||
Down -= vOmegaPlanet*(vOmegaPlanet*sea_level);}
|
||||
}
|
||||
Down.Normalize();
|
||||
East.Normalize();
|
||||
North = East*Down;
|
||||
|
||||
return FGMatrix33{North(eX), East(eX), Down(eX),
|
||||
North(eY), East(eY), Down(eY),
|
||||
North(eZ), 0.0, Down(eZ)};
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGInertial::GetGAccel(double r) const
|
||||
{
|
||||
return GM/(r*r);
|
||||
|
@ -132,7 +192,7 @@ FGColumnVector3 FGInertial::GetGravityJ2(const FGLocation& position) const
|
|||
|
||||
// Gravitation accel
|
||||
double r = position.GetRadius();
|
||||
double sinLat = position.GetSinLatitude();
|
||||
double sinLat = sin(position.GetLatitude());
|
||||
|
||||
double adivr = a/r;
|
||||
double preCommon = 1.5*J2*adivr*adivr;
|
||||
|
@ -149,11 +209,45 @@ FGColumnVector3 FGInertial::GetGravityJ2(const FGLocation& position) const
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGInertial::SetAltitudeAGL(FGLocation& location, double altitudeAGL)
|
||||
{
|
||||
FGLocation contact;
|
||||
FGColumnVector3 vDummy;
|
||||
GroundCallback->GetAGLevel(location, contact, vDummy, vDummy, vDummy);
|
||||
double groundHeight = contact.GetGeodAltitude();
|
||||
double longitude = location.GetLongitude();
|
||||
double geodLat = location.GetGeodLatitudeRad();
|
||||
location.SetPositionGeodetic(longitude, geodLat,
|
||||
groundHeight + altitudeAGL);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGInertial::SetGravityType(int gt)
|
||||
{
|
||||
// Messages to warn the user about possible inconsistencies.
|
||||
switch (gt)
|
||||
{
|
||||
case eGravType::gtStandard:
|
||||
if (a != b)
|
||||
cout << "Warning: Standard gravity model has been set for a non-spherical planet" << endl;
|
||||
break;
|
||||
case eGravType::gtWGS84:
|
||||
if (J2 == 0.0)
|
||||
cout << "Warning: WGS84 gravity model has been set without specifying the J2 gravitational constant." << endl;
|
||||
}
|
||||
|
||||
gravType = gt;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGInertial::bind(void)
|
||||
{
|
||||
PropertyManager->Tie("inertial/sea-level-radius_ft", this,
|
||||
&FGInertial::GetRefRadius);
|
||||
PropertyManager->Tie("simulation/gravity-model", &gravType);
|
||||
PropertyManager->Tie("inertial/sea-level-radius_ft", &in.Position,
|
||||
&FGLocation::GetSeaLevelRadius);
|
||||
PropertyManager->Tie("simulation/gravity-model", this, &FGInertial::GetGravityType,
|
||||
&FGInertial::SetGravityType);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -180,8 +274,14 @@ void FGInertial::Debug(int from)
|
|||
if (debug_lvl <= 0) return;
|
||||
|
||||
if (debug_lvl & 1) { // Standard console startup message output
|
||||
if (from == 0) { // Constructor
|
||||
|
||||
if (from == 0) {} // Constructor
|
||||
if (from == 2) { // Loading
|
||||
cout << endl << " Planet " << Name << endl;
|
||||
cout << " Semi major axis: " << a << endl;
|
||||
cout << " Semi minor axis: " << b << endl;
|
||||
cout << " Rotation rate : " << scientific << vOmegaPlanet(eZ) << endl;
|
||||
cout << " GM : " << GM << endl;
|
||||
cout << " J2 : " << J2 << endl << defaultfloat;
|
||||
}
|
||||
}
|
||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
||||
|
|
|
@ -38,8 +38,11 @@ SENTRY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "FGModel.h"
|
||||
#include "math/FGLocation.h"
|
||||
#include "input_output/FGGroundCallback.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -74,21 +77,78 @@ public:
|
|||
on a socket for the "Resume" command to be given.
|
||||
@return false if no error */
|
||||
bool Run(bool Holding) override;
|
||||
double SLgravity(void) const {return gAccelReference;}
|
||||
static constexpr double GetStandardGravity(void) { return gAccelReference; }
|
||||
const FGColumnVector3& GetGravity(void) const {return vGravAccel;}
|
||||
const FGColumnVector3& GetOmegaPlanet() const {return vOmegaPlanet;}
|
||||
void SetOmegaPlanet(double rate) {
|
||||
vOmegaPlanet = FGColumnVector3(0.0, 0.0, rate);
|
||||
}
|
||||
double GetRefRadius(void) const {return RadiusReference;}
|
||||
double GetSemimajor(void) const {return a;}
|
||||
double GetSemiminor(void) const {return b;}
|
||||
|
||||
struct Inputs {
|
||||
FGLocation Position;
|
||||
} in;
|
||||
/** @name Functions that rely on the ground callback
|
||||
The following functions allow to set and get the vehicle position above
|
||||
the ground. The ground level is obtained by interrogating an instance of
|
||||
FGGroundCallback. A ground callback must therefore be set with
|
||||
SetGroundCallback() before calling any of these functions. */
|
||||
///@{
|
||||
/** Get terrain contact point information below the current location.
|
||||
@param location Location at which the contact point is evaluated.
|
||||
@param contact Contact point location
|
||||
@param normal Terrain normal vector in contact point (ECEF frame)
|
||||
@param velocity Terrain linear velocity in contact point (ECEF frame)
|
||||
@param ang_velocity Terrain angular velocity in contact point (ECEF frame)
|
||||
@return Location altitude above contact point (AGL) in feet.
|
||||
@see SetGroundCallback */
|
||||
double GetContactPoint(const FGLocation& location, FGLocation& contact,
|
||||
FGColumnVector3& normal, FGColumnVector3& velocity,
|
||||
FGColumnVector3& ang_velocity) const
|
||||
{
|
||||
return GroundCallback->GetAGLevel(location, contact, normal, velocity,
|
||||
ang_velocity); }
|
||||
|
||||
/** Get the altitude above ground level.
|
||||
@return the altitude AGL in feet.
|
||||
@param location Location at which the AGL is evaluated.
|
||||
@see SetGroundCallback */
|
||||
double GetAltitudeAGL(const FGLocation& location) const {
|
||||
FGLocation lDummy;
|
||||
FGColumnVector3 vDummy;
|
||||
return GroundCallback->GetAGLevel(location, lDummy, vDummy, vDummy,
|
||||
vDummy);
|
||||
}
|
||||
|
||||
/** Set the altitude above ground level.
|
||||
@param location Location at which the AGL is set.
|
||||
@param altitudeAGL Altitude above Ground Level in feet.
|
||||
@see SetGroundCallback */
|
||||
void SetAltitudeAGL(FGLocation& location, double altitudeAGL);
|
||||
|
||||
/** Set the terrain elevation above sea level.
|
||||
@param h Terrain elevation in ft.
|
||||
@see SetGroundcallback */
|
||||
void SetTerrainElevation(double h) {
|
||||
GroundCallback->SetTerrainElevation(h);
|
||||
}
|
||||
|
||||
/** Set the simulation time.
|
||||
The elapsed time can be used by the ground callbck to assess the planet
|
||||
rotation or the movement of objects.
|
||||
@param time elapsed time in seconds since the simulation started.
|
||||
*/
|
||||
void SetTime(double time) {
|
||||
GroundCallback->SetTime(time);
|
||||
}
|
||||
///@}
|
||||
|
||||
/** Sets the ground callback pointer.
|
||||
FGInertial will take ownership of the pointer which must therefore be
|
||||
located in the heap.
|
||||
@param gc A pointer to a ground callback object
|
||||
@see FGGroundCallback
|
||||
*/
|
||||
void SetGroundCallback(FGGroundCallback* gc) { GroundCallback.reset(gc); }
|
||||
|
||||
private:
|
||||
/// These define the indices use to select the gravitation models.
|
||||
enum eGravType {
|
||||
/// Evaluate gravity using Newton's classical formula assuming the Earth is
|
||||
|
@ -99,16 +159,61 @@ private:
|
|||
gtWGS84
|
||||
};
|
||||
|
||||
/// Get the gravity type.
|
||||
int GetGravityType(void) const { return gravType; }
|
||||
|
||||
/// Set the gravity type.
|
||||
void SetGravityType(int gt);
|
||||
|
||||
/** Transform matrix from the local horizontal frame to earth centered.
|
||||
The local frame is the NED (North-East-Down) frame. Since the Down
|
||||
direction depends on the gravity so is the local frame.
|
||||
The East direction is tangent to the spheroid with a null component along
|
||||
the Z axis.
|
||||
The North direction is obtained from the cross product between East and
|
||||
Down.
|
||||
@param location The location at which the transform matrix must be
|
||||
evaluated.
|
||||
@return a rotation matrix of the transform from the earth centered frame
|
||||
to the local horizontal frame.
|
||||
*/
|
||||
FGMatrix33 GetTl2ec(const FGLocation& location) const;
|
||||
|
||||
/** Transform matrix from the earth centered to local horizontal frame.
|
||||
The local frame is the NED (North-East-Down) frame. Since the Down
|
||||
direction depends on the gravity so is the local frame.
|
||||
The East direction is tangent to the spheroid with a null component along
|
||||
the Z axis.
|
||||
The North direction is obtained from the cross product between East and
|
||||
Down.
|
||||
@param location The location at which the transform matrix must be
|
||||
evaluated.
|
||||
@return a rotation matrix of the transform from the earth centered frame
|
||||
to the local horizontal frame.
|
||||
*/
|
||||
FGMatrix33 GetTec2l(const FGLocation& location) const
|
||||
{ return GetTl2ec(location).Transposed(); }
|
||||
|
||||
struct Inputs {
|
||||
FGLocation Position;
|
||||
} in;
|
||||
|
||||
bool Load(Element* el) override;
|
||||
|
||||
private:
|
||||
// Standard gravity (9.80665 m/s^2) in ft/s^2 which is the gravity at 45 deg.
|
||||
// of latitude (see ISA 1976 and Steven & Lewis)
|
||||
// It includes the centripetal acceleration.
|
||||
static constexpr double gAccelReference = 9.80665 / fttom;
|
||||
|
||||
FGColumnVector3 vOmegaPlanet;
|
||||
FGColumnVector3 vGravAccel;
|
||||
double gAccelReference;
|
||||
double RadiusReference;
|
||||
double GM;
|
||||
double C2_0; // WGS84 value for the C2,0 coefficient
|
||||
double J2; // WGS84 value for J2
|
||||
double a; // WGS84 semimajor axis length in feet
|
||||
double b; // WGS84 semiminor axis length in feet
|
||||
int gravType;
|
||||
std::unique_ptr<FGGroundCallback> GroundCallback;
|
||||
|
||||
double GetGAccel(double r) const;
|
||||
FGColumnVector3 GetGravityJ2(const FGLocation& position) const;
|
||||
|
|
|
@ -85,13 +85,13 @@ class FGInput : public FGModel
|
|||
{
|
||||
public:
|
||||
FGInput(FGFDMExec*);
|
||||
~FGInput();
|
||||
~FGInput() override;
|
||||
|
||||
/** Load the input directives and adds a new input instance to the Input
|
||||
Manager list.
|
||||
@param el XMLElement that is pointing to the input directives
|
||||
@result true if the execution succeeded. */
|
||||
bool Load(Element* el);
|
||||
bool Load(Element* el) override;
|
||||
|
||||
/** Initializes the instance. This method is called by FGFDMExec::RunIC().
|
||||
This is were the initialization of all classes derived from FGInputType
|
||||
|
@ -99,7 +99,7 @@ public:
|
|||
to FGFDMExec::RunIC() so that the initialization process can be executed
|
||||
properly.
|
||||
@result true if the execution succeeded. */
|
||||
bool InitModel(void);
|
||||
bool InitModel(void) override;
|
||||
|
||||
/** Runs the Input model; called by the Executive
|
||||
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
||||
|
@ -108,7 +108,7 @@ public:
|
|||
model, which may need to be active to listen on a socket for the
|
||||
"Resume" command to be given.
|
||||
@return false if no error */
|
||||
bool Run(bool Holding);
|
||||
bool Run(bool Holding) override;
|
||||
|
||||
/** Adds a new input instance to the Input Manager. The definition of the
|
||||
new input instance is read from a file.
|
||||
|
@ -147,7 +147,7 @@ private:
|
|||
std::vector<FGInputType*> InputTypes;
|
||||
bool enabled;
|
||||
|
||||
void Debug(int from);
|
||||
void Debug(int from) override;
|
||||
};
|
||||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -45,6 +45,7 @@ INCLUDES
|
|||
#include "models/FGGroundReactions.h"
|
||||
#include "math/FGTable.h"
|
||||
#include "input_output/FGXMLElement.h"
|
||||
#include "models/FGInertial.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -288,7 +289,9 @@ const FGColumnVector3& FGLGear::GetBodyForces(FGSurface *surface)
|
|||
|
||||
// Compute the height of the theoretical location of the wheel (if strut is
|
||||
// not compressed) with respect to the ground level
|
||||
double height = gearLoc.GetContactPoint(contact, normal, terrainVel, dummy);
|
||||
double height = fdmex->GetInertial()->GetContactPoint(gearLoc, contact,
|
||||
normal, terrainVel,
|
||||
dummy);
|
||||
|
||||
// Does this surface contact point interact with another surface?
|
||||
if (surface) {
|
||||
|
@ -603,13 +606,11 @@ void FGLGear::ComputeSideForceCoefficient(void)
|
|||
|
||||
void FGLGear::ComputeVerticalStrutForce()
|
||||
{
|
||||
double springForce = 0;
|
||||
double dampForce = 0;
|
||||
|
||||
if (fStrutForce)
|
||||
StrutForce = min(fStrutForce->GetValue(), (double)0.0);
|
||||
else {
|
||||
springForce = -compressLength * kSpring;
|
||||
double springForce = -compressLength * kSpring;
|
||||
double dampForce = 0;
|
||||
|
||||
if (compressSpeed >= 0.0) {
|
||||
|
||||
|
|
|
@ -7,21 +7,21 @@
|
|||
------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
the terms of the GNU Lesser 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 Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
Further information about the GNU Lesser General Public License can also be
|
||||
found on the world wide web at http://www.gnu.org.
|
||||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -145,8 +145,8 @@ CLASS DOCUMENTATION
|
|||
in body frame.</li>
|
||||
</ol>
|
||||
|
||||
<h3>Configuration File Format:</h3>
|
||||
@code
|
||||
<h3>Configuration File Format for \<contact> Section:</h3>
|
||||
@code{.xml}
|
||||
<contact type="{BOGEY | STRUCTURE}" name="{string}">
|
||||
<location unit="{IN | M}">
|
||||
<x> {number} </x>
|
||||
|
@ -162,14 +162,14 @@ CLASS DOCUMENTATION
|
|||
<dynamic_friction> {number} </dynamic_friction>
|
||||
<rolling_friction> {number} </rolling_friction>
|
||||
<spring_coeff unit="{LBS/FT | N/M}"> {number} </spring_coeff>
|
||||
<damping_coeff [type="SQUARE"] unit="{LBS/FT/SEC | N/M/SEC}"> {number} </damping_coeff>
|
||||
<damping_coeff_rebound [type="SQUARE"] unit="{LBS/FT/SEC | N/M/SEC}"> {number} </damping_coeff_rebound>
|
||||
<damping_coeff type="{ | SQUARE}" unit="{LBS/FT/SEC | N/M/SEC}"> {number} </damping_coeff>
|
||||
<damping_coeff_rebound type="{ | SQUARE}" unit="{LBS/FT/SEC | N/M/SEC}"> {number} </damping_coeff_rebound>
|
||||
<max_steer unit="DEG"> {number | 0 | 360} </max_steer>
|
||||
<brake_group> {NONE | LEFT | RIGHT | CENTER | NOSE | TAIL} </brake_group>
|
||||
<retractable>{0 | 1}</retractable>
|
||||
<table name="{CORNERING_COEFF}" type="internal">
|
||||
<tableData>
|
||||
...
|
||||
{cornering parameters}
|
||||
</tableData>
|
||||
</table>
|
||||
</contact>
|
||||
|
|
|
@ -133,7 +133,7 @@ bool FGMassBalance::Load(Element* document)
|
|||
Name = "Mass Properties Model: " + document->GetAttributeValue("name");
|
||||
|
||||
// Perform base class Pre-Load
|
||||
if (!FGModel::Load(document, true))
|
||||
if (!FGModel::Upload(document, true))
|
||||
return false;
|
||||
|
||||
SetAircraftBaseInertias(ReadInertiaMatrix(document));
|
||||
|
@ -247,9 +247,9 @@ bool FGMassBalance::Run(bool Holding)
|
|||
k5 = (Ixy*Ixz + Iyz*Ixx)*denom;
|
||||
k6 = (Ixx*Iyy - Ixy*Ixy)*denom;
|
||||
|
||||
mJinv.InitMatrix( k1, k2, k3,
|
||||
k2, k4, k5,
|
||||
k3, k5, k6 );
|
||||
mJinv = { k1, k2, k3,
|
||||
k2, k4, k5,
|
||||
k3, k5, k6 };
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ public:
|
|||
explicit FGMassBalance(FGFDMExec*);
|
||||
~FGMassBalance();
|
||||
|
||||
bool Load(Element* el);
|
||||
bool Load(Element* el) override;
|
||||
bool InitModel(void) override;
|
||||
/** Runs the Mass Balance model; called by the Executive
|
||||
Can pass in a value indicating if the executive is directing the
|
||||
|
|
|
@ -107,7 +107,7 @@ SGPath FGModel::FindFullPathName(const SGPath& path) const
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGModel::Load(Element* el, bool preLoad)
|
||||
bool FGModel::Upload(Element* el, bool preLoad)
|
||||
{
|
||||
FGModelLoader ModelLoader(this);
|
||||
Element* document = ModelLoader.Open(el);
|
||||
|
|
|
@ -95,18 +95,21 @@ public:
|
|||
void SetPropertyManager(FGPropertyManager *fgpm) { PropertyManager=fgpm;}
|
||||
virtual SGPath FindFullPathName(const SGPath& path) const;
|
||||
const std::string& GetName(void) { return Name; }
|
||||
virtual bool Load(Element* el) { return true; }
|
||||
|
||||
protected:
|
||||
unsigned int exe_ctr;
|
||||
unsigned int rate;
|
||||
std::string Name;
|
||||
|
||||
/** Loads this model.
|
||||
/** Uploads this model in memory.
|
||||
Uploads the model in memory if its contents are contained in a separate
|
||||
file.
|
||||
@param el a pointer to the element
|
||||
@param preLoad true if model functions and local properties must be
|
||||
preloaded.
|
||||
@return true if model is successfully loaded*/
|
||||
virtual bool Load(Element* el, bool preLoad);
|
||||
bool Upload(Element* el, bool preLoad);
|
||||
|
||||
virtual void Debug(int from);
|
||||
|
||||
|
|
|
@ -236,7 +236,7 @@ bool FGOutput::Load(Element* document, const SGPath& dir)
|
|||
includePath = dir;
|
||||
|
||||
// Perform base class Pre-Load
|
||||
if (!FGModel::Load(document, false))
|
||||
if (!FGModel::Upload(document, false))
|
||||
return false;
|
||||
|
||||
size_t idx = OutputTypes.size();
|
||||
|
|
|
@ -195,7 +195,7 @@ public:
|
|||
@param el XMLElement that is pointing to the output directives
|
||||
@param dir optional directory path to load included files from
|
||||
@result true if the execution succeeded. */
|
||||
virtual bool Load(Element* el, const SGPath& dir = SGPath());
|
||||
bool Load(Element* el, const SGPath& dir = SGPath());
|
||||
/** Load the output directives and adds a new output instance to the Output
|
||||
Manager list. Unlike the Load() method, the new output instance is not
|
||||
generated from output directives read in a XML file but from a list of
|
||||
|
|
|
@ -69,6 +69,7 @@ INCLUDES
|
|||
#include "initialization/FGInitialCondition.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "simgear/io/iostreams/sgstream.hxx"
|
||||
#include "FGInertial.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -84,6 +85,8 @@ FGPropagate::FGPropagate(FGFDMExec* fdmex)
|
|||
Debug(0);
|
||||
Name = "FGPropagate";
|
||||
|
||||
Inertial = FDMExec->GetInertial();
|
||||
|
||||
/// These define the indices use to select the various integrators.
|
||||
// eNone = 0, eRectEuler, eTrapezoidal, eAdamsBashforth2, eAdamsBashforth3, eAdamsBashforth4};
|
||||
|
||||
|
@ -118,7 +121,7 @@ bool FGPropagate::InitModel(void)
|
|||
|
||||
// For initialization ONLY:
|
||||
VState.vLocation.SetEllipse(in.SemiMajor, in.SemiMinor);
|
||||
VState.vLocation.SetAltitudeAGL(4.0);
|
||||
Inertial->SetAltitudeAGL(VState.vLocation, 4.0);
|
||||
|
||||
VState.dqPQRidot.resize(5, FGColumnVector3(0.0,0.0,0.0));
|
||||
VState.dqUVWidot.resize(5, FGColumnVector3(0.0,0.0,0.0));
|
||||
|
@ -145,9 +148,9 @@ void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
|
|||
VState.vLocation = FGIC->GetPosition();
|
||||
|
||||
epa = FGIC->GetEarthPositionAngleIC();
|
||||
Ti2ec = FGMatrix33(cos(epa), sin(epa), 0.0,
|
||||
-sin(epa), cos(epa), 0.0,
|
||||
0.0, 0.0, 1.0);
|
||||
Ti2ec = { cos(epa), sin(epa), 0.0,
|
||||
-sin(epa), cos(epa), 0.0,
|
||||
0.0, 0.0, 1.0 };
|
||||
Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
|
||||
|
||||
VState.vInertialPosition = Tec2i * VState.vLocation;
|
||||
|
@ -228,8 +231,9 @@ bool FGPropagate::Run(bool Holding)
|
|||
Integrate(VState.vInertialVelocity, in.vUVWidot, VState.dqUVWidot, dt, integrator_translational_rate);
|
||||
}
|
||||
|
||||
// CAUTION : the order of the operations below is very important to get transformation
|
||||
// matrices that are consistent with the new state of the vehicle
|
||||
// CAUTION : the order of the operations below is very important to get
|
||||
// transformation matrices that are consistent with the new state of the
|
||||
// vehicle
|
||||
|
||||
// 1. Update the Earth position angle (EPA)
|
||||
epa += in.vOmegaPlanet(eZ)*dt;
|
||||
|
@ -237,23 +241,24 @@ bool FGPropagate::Run(bool Holding)
|
|||
// 2. Update the Ti2ec and Tec2i transforms from the updated EPA
|
||||
double cos_epa = cos(epa);
|
||||
double sin_epa = sin(epa);
|
||||
Ti2ec = FGMatrix33(cos_epa, sin_epa, 0.0,
|
||||
-sin_epa, cos_epa, 0.0,
|
||||
0.0, 0.0, 1.0);
|
||||
Ti2ec = { cos_epa, sin_epa, 0.0,
|
||||
-sin_epa, cos_epa, 0.0,
|
||||
0.0, 0.0, 1.0 };
|
||||
Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
|
||||
|
||||
// 3. Update the location from the updated Ti2ec and inertial position
|
||||
VState.vLocation = Ti2ec*VState.vInertialPosition;
|
||||
|
||||
// 4. Update the other "Location-based" transformation matrices from the updated
|
||||
// vLocation vector.
|
||||
// 4. Update the other "Location-based" transformation matrices from the
|
||||
// updated vLocation vector.
|
||||
UpdateLocationMatrices();
|
||||
|
||||
// 5. Update the "Orientation-based" transformation matrices from the updated
|
||||
// orientation quaternion and vLocation vector.
|
||||
UpdateBodyMatrices();
|
||||
|
||||
// Translational position derivative (velocities are integrated in the inertial frame)
|
||||
// Translational position derivative (velocities are integrated in the
|
||||
// inertial frame)
|
||||
CalculateUVW();
|
||||
|
||||
// Set auxilliary state variables
|
||||
|
@ -266,7 +271,8 @@ bool FGPropagate::Run(bool Holding)
|
|||
|
||||
VState.qAttitudeLocal = Tl2b.GetQuaternion();
|
||||
|
||||
// Compute vehicle velocity wrt ECEF frame, expressed in Local horizontal frame.
|
||||
// Compute vehicle velocity wrt ECEF frame, expressed in Local horizontal
|
||||
// frame.
|
||||
vVel = Tb2l * VState.vUVW;
|
||||
|
||||
Debug(2);
|
||||
|
@ -514,48 +520,76 @@ void FGPropagate::SetInertialRates(const FGColumnVector3& vRates) {
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGPropagate::GetAltitudeASL() const
|
||||
{
|
||||
return VState.vLocation.GetRadius() - VState.vLocation.GetSeaLevelRadius();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPropagate::SetAltitudeASL(double altASL)
|
||||
{
|
||||
double slr = VState.vLocation.GetSeaLevelRadius();
|
||||
VState.vLocation.SetRadius(slr + altASL);
|
||||
UpdateVehicleState();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPropagate::RecomputeLocalTerrainVelocity()
|
||||
{
|
||||
FGLocation contact;
|
||||
FGColumnVector3 normal;
|
||||
VState.vLocation.GetContactPoint(contact, normal, LocalTerrainVelocity,
|
||||
LocalTerrainAngularVelocity);
|
||||
Inertial->GetContactPoint(VState.vLocation, contact, normal,
|
||||
LocalTerrainVelocity, LocalTerrainAngularVelocity);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGPropagate::GetTerrainElevation(void) const
|
||||
{
|
||||
FGLocation contact;
|
||||
FGColumnVector3 vDummy;
|
||||
Inertial->GetContactPoint(VState.vLocation, contact, vDummy, vDummy, vDummy);
|
||||
return contact.GetGeodAltitude();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPropagate::SetTerrainElevation(double terrainElev)
|
||||
{
|
||||
double radius = terrainElev + VState.vLocation.GetSeaLevelRadius();
|
||||
FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(radius);
|
||||
Inertial->SetTerrainElevation(terrainElev);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGPropagate::GetLocalTerrainRadius(void) const
|
||||
{
|
||||
return VState.vLocation.GetTerrainRadius();
|
||||
FGLocation contact;
|
||||
FGColumnVector3 vDummy;
|
||||
Inertial->GetContactPoint(VState.vLocation, contact, vDummy, vDummy, vDummy);
|
||||
return contact.GetRadius();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGPropagate::GetDistanceAGL(void) const
|
||||
{
|
||||
return VState.vLocation.GetAltitudeAGL();
|
||||
return Inertial->GetAltitudeAGL(VState.vLocation);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGPropagate::GetDistanceAGLKm(void) const
|
||||
{
|
||||
return VState.vLocation.GetAltitudeAGL()*0.0003048;
|
||||
return GetDistanceAGL()*0.0003048;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPropagate::SetDistanceAGL(double tt)
|
||||
{
|
||||
VState.vLocation.SetAltitudeAGL(tt);
|
||||
Inertial->SetAltitudeAGL(VState.vLocation, tt);
|
||||
UpdateVehicleState();
|
||||
}
|
||||
|
||||
|
@ -563,8 +597,7 @@ void FGPropagate::SetDistanceAGL(double tt)
|
|||
|
||||
void FGPropagate::SetDistanceAGLKm(double tt)
|
||||
{
|
||||
VState.vLocation.SetAltitudeAGL(tt*3280.8399);
|
||||
UpdateVehicleState();
|
||||
SetDistanceAGL(tt*3280.8399);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -49,6 +49,7 @@ FORWARD DECLARATIONS
|
|||
namespace JSBSim {
|
||||
|
||||
class FGInitialCondition;
|
||||
class FGInertial;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
|
@ -143,7 +144,7 @@ public:
|
|||
- integrator, rotational position = Trapezoidal
|
||||
- integrator, translational position = Trapezoidal
|
||||
@param Executive a pointer to the parent executive object */
|
||||
FGPropagate(FGFDMExec* Executive);
|
||||
explicit FGPropagate(FGFDMExec* Executive);
|
||||
|
||||
/// Destructor
|
||||
~FGPropagate();
|
||||
|
@ -182,7 +183,7 @@ public:
|
|||
const FGColumnVector3& GetVel(void) const { return vVel; }
|
||||
|
||||
/** Retrieves the body frame vehicle velocity vector.
|
||||
The vector returned is represented by an FGColumnVector reference. The vector
|
||||
The vector returned is represented by an FGColumnVector3 reference. The vector
|
||||
for the velocity in Body frame is organized (Vx, Vy, Vz). The vector
|
||||
is 1-based, so that the first element can be retrieved using the "()" operator.
|
||||
In other words, vUVW(1) is Vx. Various convenience enumerators are defined
|
||||
|
@ -196,7 +197,7 @@ public:
|
|||
/** Retrieves the body angular rates vector, relative to the ECEF frame.
|
||||
Retrieves the body angular rates (p, q, r), which are calculated by integration
|
||||
of the angular acceleration.
|
||||
The vector returned is represented by an FGColumnVector reference. The vector
|
||||
The vector returned is represented by an FGColumnVector3 reference. The vector
|
||||
for the angular velocity in Body frame is organized (P, Q, R). The vector
|
||||
is 1-based, so that the first element can be retrieved using the "()" operator.
|
||||
In other words, vPQR(1) is P. Various convenience enumerators are defined
|
||||
|
@ -324,7 +325,7 @@ public:
|
|||
units ft
|
||||
@return The current altitude above sea level in feet.
|
||||
*/
|
||||
double GetAltitudeASL(void) const { return VState.vLocation.GetAltitudeASL(); }
|
||||
double GetAltitudeASL(void) const;
|
||||
|
||||
/** Returns the current altitude above sea level.
|
||||
This function returns the altitude above sea level.
|
||||
|
@ -436,7 +437,7 @@ public:
|
|||
const FGColumnVector3& GetTerrainAngularVelocity(void) const { return LocalTerrainAngularVelocity; }
|
||||
void RecomputeLocalTerrainVelocity();
|
||||
|
||||
double GetTerrainElevation(void) const { return GetLocalTerrainRadius() - VState.vLocation.GetSeaLevelRadius(); }
|
||||
double GetTerrainElevation(void) const;
|
||||
double GetDistanceAGL(void) const;
|
||||
double GetDistanceAGLKm(void) const;
|
||||
double GetRadius(void) const {
|
||||
|
@ -571,11 +572,7 @@ public:
|
|||
VState.vInertialPosition = Tec2i * VState.vLocation;
|
||||
}
|
||||
|
||||
void SetAltitudeASL(double altASL)
|
||||
{
|
||||
VState.vLocation.SetAltitudeASL(altASL);
|
||||
UpdateVehicleState();
|
||||
}
|
||||
void SetAltitudeASL(double altASL);
|
||||
void SetAltitudeASLmeters(double altASL) { SetAltitudeASL(altASL/fttom); }
|
||||
|
||||
void SetTerrainElevation(double tt);
|
||||
|
@ -623,6 +620,7 @@ private:
|
|||
|
||||
struct VehicleState VState;
|
||||
|
||||
FGInertial* Inertial = nullptr;
|
||||
FGColumnVector3 vVel;
|
||||
FGMatrix33 Tec2b;
|
||||
FGMatrix33 Tb2ec;
|
||||
|
|
|
@ -365,7 +365,7 @@ bool FGPropulsion::Load(Element* el)
|
|||
Name = "Propulsion Model: " + el->GetAttributeValue("name");
|
||||
|
||||
// Perform base class Pre-Load
|
||||
if (!FGModel::Load(el, true))
|
||||
if (!FGModel::Upload(el, true))
|
||||
return false;
|
||||
|
||||
// Process tank definitions first to establish the number of fuel tanks
|
||||
|
@ -581,7 +581,7 @@ const FGMatrix33& FGPropulsion::CalculateTankInertias(void)
|
|||
|
||||
if (size == 0) return tankJ;
|
||||
|
||||
tankJ = FGMatrix33();
|
||||
tankJ.InitMatrix();
|
||||
|
||||
for (unsigned int i=0; i<size; i++) {
|
||||
tankJ += FDMExec->GetMassBalance()->GetPointmassInertia( lbtoslug * Tanks[i]->GetContents(),
|
||||
|
|
|
@ -102,7 +102,7 @@ public:
|
|||
/// Constructor
|
||||
FGPropulsion(FGFDMExec*);
|
||||
/// Destructor
|
||||
~FGPropulsion();
|
||||
~FGPropulsion() override;
|
||||
|
||||
/** Executes the propulsion model.
|
||||
The initial plan for the FGPropulsion class calls for Run() to be executed,
|
||||
|
@ -113,15 +113,15 @@ public:
|
|||
model, which may need to be active to listen on a socket for the
|
||||
"Resume" command to be given.
|
||||
@return false if no error */
|
||||
bool Run(bool Holding);
|
||||
bool Run(bool Holding) override;
|
||||
|
||||
bool InitModel(void);
|
||||
bool InitModel(void) override;
|
||||
|
||||
/** Loads the propulsion system (engine[s] and tank[s]).
|
||||
Characteristics of the propulsion system are read in from the config file.
|
||||
@param el pointer to an XML element that contains the engine information.
|
||||
@return true if successfully loaded, otherwise false */
|
||||
virtual bool Load(Element* el);
|
||||
bool Load(Element* el) override;
|
||||
|
||||
/// Retrieves the number of engines defined for the aircraft.
|
||||
unsigned int GetNumEngines(void) const {return (unsigned int)Engines.size();}
|
||||
|
@ -173,7 +173,7 @@ public:
|
|||
const FGColumnVector3& GetTanksMoment(void);
|
||||
double GetTanksWeight(void) const;
|
||||
|
||||
SGPath FindFullPathName(const SGPath& path) const;
|
||||
SGPath FindFullPathName(const SGPath& path) const override;
|
||||
inline int GetActiveEngine(void) const {return ActiveEngine;}
|
||||
inline bool GetFuelFreeze(void) const {return FuelFreeze;}
|
||||
|
||||
|
@ -221,7 +221,7 @@ private:
|
|||
bool ReadingEngine;
|
||||
|
||||
void bind();
|
||||
void Debug(int from);
|
||||
void Debug(int from) override;
|
||||
};
|
||||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -101,7 +101,7 @@ public:
|
|||
FGStandardAtmosphere(FGFDMExec*);
|
||||
|
||||
/// Destructor
|
||||
virtual ~FGStandardAtmosphere();
|
||||
~FGStandardAtmosphere() override;
|
||||
|
||||
bool InitModel(void) override;
|
||||
|
||||
|
|
|
@ -4,27 +4,28 @@
|
|||
Author: Jon Berndt, Tony Peden, Andreas Gaeb
|
||||
Date started: Extracted from FGAtmosphere, which originated in 1998
|
||||
5/2011
|
||||
Purpose: Models winds, gusts, turbulence, and other atmospheric disturbances
|
||||
Purpose: Models winds, gusts, turbulence, and other atmospheric
|
||||
disturbances
|
||||
Called by: FGFDMExec
|
||||
|
||||
------------- Copyright (C) 2011 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
the terms of the GNU Lesser 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 Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
Further information about the GNU Lesser General Public License can also be
|
||||
found on the world wide web at http://www.gnu.org.
|
||||
|
||||
FUNCTIONAL DESCRIPTION
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -42,10 +43,9 @@ COMMENTS, REFERENCES, and NOTES
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include "FGWinds.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "math/FGTable.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -69,7 +69,7 @@ static inline double square_signed (double value)
|
|||
*/
|
||||
|
||||
/// simply square a value
|
||||
static inline double sqr(double x) { return x*x; }
|
||||
constexpr double sqr(double x) { return x*x; }
|
||||
|
||||
FGWinds::FGWinds(FGFDMExec* fdmex) : FGModel(fdmex)
|
||||
{
|
||||
|
@ -438,7 +438,7 @@ void FGWinds::CosineGust()
|
|||
if (profile.elapsedTime > (profile.startupDuration + profile.steadyDuration + profile.endDuration)) {
|
||||
profile.Running = false;
|
||||
profile.elapsedTime = 0.0;
|
||||
oneMinusCosineGust.vWindTransformed.InitMatrix(0.0);
|
||||
oneMinusCosineGust.vWindTransformed.InitMatrix();
|
||||
vCosineGust.InitMatrix(0);
|
||||
}
|
||||
}
|
||||
|
@ -521,7 +521,7 @@ void FGWinds::bind(void)
|
|||
PropertyManager->Tie("atmosphere/cosine-gust/X-velocity-ft_sec", this, (Ptr)0L, &FGWinds::GustXComponent);
|
||||
PropertyManager->Tie("atmosphere/cosine-gust/Y-velocity-ft_sec", this, (Ptr)0L, &FGWinds::GustYComponent);
|
||||
PropertyManager->Tie("atmosphere/cosine-gust/Z-velocity-ft_sec", this, (Ptr)0L, &FGWinds::GustZComponent);
|
||||
PropertyManager->Tie("atmosphere/cosine-gust/start", this, (PMFt)0L, (PMFi)&FGWinds::StartGust);
|
||||
PropertyManager->Tie("atmosphere/cosine-gust/start", this, static_cast<bool (FGWinds::*)(void) const>(nullptr), &FGWinds::StartGust);
|
||||
|
||||
// User-specified Up- Down-burst parameters
|
||||
PropertyManager->Tie("atmosphere/updownburst/number-of-cells", this, (PMFt)0L, &FGWinds::NumberOfUpDownburstCells);
|
||||
|
|
|
@ -7,21 +7,21 @@
|
|||
------------- Copyright (C) 2011 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
the terms of the GNU Lesser 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 Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
Further information about the GNU Lesser General Public License can also be
|
||||
found on the world wide web at http://www.gnu.org.
|
||||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -39,9 +39,7 @@ INCLUDES
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "models/FGModel.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
#include "math/FGMatrix33.h"
|
||||
#include "math/FGTable.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -49,12 +47,15 @@ FORWARD DECLARATIONS
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
class FGTable;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/** Models atmospheric disturbances: winds, gusts, turbulence, downbursts, etc.
|
||||
|
||||
<h2>Turbulence</h2>
|
||||
Various turbulence models are available. They are specified
|
||||
via the property <tt>atmosphere/turb-type</tt>. The following models are
|
||||
available:
|
||||
|
@ -64,22 +65,23 @@ CLASS DOCUMENTATION
|
|||
- 3: ttMilspec (Dryden spectrum)
|
||||
- 4: ttTustin (Dryden spectrum)
|
||||
|
||||
The Milspec and Tustin models are described in the Yeager report cited below.
|
||||
They both use a Dryden spectrum model whose parameters (scale lengths and intensities)
|
||||
are modelled according to MIL-F-8785C. Parameters are modelled differently
|
||||
for altitudes below 1000ft and above 2000ft, for altitudes in between they
|
||||
are interpolated linearly.
|
||||
The Milspec and Tustin models are described in the Yeager report cited
|
||||
below. They both use a Dryden spectrum model whose parameters (scale
|
||||
lengths and intensities) are modelled according to MIL-F-8785C. Parameters
|
||||
are modelled differently for altitudes below 1000ft and above 2000ft, for
|
||||
altitudes in between they are interpolated linearly.
|
||||
|
||||
The two models differ in the implementation of the transfer functions
|
||||
described in the milspec.
|
||||
|
||||
To use one of these two models, set <tt>atmosphere/turb-type</tt> to 4 resp. 5,
|
||||
and specify values for <tt>atmosphere/turbulence/milspec/windspeed_at_20ft_AGL-fps<tt>
|
||||
and <tt>atmosphere/turbulence/milspec/severity<tt> (the latter corresponds to
|
||||
the probability of exceedence curves from Fig. 7 of the milspec, allowable
|
||||
range is 0 (disabled) to 7). <tt>atmosphere/psiw-rad</tt> is respected as well;
|
||||
note that you have to specify a positive wind magnitude to prevent psiw from
|
||||
being reset to zero.
|
||||
To use one of these two models, set <tt>atmosphere/turb-type</tt> to 4
|
||||
resp. 5, and specify values for
|
||||
<tt>atmosphere/turbulence/milspec/windspeed_at_20ft_AGL-fps</tt> and
|
||||
<tt>atmosphere/turbulence/milspec/severity</tt> (the latter corresponds to
|
||||
the probability of exceedence curves from Fig. 7 of the milspec,
|
||||
allowable range is 0 (disabled) to 7). <tt>atmosphere/psiw-rad</tt> is
|
||||
respected as well; note that you have to specify a positive wind magnitude
|
||||
to prevent psiw from being reset to zero.
|
||||
|
||||
Reference values (cf. figures 7 and 9 from the milspec):
|
||||
<table>
|
||||
|
@ -97,6 +99,57 @@ CLASS DOCUMENTATION
|
|||
<td>6</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>Cosine Gust</h2>
|
||||
A one minus cosine gust model is available. This permits a configurable,
|
||||
predictable gust to be input to JSBSim for testing handling and
|
||||
dynamics. Here is how a gust can be entered in a script:
|
||||
|
||||
~~~{.xml}
|
||||
<event name="Introduce gust">
|
||||
<condition> simulation/sim-time-sec ge 10 </condition>
|
||||
<set name="atmosphere/cosine-gust/startup-duration-sec" value="5"/>
|
||||
<set name="atmosphere/cosine-gust/steady-duration-sec" value="1"/>
|
||||
<set name="atmosphere/cosine-gust/end-duration-sec" value="5"/>
|
||||
<set name="atmosphere/cosine-gust/magnitude-ft_sec" value="30"/>
|
||||
<set name="atmosphere/cosine-gust/frame" value="2"/>
|
||||
<set name="atmosphere/cosine-gust/X-velocity-ft_sec" value="-1"/>
|
||||
<set name="atmosphere/cosine-gust/Y-velocity-ft_sec" value="0"/>
|
||||
<set name="atmosphere/cosine-gust/Z-velocity-ft_sec" value="0"/>
|
||||
<set name="atmosphere/cosine-gust/start" value="1"/>
|
||||
<notify/>
|
||||
</event>
|
||||
~~~
|
||||
|
||||
The x, y, z velocity components are meant to define the direction vector.
|
||||
The vector will be normalized by the routine, so it does not need to be a
|
||||
unit vector.
|
||||
|
||||
The startup duration is the time it takes to build up to full strength
|
||||
(magnitude-ft_sec) from zero. Steady duration is the time the gust stays at
|
||||
the specified magnitude. End duration is the time it takes to dwindle to
|
||||
zero from the specified magnitude. The start and end transients are in a
|
||||
smooth cosine shape.
|
||||
|
||||
The frame is specified from the following enum:
|
||||
|
||||
enum eGustFrame {gfNone=0, gfBody, gfWind, gfLocal};
|
||||
|
||||
That is, if you specify the X, Y, Z gust direction vector in the body frame,
|
||||
frame will be "1". If the X, Y, and Z gust direction vector is in the Wind
|
||||
frame, use frame = 2. If you specify the gust direction vector in the local
|
||||
frame (N-E-D) use frame = 3. Note that an internal local frame direction
|
||||
vector is created based on the X, Y, Z direction vector you specify and the
|
||||
frame *at the time the gust is begun*. The direction vector is not updated
|
||||
after the initial creation. This is to keep the gust at the same direction
|
||||
independent of aircraft dynamics.
|
||||
|
||||
The gust is triggered when the property atmosphere/cosine-gust/start is set
|
||||
to 1. It can be used repeatedly - the gust resets itself after it has
|
||||
completed.
|
||||
|
||||
The cosine gust is global: it affects the whole world not just the vicinity
|
||||
of the aircraft.
|
||||
|
||||
@see Yeager, Jessie C.: "Implementation and Testing of Turbulence Models for
|
||||
the F18-HARV" (<a
|
||||
href="http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19980028448_1998081596.pdf">
|
||||
|
@ -114,18 +167,18 @@ class FGWinds : public FGModel {
|
|||
public:
|
||||
|
||||
/// Constructor
|
||||
FGWinds(FGFDMExec*);
|
||||
explicit FGWinds(FGFDMExec*);
|
||||
/// Destructor
|
||||
~FGWinds();
|
||||
/** Runs the winds model; called by the Executive
|
||||
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
||||
@param Holding if true, the executive has been directed to hold the sim from
|
||||
advancing time. Some models may ignore this flag, such as the Input
|
||||
model, which may need to be active to listen on a socket for the
|
||||
"Resume" command to be given.
|
||||
@param Holding if true, the executive has been directed to hold the sim
|
||||
from advancing time. Some models may ignore this flag, such
|
||||
as the Input model, which may need to be active to listen
|
||||
on a socket for the "Resume" command to be given.
|
||||
@return false if no error */
|
||||
bool Run(bool Holding);
|
||||
bool InitModel(void);
|
||||
bool Run(bool Holding) override;
|
||||
bool InitModel(void) override;
|
||||
enum tType {ttNone, ttStandard, ttCulp, ttMilspec, ttTustin} turbType;
|
||||
|
||||
// TOTAL WIND access functions (wind + gust + turbulence)
|
||||
|
@ -159,10 +212,11 @@ public:
|
|||
virtual double GetWindPsi(void) const { return psiw; }
|
||||
|
||||
/** Sets the direction that the wind is coming from.
|
||||
The direction is defined as north=0 and increases counterclockwise to 2*pi (radians). The
|
||||
vertical component of wind is assumed to be zero - and is forcibly set to zero. This function
|
||||
sets the vWindNED vector components based on the supplied direction. The magnitude of
|
||||
the wind set in the vector is preserved (assuming the vertical component is non-zero).
|
||||
The direction is defined as north=0 and increases counterclockwise to 2*pi
|
||||
(radians). The vertical component of wind is assumed to be zero - and is
|
||||
forcibly set to zero. This function sets the vWindNED vector components
|
||||
based on the supplied direction. The magnitude of the wind set in the
|
||||
vector is preserved (assuming the vertical component is non-zero).
|
||||
@param dir wind direction in the horizontal plane, in radians.*/
|
||||
virtual void SetWindPsi(double dir);
|
||||
|
||||
|
@ -190,7 +244,8 @@ public:
|
|||
/// Retrieves the gust components in NED frame.
|
||||
virtual const FGColumnVector3& GetGustNED(void) const {return vGustNED;}
|
||||
|
||||
/** Turbulence models available: ttNone, ttStandard, ttBerndt, ttCulp, ttMilspec, ttTustin */
|
||||
/** Turbulence models available: ttNone, ttStandard, ttBerndt, ttCulp,
|
||||
ttMilspec, ttTustin */
|
||||
virtual void SetTurbType(tType tt) {turbType = tt;}
|
||||
virtual tType GetTurbType() const {return turbType;}
|
||||
|
||||
|
@ -348,7 +403,7 @@ private:
|
|||
double DistanceFromRingCenter(double lat, double lon);
|
||||
|
||||
virtual void bind(void);
|
||||
void Debug(int from);
|
||||
void Debug(int from) override;
|
||||
};
|
||||
|
||||
} // namespace JSBSim
|
||||
|
|
|
@ -51,7 +51,6 @@ CLASS IMPLEMENTATION
|
|||
|
||||
FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
|
||||
{
|
||||
Element *input_element,*init_element, *clip_el;
|
||||
Input = Output = delay_time = 0.0;
|
||||
delay = index = 0;
|
||||
ClipMin = ClipMax = new FGRealValue(0.0);
|
||||
|
@ -111,14 +110,14 @@ FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
|
|||
|
||||
Name = element->GetAttributeValue("name");
|
||||
|
||||
init_element = element->FindElement("init");
|
||||
Element *init_element = element->FindElement("init");
|
||||
while (init_element) {
|
||||
InitNodes.push_back(new FGPropertyValue(init_element->GetDataLine(),
|
||||
PropertyManager ));
|
||||
init_element = element->FindNextElement("init");
|
||||
}
|
||||
|
||||
input_element = element->FindElement("input");
|
||||
Element *input_element = element->FindElement("input");
|
||||
while (input_element) {
|
||||
InputNodes.push_back(new FGPropertyValue(input_element->GetDataLine(),
|
||||
PropertyManager ));
|
||||
|
@ -137,9 +136,12 @@ FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
|
|||
throw(string("Invalid output property name in flight control definition"));
|
||||
}
|
||||
OutputNodes.push_back(OutputNode);
|
||||
// Initialize to a sensible value.
|
||||
// If the node has just been created then it must be initialized to a
|
||||
// sensible value since FGPropertyNode::GetNode() does not take care of
|
||||
// that. If the node was already existing, its current value is kept
|
||||
// unchanged.
|
||||
if (!node_exists)
|
||||
OutputNode->setDoubleValue(Output);
|
||||
OutputNode->setDoubleValue(Output);
|
||||
out_elem = element->FindNextElement("output");
|
||||
}
|
||||
|
||||
|
@ -162,7 +164,7 @@ FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
|
|||
for (unsigned int i=0; i<delay; i++) output_array[i] = 0.0;
|
||||
}
|
||||
|
||||
clip_el = element->FindElement("clipto");
|
||||
Element *clip_el = element->FindElement("clipto");
|
||||
if (clip_el) {
|
||||
Element* el = clip_el->FindElement("min");
|
||||
if (!el) {
|
||||
|
@ -220,10 +222,17 @@ void FGFCSComponent::SetOutput(void)
|
|||
|
||||
void FGFCSComponent::Delay(void)
|
||||
{
|
||||
output_array[index] = Output;
|
||||
if ((unsigned int)index == delay-1) index = 0;
|
||||
else index++;
|
||||
Output = output_array[index];
|
||||
if (fcs->GetTrimStatus()) {
|
||||
// Update the whole history while trim routines are executing.
|
||||
// Don't want to model delays while calculating a trim solution.
|
||||
std::fill(output_array.begin(), output_array.end(), Output);
|
||||
}
|
||||
else {
|
||||
output_array[index] = Output;
|
||||
if ((unsigned int)index == delay-1) index = 0;
|
||||
else index++;
|
||||
Output = output_array[index];
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -236,10 +245,10 @@ void FGFCSComponent::Clip(void)
|
|||
double range = vmax - vmin;
|
||||
|
||||
if (range < 0.0) {
|
||||
cerr << "Trying to clip with a max value (" << vmax << ") from "
|
||||
<< ClipMax->GetName() << " lower than the min value (" << vmin
|
||||
<< ") from " << ClipMin->GetName() << "." << endl
|
||||
<< "Clipping is ignored." << endl;
|
||||
cerr << "Trying to clip with a max value " << ClipMax->GetName()
|
||||
<< " lower than the min value " << ClipMin->GetName()
|
||||
<< endl;
|
||||
throw("JSBSim aborts");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -276,6 +285,10 @@ void FGFCSComponent::bind(Element* el)
|
|||
|
||||
if (node) {
|
||||
OutputNodes.push_back(node);
|
||||
// If the node has just been created then it must be initialized to a
|
||||
// sensible value since FGPropertyNode::GetNode() does not take care of
|
||||
// that. If the node was already existing, its current value is kept
|
||||
// unchanged.
|
||||
if (!node_exists)
|
||||
node->setDoubleValue(Output);
|
||||
}
|
||||
|
|
|
@ -212,7 +212,7 @@ void FGFilter::Debug(int from)
|
|||
if (from == 0) { // Constructor
|
||||
cout << " INPUT: " << InputNodes[0]->GetName() << endl;
|
||||
|
||||
for (int i=1; i <= 7; i++) {
|
||||
for (int i=1; i < 7; i++) {
|
||||
if (!C[i]) break;
|
||||
|
||||
cout << " C[" << i << "]";
|
||||
|
|
|
@ -74,15 +74,20 @@ FGMagnetometer::FGMagnetometer(FGFCS* fcs, Element* element)
|
|||
//would be better to get the date from the sim if its simulated...
|
||||
time_t rawtime;
|
||||
time( &rawtime );
|
||||
tm * ptm = gmtime ( &rawtime );
|
||||
struct tm ptm;
|
||||
#ifdef _MSC_VER
|
||||
gmtime_s(&ptm, &rawtime);
|
||||
#else
|
||||
gmtime_r(&rawtime, &ptm);
|
||||
#endif
|
||||
|
||||
int year = ptm->tm_year;
|
||||
int year = ptm.tm_year;
|
||||
if(year>100)
|
||||
{
|
||||
year-= 100;
|
||||
}
|
||||
//the months here are zero based TODO find out if the function expects 1s based
|
||||
date = (yymmdd_to_julian_days(ptm->tm_year,ptm->tm_mon,ptm->tm_mday));//Julian 1950-2049 yy,mm,dd
|
||||
date = (yymmdd_to_julian_days(ptm.tm_year, ptm.tm_mon, ptm.tm_mday)); //Julian 1950-2049 yy,mm,dd
|
||||
updateInertialMag();
|
||||
|
||||
Debug(0);
|
||||
|
@ -97,8 +102,7 @@ FGMagnetometer::~FGMagnetometer()
|
|||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
void FGMagnetometer::updateInertialMag(void)
|
||||
{
|
||||
counter++;
|
||||
if (counter > INERTIAL_UPDATE_RATE)//dont need to update every iteration
|
||||
if (counter++ % INERTIAL_UPDATE_RATE == 0)//dont need to update every iteration
|
||||
{
|
||||
counter = 0;
|
||||
|
||||
|
|
|
@ -52,8 +52,8 @@ FGPID::FGPID(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
|
|||
|
||||
I_out_total = 0.0;
|
||||
Input_prev = Input_prev2 = 0.0;
|
||||
Trigger = 0;
|
||||
ProcessVariableDot = 0;
|
||||
Trigger = nullptr;
|
||||
ProcessVariableDot = nullptr;
|
||||
IsStandard = false;
|
||||
IntType = eNone; // No integrator initially defined.
|
||||
|
||||
|
@ -96,13 +96,20 @@ FGPID::FGPID(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
|
|||
|
||||
el = element->FindElement("pvdot");
|
||||
if (el)
|
||||
ProcessVariableDot = PropertyManager->GetNode(el->GetDataLine());
|
||||
ProcessVariableDot = new FGPropertyValue(el->GetDataLine(), PropertyManager);
|
||||
|
||||
el = element->FindElement("trigger");
|
||||
if (el)
|
||||
Trigger = PropertyManager->GetNode(el->GetDataLine());
|
||||
Trigger = new FGPropertyValue(el->GetDataLine(), PropertyManager);
|
||||
|
||||
bind(element);
|
||||
bind(el);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPID::bind(Element *el)
|
||||
{
|
||||
FGFCSComponent::bind(el);
|
||||
|
||||
string tmp;
|
||||
if (Name.find("/") == string::npos) {
|
||||
|
@ -111,7 +118,7 @@ FGPID::FGPID(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
|
|||
tmp = Name;
|
||||
}
|
||||
typedef double (FGPID::*PMF)(void) const;
|
||||
PropertyManager->Tie(tmp+"/initial-integrator-value", this, (PMF)0,
|
||||
PropertyManager->Tie(tmp+"/initial-integrator-value", this, (PMF)nullptr,
|
||||
&FGPID::SetInitialOutput);
|
||||
|
||||
Debug(0);
|
||||
|
@ -124,6 +131,8 @@ FGPID::~FGPID()
|
|||
delete Kp;
|
||||
delete Ki;
|
||||
delete Kd;
|
||||
delete Trigger;
|
||||
delete ProcessVariableDot;
|
||||
Debug(1);
|
||||
}
|
||||
|
||||
|
@ -157,7 +166,7 @@ bool FGPID::Run(void )
|
|||
// is negative.
|
||||
|
||||
double test = 0.0;
|
||||
if (Trigger != 0) test = Trigger->getDoubleValue();
|
||||
if (Trigger) test = Trigger->getDoubleValue();
|
||||
|
||||
if (fabs(test) < 0.000001) {
|
||||
switch(IntType) {
|
||||
|
|
|
@ -148,10 +148,9 @@ private:
|
|||
|
||||
eIntegrateType IntType;
|
||||
|
||||
FGParameter *Kp, *Ki, *Kd;
|
||||
FGPropertyNode_ptr Trigger;
|
||||
FGPropertyNode_ptr ProcessVariableDot;
|
||||
FGParameter *Kp, *Ki, *Kd, *Trigger, *ProcessVariableDot;
|
||||
|
||||
void bind(Element* el) override;
|
||||
void Debug(int from) override;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -40,6 +40,9 @@ INCLUDES
|
|||
#include "FGWaypoint.h"
|
||||
#include "input_output/FGXMLElement.h"
|
||||
#include "math/FGLocation.h"
|
||||
#include "models/FGFCS.h"
|
||||
#include "models/FGInertial.h"
|
||||
#include "initialization/FGInitialCondition.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -61,9 +64,11 @@ FGWaypoint::FGWaypoint(FGFCS* fcs, Element* element)
|
|||
target_longitude_unit = 1.0;
|
||||
source_latitude_unit = 1.0;
|
||||
source_longitude_unit = 1.0;
|
||||
source = fcs->GetExec()->GetIC()->GetPosition();
|
||||
|
||||
if (element->FindElement("target_latitude") ) {
|
||||
target_latitude = PropertyManager->CreatePropertyObject<double>(element->FindElementValue("target_latitude"));
|
||||
target_latitude.reset(new FGPropertyValue(element->FindElementValue("target_latitude"),
|
||||
PropertyManager));
|
||||
if (element->FindElement("target_latitude")->HasAttribute("unit")) {
|
||||
if (element->FindElement("target_latitude")->GetAttributeValue("unit") == "DEG") {
|
||||
target_latitude_unit = 0.017453293;
|
||||
|
@ -77,7 +82,8 @@ FGWaypoint::FGWaypoint(FGFCS* fcs, Element* element)
|
|||
}
|
||||
|
||||
if (element->FindElement("target_longitude") ) {
|
||||
target_longitude = PropertyManager->CreatePropertyObject<double>(element->FindElementValue("target_longitude"));
|
||||
target_longitude.reset(new FGPropertyValue(element->FindElementValue("target_longitude"),
|
||||
PropertyManager));
|
||||
if (element->FindElement("target_longitude")->HasAttribute("unit")) {
|
||||
if (element->FindElement("target_longitude")->GetAttributeValue("unit") == "DEG") {
|
||||
target_longitude_unit = 0.017453293;
|
||||
|
@ -91,7 +97,8 @@ FGWaypoint::FGWaypoint(FGFCS* fcs, Element* element)
|
|||
}
|
||||
|
||||
if (element->FindElement("source_latitude") ) {
|
||||
source_latitude = PropertyManager->CreatePropertyObject<double>(element->FindElementValue("source_latitude"));
|
||||
source_latitude.reset(new FGPropertyValue(element->FindElementValue("source_latitude"),
|
||||
PropertyManager));
|
||||
if (element->FindElement("source_latitude")->HasAttribute("unit")) {
|
||||
if (element->FindElement("source_latitude")->GetAttributeValue("unit") == "DEG") {
|
||||
source_latitude_unit = 0.017453293;
|
||||
|
@ -105,7 +112,8 @@ FGWaypoint::FGWaypoint(FGFCS* fcs, Element* element)
|
|||
}
|
||||
|
||||
if (element->FindElement("source_longitude") ) {
|
||||
source_longitude = PropertyManager->CreatePropertyObject<double>(element->FindElementValue("source_longitude"));
|
||||
source_longitude.reset(new FGPropertyValue(element->FindElementValue("source_longitude"),
|
||||
PropertyManager));
|
||||
if (element->FindElement("source_longitude")->HasAttribute("unit")) {
|
||||
if (element->FindElement("source_longitude")->GetAttributeValue("unit") == "DEG") {
|
||||
source_longitude_unit = 0.017453293;
|
||||
|
@ -121,9 +129,7 @@ FGWaypoint::FGWaypoint(FGFCS* fcs, Element* element)
|
|||
if (element->FindElement("radius"))
|
||||
radius = element->FindElementValueAsNumberConvertTo("radius", "FT");
|
||||
else {
|
||||
FGLocation source(source_longitude * source_latitude_unit,
|
||||
source_latitude * source_longitude_unit, 1.0);
|
||||
radius = source.GetSeaLevelRadius(); // Radius of Earth in feet.
|
||||
radius = 20925646.32546; // Radius of Earth in feet.
|
||||
}
|
||||
|
||||
unit = element->GetAttributeValue("unit");
|
||||
|
@ -170,10 +176,11 @@ FGWaypoint::~FGWaypoint()
|
|||
|
||||
bool FGWaypoint::Run(void )
|
||||
{
|
||||
double target_latitude_rad = target_latitude * target_latitude_unit;
|
||||
double target_longitude_rad = target_longitude * target_longitude_unit;
|
||||
FGLocation source(source_longitude * source_latitude_unit,
|
||||
source_latitude * source_longitude_unit, radius);
|
||||
double source_latitude_rad = source_latitude->GetValue() * source_latitude_unit;
|
||||
double source_longitude_rad = source_longitude->GetValue() * source_longitude_unit;
|
||||
double target_latitude_rad = target_latitude->GetValue() * target_latitude_unit;
|
||||
double target_longitude_rad = target_longitude->GetValue() * target_longitude_unit;
|
||||
source.SetPosition(source_longitude_rad, source_latitude_rad, radius);
|
||||
|
||||
if (WaypointType == eHeading) { // Calculate Heading
|
||||
double heading_to_waypoint_rad = source.GetHeadingTo(target_longitude_rad,
|
||||
|
|
|
@ -37,7 +37,10 @@ SENTRY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "FGFCSComponent.h"
|
||||
#include "math/FGLocation.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -100,10 +103,11 @@ public:
|
|||
bool Run(void) override;
|
||||
|
||||
private:
|
||||
simgear::PropertyObject<double> target_latitude;
|
||||
simgear::PropertyObject<double> target_longitude;
|
||||
simgear::PropertyObject<double> source_latitude;
|
||||
simgear::PropertyObject<double> source_longitude;
|
||||
FGLocation source;
|
||||
std::unique_ptr<FGPropertyValue> target_latitude;
|
||||
std::unique_ptr<FGPropertyValue> target_longitude;
|
||||
std::unique_ptr<FGPropertyValue> source_latitude;
|
||||
std::unique_ptr<FGPropertyValue> source_longitude;
|
||||
double target_latitude_unit;
|
||||
double target_longitude_unit;
|
||||
double source_latitude_unit;
|
||||
|
|
|
@ -142,7 +142,7 @@ public:
|
|||
};
|
||||
|
||||
FGEngine(int engine_number, struct Inputs& input);
|
||||
virtual ~FGEngine();
|
||||
~FGEngine() override;
|
||||
|
||||
enum EngineType {etUnknown, etRocket, etPiston, etTurbine, etTurboprop, etElectric};
|
||||
|
||||
|
@ -241,7 +241,7 @@ protected:
|
|||
|
||||
std::vector <int> SourceTanks;
|
||||
|
||||
virtual bool Load(FGFDMExec *exec, Element *el);
|
||||
bool Load(FGFDMExec *exec, Element *el);
|
||||
void Debug(int from);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -4,24 +4,24 @@
|
|||
Author: Tony Peden
|
||||
Date started: 6/10/00
|
||||
|
||||
------------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) -------------
|
||||
--------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) --------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
the terms of the GNU Lesser 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 Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
Further information about the GNU Lesser General Public License can also be
|
||||
found on the world wide web at http://www.gnu.org.
|
||||
|
||||
|
||||
HISTORY
|
||||
|
@ -33,19 +33,14 @@ FUNCTIONAL DESCRIPTION
|
|||
--------------------------------------------------------------------------------
|
||||
|
||||
The purpose of this class is to provide storage for computed forces and
|
||||
encapsulate all the functionality associated with transforming those
|
||||
forces from their native coord system to the body system. This includes
|
||||
computing the moments due to the difference between the point of application
|
||||
and the cg.
|
||||
encapsulate all the functionality associated with transforming those forces from
|
||||
their native coord system to the body system. This includes computing the
|
||||
moments due to the difference between the point of application and the cg.
|
||||
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "FGForce.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "models/FGPropagate.h"
|
||||
#include "models/FGMassBalance.h"
|
||||
#include "models/FGAuxiliary.h"
|
||||
|
||||
|
@ -68,9 +63,9 @@ FGForce::FGForce(FGFDMExec *FDMExec) :
|
|||
vFb.InitMatrix();
|
||||
vM.InitMatrix();
|
||||
|
||||
mT.InitMatrix(1., 0., 0.,
|
||||
0., 1., 0.,
|
||||
0., 0., 1.);
|
||||
mT = { 1., 0., 0.,
|
||||
0., 1., 0.,
|
||||
0., 0., 1. };
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
|
|
@ -8,21 +8,21 @@
|
|||
------------- Copyright (C) 2000 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
the terms of the GNU Lesser 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 Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
Further information about the GNU Lesser General Public License can also be
|
||||
found on the world wide web at http://www.gnu.org.
|
||||
|
||||
FUNCTIONAL DESCRIPTION
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -199,9 +199,9 @@ FGRotor::FGRotor(FGFDMExec *exec, Element* rotor_element, int num)
|
|||
|
||||
// shaft representation - a rather simple transform,
|
||||
// but using a matrix is safer.
|
||||
TboToHsr.InitMatrix( 0.0, 0.0, 1.0,
|
||||
0.0, 1.0, 0.0,
|
||||
-1.0, 0.0, 0.0 );
|
||||
TboToHsr = { 0.0, 0.0, 1.0,
|
||||
0.0, 1.0, 0.0,
|
||||
-1.0, 0.0, 0.0 };
|
||||
HsrToTbo = TboToHsr.Transposed();
|
||||
|
||||
// smooth out jumps in hagl reported, otherwise the ground effect
|
||||
|
|
Loading…
Add table
Reference in a new issue