Sync'ed with JSBSim v1.1.11
- Output files are now written in the current directory instead of being written in the aircraft folder (issue GH#337) - A new exception TrimFailureException is now thrown when trim fails. This eases the detection of the trim failure (previously the exception message needed to be checked). - An exception is thrown when a latitude higher than 90 degrees is supplied to a <waypoint> control element (PR GH#536) - Fix the sign of the initial NED climb rate (property ic/gamma-deg) (PR #545) - JSBSim now checks malformed data in <table> elements. Anything different than numbers and spaces/tabs will be rejected. - Usage of <location> and <orientation> in engines is now officially dropped (PR #559, #561 and #563). These elements were deprecated long ago in favor of the corresponding elements <location> and <orientation> in thrusters. Therefore the code removed is no-op. - The computation of the initial rotation rates has been fixed (Issue GH#553). Previously, the rotation rates could be initialized with extremely high values when the vehicle was spawned over the Poles. And for a given set of initial conditions, the initial rotation rates could have different values depending on the initial latitude at which the vehicle was initialized. This now fixed. - The precision with which values are transmitted thru a socket can now be set via the attribute precision such as <output precision="8"> (PR GH#579) - Added 2 new methods to FGFDMExec: SetOutputPath and GetOutputPath to specify the path to which the output files will be written. - All JSBSim exceptions now inherit from JSBSim::BaseException. There still exist std::* exceptions thrown by JSBSim. Cleanup is still in progress. - JSBSim no longer calls exit() or abort(). Exceptions are thrown instead. This gives the calling application an opportunity to gracefully recover.
This commit is contained in:
parent
06063ed82a
commit
60ce826874
34 changed files with 424 additions and 364 deletions
|
@ -144,9 +144,14 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr)
|
|||
// this is to catch errors in binding member functions to the property tree.
|
||||
try {
|
||||
Allocate();
|
||||
} catch (const string& msg ) {
|
||||
cout << "Caught error: " << msg << endl;
|
||||
exit(1);
|
||||
}
|
||||
catch (const string& msg) {
|
||||
cerr << endl << "Caught error: " << msg << endl;
|
||||
throw;
|
||||
}
|
||||
catch (const BaseException& e) {
|
||||
cout << endl << "Caught error: " << e.what() << endl;
|
||||
throw;
|
||||
}
|
||||
|
||||
trim_status = false;
|
||||
|
@ -1093,8 +1098,10 @@ bool FGFDMExec::ReadChild(Element* el)
|
|||
if (location) {
|
||||
child->Loc = location->FindElementTripletConvertTo("IN");
|
||||
} else {
|
||||
cerr << endl << highint << fgred << " No location was found for this child object!" << reset << endl;
|
||||
exit(-1);
|
||||
const string s(" No location was found for this child object!");
|
||||
cerr << el->ReadFrom() << endl << highint << fgred
|
||||
<< s << reset << endl;
|
||||
throw BaseException(s);
|
||||
}
|
||||
|
||||
Element* orientation = el->FindElement("orient");
|
||||
|
@ -1165,7 +1172,7 @@ void FGFDMExec::DoTrim(int mode)
|
|||
trim.Report();
|
||||
|
||||
if (!success)
|
||||
throw("Trim Failed");
|
||||
throw TrimFailureException("Trim Failed");
|
||||
|
||||
trim_completed = 1;
|
||||
}
|
||||
|
|
|
@ -72,6 +72,11 @@ class FGPropulsion;
|
|||
class FGMassBalance;
|
||||
class FGTrim;
|
||||
|
||||
class TrimFailureException : public BaseException {
|
||||
public:
|
||||
TrimFailureException(const std::string& msg) : BaseException(msg) {}
|
||||
};
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
@ -194,7 +199,7 @@ class FGFDMExec : public FGJSBBase
|
|||
mated = true;
|
||||
internal = false;
|
||||
}
|
||||
|
||||
|
||||
void Run(void) {exec->Run();}
|
||||
void AssignState(FGPropagate* source_prop) {
|
||||
exec->GetPropagate()->SetVState(source_prop->GetVState());
|
||||
|
@ -283,44 +288,65 @@ public:
|
|||
@return true if successful*/
|
||||
bool LoadModel(const std::string& model, bool addModelToPath = true);
|
||||
|
||||
/** Loads a script
|
||||
/** Load a script
|
||||
@param Script The full path name and file name for the script to be loaded.
|
||||
@param deltaT The simulation integration step size, if given. If no value is supplied
|
||||
then 0.0 is used and the value is expected to be supplied in
|
||||
the script file itself.
|
||||
@param initfile The initialization file that will override the initialization file
|
||||
specified in the script file. If no file name is given on the command line,
|
||||
the file specified in the script will be used. If an initialization file
|
||||
is not given in either place, an error will result.
|
||||
@param deltaT The simulation integration step size, if given. If no value
|
||||
is supplied then 0.0 is used and the value is expected to be
|
||||
supplied in the script file itself.
|
||||
@param initfile The initialization file that will override the
|
||||
initialization file specified in the script file. If no
|
||||
file name is given on the command line, the file specified
|
||||
in the script will be used. If an initialization file is
|
||||
not given in either place, an error will result.
|
||||
@return true if successfully loads; false otherwise. */
|
||||
bool LoadScript(const SGPath& Script, double deltaT=0.0,
|
||||
const SGPath& initfile=SGPath());
|
||||
|
||||
/** Sets the path to the engine config file directories.
|
||||
@param path path to the directory under which engine config
|
||||
files are kept, for instance "engine" */
|
||||
/** Set the path to the engine config file directories.
|
||||
Relative paths are taken from the root directory.
|
||||
@param path path to the directory under which engine config files are
|
||||
kept, for instance "engine".
|
||||
@see SetRootDir
|
||||
@see GetEnginePath */
|
||||
bool SetEnginePath(const SGPath& path) {
|
||||
EnginePath = GetFullPath(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Sets the path to the aircraft config file directories.
|
||||
@param path path to the aircraft directory. For instance:
|
||||
"aircraft". Under aircraft, then, would be directories for various
|
||||
modeled aircraft such as C172/, x15/, etc. */
|
||||
/** Set the path to the aircraft config file directories.
|
||||
Under this path, then, would be directories for various modeled aircraft
|
||||
such as C172/, x15/, etc.
|
||||
Relative paths are taken from the root directory.
|
||||
@param path path to the aircraft directory, for instance "aircraft".
|
||||
@see SetRootDir
|
||||
@see GetAircraftPath */
|
||||
bool SetAircraftPath(const SGPath& path) {
|
||||
AircraftPath = GetFullPath(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Sets the path to the systems config file directories.
|
||||
@param path path to the directory under which systems config
|
||||
files are kept, for instance "systems" */
|
||||
|
||||
/** Set the path to the systems config file directories.
|
||||
Relative paths are taken from the root directory.
|
||||
@param path path to the directory under which systems config files are
|
||||
kept, for instance "systems"
|
||||
@see SetRootDir
|
||||
@see GetSystemsPath */
|
||||
bool SetSystemsPath(const SGPath& path) {
|
||||
SystemsPath = GetFullPath(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Set the directory where the output files will be written.
|
||||
Relative paths are taken from the root directory.
|
||||
@param path path to the directory under which the output files will be
|
||||
written.
|
||||
@see SetRootDir
|
||||
@see GetOutputPath */
|
||||
bool SetOutputPath(const SGPath& path) {
|
||||
OutputPath = GetFullPath(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @name Top-level executive State and Model retrieval mechanism
|
||||
///@{
|
||||
/// Returns the FGAtmosphere pointer.
|
||||
|
@ -364,13 +390,15 @@ public:
|
|||
///@}
|
||||
|
||||
/// Retrieves the engine path.
|
||||
const SGPath& GetEnginePath(void) {return EnginePath;}
|
||||
const SGPath& GetEnginePath(void) { return EnginePath; }
|
||||
/// Retrieves the aircraft path.
|
||||
const SGPath& GetAircraftPath(void) {return AircraftPath;}
|
||||
const SGPath& GetAircraftPath(void) { return AircraftPath; }
|
||||
/// Retrieves the systems path.
|
||||
const SGPath& GetSystemsPath(void) {return SystemsPath;}
|
||||
const SGPath& GetSystemsPath(void) { return SystemsPath; }
|
||||
/// Retrieves the full aircraft path name.
|
||||
const SGPath& GetFullAircraftPath(void) {return FullAircraftPath;}
|
||||
const SGPath& GetFullAircraftPath(void) { return FullAircraftPath; }
|
||||
/// Retrieves the path to the output files.
|
||||
const SGPath& GetOutputPath(void) { return OutputPath; }
|
||||
|
||||
/** Retrieves the value of a property.
|
||||
@param property the name of the property
|
||||
|
@ -535,13 +563,23 @@ public:
|
|||
@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.
|
||||
@param rootDir the string containing the root directory. */
|
||||
/** Set the root directory that is used to obtain absolute paths from
|
||||
relative paths.
|
||||
Aircraft, engine, systems and output paths are not updated by this
|
||||
method. You must call each methods (SetAircraftPath(), SetEnginePath(),
|
||||
etc.) individually if you need to update these paths as well.
|
||||
@param rootDir the path to the root directory.
|
||||
@see GetRootDir
|
||||
@see SetAircraftPath
|
||||
@see SetEnginePath
|
||||
@see SetSystemsPath
|
||||
@see SetOutputPath
|
||||
*/
|
||||
void SetRootDir(const SGPath& rootDir) {RootDir = rootDir;}
|
||||
|
||||
/** Retrieves the Root Directory.
|
||||
@return the string representing the root (base) JSBSim directory. */
|
||||
/** Retrieve the Root Directory.
|
||||
@return the path to the root (base) JSBSim directory.
|
||||
@see SetRootDir */
|
||||
const SGPath& GetRootDir(void) const {return RootDir;}
|
||||
|
||||
/** Increments the simulation time if not in Holding mode. The Frame counter
|
||||
|
@ -600,6 +638,7 @@ private:
|
|||
SGPath FullAircraftPath;
|
||||
SGPath EnginePath;
|
||||
SGPath SystemsPath;
|
||||
SGPath OutputPath;
|
||||
std::string CFGVersion;
|
||||
std::string Release;
|
||||
SGPath RootDir;
|
||||
|
|
|
@ -42,6 +42,7 @@ INCLUDES
|
|||
#include <queue>
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "input_output/string_utilities.h"
|
||||
|
||||
|
@ -55,6 +56,11 @@ FORWARD DECLARATIONS
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
class BaseException : public std::runtime_error {
|
||||
public:
|
||||
BaseException(const std::string& msg) : std::runtime_error(msg) {}
|
||||
};
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
@ -263,7 +269,7 @@ public:
|
|||
static double PitotTotalPressure(double mach, double p);
|
||||
|
||||
/** Compute the Mach number from the differential pressure (qc) and the
|
||||
* static pressure. Based on the formulas in the US Air Force Aircraft
|
||||
* static pressure. Based on the formulas in the US Air Force Aircraft
|
||||
* Performance Flight Testing Manual (AFFTC-TIH-99-01).
|
||||
* @param qc The differential/impact pressure
|
||||
* @param p Pressure in psf
|
||||
|
@ -271,7 +277,7 @@ public:
|
|||
static double MachFromImpactPressure(double qc, double p);
|
||||
|
||||
/** Calculate the calibrated airspeed from the Mach number. Based on the
|
||||
* formulas in the US Air Force Aircraft Performance Flight Testing
|
||||
* formulas in the US Air Force Aircraft Performance Flight Testing
|
||||
* Manual (AFFTC-TIH-99-01).
|
||||
* @param mach The Mach number
|
||||
* @param p Pressure in psf
|
||||
|
@ -280,7 +286,7 @@ public:
|
|||
static double VcalibratedFromMach(double mach, double p);
|
||||
|
||||
/** Calculate the Mach number from the calibrated airspeed.Based on the
|
||||
* formulas in the US Air Force Aircraft Performance Flight Testing
|
||||
* formulas in the US Air Force Aircraft Performance Flight Testing
|
||||
* Manual (AFFTC-TIH-99-01).
|
||||
* @param vcas The calibrated airspeed (CAS) in ft/s
|
||||
* @param p Pressure in psf
|
||||
|
@ -321,13 +327,13 @@ public:
|
|||
static bool EqualToRoundoff(double a, float b) {
|
||||
return EqualToRoundoff((float)a, b);
|
||||
}
|
||||
|
||||
|
||||
/** Constrain a value between a minimum and a maximum value.
|
||||
*/
|
||||
static constexpr double Constrain(double min, double value, double max) {
|
||||
return value<min?(min):(value>max?(max):(value));
|
||||
}
|
||||
|
||||
|
||||
static constexpr double sign(double num) {return num>=0.0?1.0:-1.0;}
|
||||
|
||||
static double GaussianRandomNumber(void);
|
||||
|
|
|
@ -808,7 +808,7 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt)
|
|||
}
|
||||
geodAlt = z/sinGeodLat-N*(1-e2);
|
||||
}
|
||||
|
||||
|
||||
double longitude = position.GetLongitude();
|
||||
position.SetPositionGeodetic(longitude, geodLatitude, geodAlt);
|
||||
}
|
||||
|
@ -1013,13 +1013,17 @@ bool FGInitialCondition::Load(const SGPath& rstfile, bool useStoredPath)
|
|||
|
||||
// Make sure that the document is valid
|
||||
if (!document) {
|
||||
cerr << "File: " << init_file_name << " could not be read." << endl;
|
||||
exit(-1);
|
||||
stringstream s;
|
||||
s << "File: " << init_file_name << " could not be read.";
|
||||
cerr << s.str() << endl;
|
||||
throw BaseException(s.str());
|
||||
}
|
||||
|
||||
if (document->GetName() != string("initialize")) {
|
||||
cerr << "File: " << init_file_name << " is not a reset file." << endl;
|
||||
exit(-1);
|
||||
stringstream s;
|
||||
s << "File: " << init_file_name << " is not a reset file.";
|
||||
cerr << s.str() << endl;
|
||||
throw BaseException(s.str());
|
||||
}
|
||||
|
||||
double version = HUGE_VAL;
|
||||
|
@ -1031,8 +1035,9 @@ bool FGInitialCondition::Load(const SGPath& rstfile, bool useStoredPath)
|
|||
if (version == HUGE_VAL) {
|
||||
result = Load_v1(document); // Default to the old version
|
||||
} else if (version >= 3.0) {
|
||||
cerr << "Only initialization file formats 1 and 2 are currently supported" << endl;
|
||||
exit (-1);
|
||||
const string s("Only initialization file formats 1 and 2 are currently supported");
|
||||
cerr << document->ReadFrom() << endl << s << endl;
|
||||
throw BaseException(s);
|
||||
} else if (version >= 2.0) {
|
||||
result = Load_v2(document);
|
||||
} else if (version >= 1.0) {
|
||||
|
@ -1182,15 +1187,7 @@ bool FGInitialCondition::Load_v1(Element* document)
|
|||
if (document->FindElement("trim"))
|
||||
SetTrimRequest(document->FindElementValue("trim"));
|
||||
|
||||
// Refer to Stevens and Lewis, 1.5-14a, pg. 49.
|
||||
// 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 = {radInv*vUVW_NED(eEast),
|
||||
-radInv*vUVW_NED(eNorth),
|
||||
-radInv*vUVW_NED(eEast)*tan(position.GetLatitude())};
|
||||
|
||||
vPQR_body = Tl2b * vOmegaLocal;
|
||||
vPQR_body.InitMatrix();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -1403,19 +1400,12 @@ bool FGInitialCondition::Load_v2(Element* document)
|
|||
// - Body
|
||||
|
||||
Element* attrate_el = document->FindElement("attitude_rate");
|
||||
const FGMatrix33& Tl2b = orientation.GetT();
|
||||
|
||||
// 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 = { radInv*vUVW_NED(eEast),
|
||||
-radInv*vUVW_NED(eNorth),
|
||||
-radInv*vUVW_NED(eEast)*tan(position.GetLatitude())};
|
||||
|
||||
if (attrate_el) {
|
||||
|
||||
string frame = attrate_el->GetAttributeValue("frame");
|
||||
frame = to_lower(frame);
|
||||
const FGMatrix33& Tl2b = orientation.GetT();
|
||||
FGColumnVector3 vAttRate = attrate_el->FindElementTripletConvertTo("RAD/SEC");
|
||||
|
||||
if (frame == "eci") {
|
||||
|
@ -1424,6 +1414,12 @@ bool FGInitialCondition::Load_v2(Element* document)
|
|||
} else if (frame == "ecef") {
|
||||
vPQR_body = Tl2b * position.GetTec2l() * vAttRate;
|
||||
} else if (frame == "local") {
|
||||
// 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 = {radInv*vUVW_NED(eEast),
|
||||
-radInv*vUVW_NED(eNorth),
|
||||
-radInv*vUVW_NED(eEast)*tan(position.GetLatitude())};
|
||||
vPQR_body = Tl2b * (vAttRate + vOmegaLocal);
|
||||
} else if (frame == "body") {
|
||||
vPQR_body = vAttRate;
|
||||
|
@ -1434,11 +1430,11 @@ bool FGInitialCondition::Load_v2(Element* document)
|
|||
result = false;
|
||||
|
||||
} else if (frame.empty()) {
|
||||
vPQR_body = Tl2b * vOmegaLocal;
|
||||
vPQR_body.InitMatrix();
|
||||
}
|
||||
|
||||
} else { // Body frame attitude rate assumed 0 relative to local.
|
||||
vPQR_body = Tl2b * vOmegaLocal;
|
||||
vPQR_body.InitMatrix();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -519,7 +519,7 @@ public:
|
|||
{
|
||||
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||
return _vt_NED(eW);
|
||||
return -_vt_NED(eW);
|
||||
}
|
||||
|
||||
/** Gets the initial body velocity
|
||||
|
|
|
@ -214,7 +214,7 @@ void FGOutputFG::SocketDataFill(FGNetFDM* net)
|
|||
net->stall_warning = 0.0; // 0.0 - 1.0 indicating the amount of stall
|
||||
net->slip_deg = (float)(Auxiliary->Getbeta(inDegrees)); // slip ball deflection, deg
|
||||
|
||||
net->num_engines = min((unsigned) FGNetFDM::FG_MAX_ENGINES, Propulsion->GetNumEngines()); // Number of valid engines
|
||||
net->num_engines = min(FGNetFDM::FG_MAX_ENGINES,Propulsion->GetNumEngines()); // Number of valid engines
|
||||
|
||||
for (i=0; i<net->num_engines; i++) {
|
||||
FGEngine* engine = Propulsion->GetEngine(i);
|
||||
|
@ -254,7 +254,7 @@ void FGOutputFG::SocketDataFill(FGNetFDM* net)
|
|||
}
|
||||
}
|
||||
|
||||
net->num_tanks = min((unsigned) FGNetFDM::FG_MAX_TANKS, Propulsion->GetNumTanks()); // Max number of fuel tanks
|
||||
net->num_tanks = min(FGNetFDM::FG_MAX_TANKS, Propulsion->GetNumTanks()); // Max number of fuel tanks
|
||||
|
||||
for (i=0; i<net->num_tanks; i++) {
|
||||
net->fuel_quantity[i] = (float)(((FGTank *)Propulsion->GetTank(i))->GetContents());
|
||||
|
|
|
@ -100,7 +100,7 @@ public:
|
|||
the next call to SetStartNewOutput().
|
||||
@param name new name */
|
||||
void SetOutputName(const std::string& fname) override {
|
||||
Name = (FDMExec->GetRootDir()/fname).utf8Str();
|
||||
Name = (FDMExec->GetOutputPath()/fname).utf8Str();
|
||||
runID_postfix = -1;
|
||||
Filename = SGPath();
|
||||
}
|
||||
|
|
|
@ -121,6 +121,12 @@ bool FGOutputSocket::Load(Element* el)
|
|||
el->GetAttributeValue("protocol") + "/" +
|
||||
el->GetAttributeValue("port"));
|
||||
|
||||
// Check if output precision for doubles has been specified, default to 7 if not
|
||||
if(el->HasAttribute("precision"))
|
||||
precision = (int)el->GetAttributeValueAsNumber("precision");
|
||||
else
|
||||
precision = 7;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -130,7 +136,7 @@ bool FGOutputSocket::InitModel(void)
|
|||
{
|
||||
if (FGOutputType::InitModel()) {
|
||||
delete socket;
|
||||
socket = new FGfdmSocket(SockName, SockPort, SockProtocol);
|
||||
socket = new FGfdmSocket(SockName, SockPort, SockProtocol, precision);
|
||||
|
||||
if (socket == 0) return false;
|
||||
if (!socket->GetConnectStatus()) return false;
|
||||
|
|
|
@ -108,6 +108,7 @@ protected:
|
|||
unsigned int SockPort;
|
||||
FGfdmSocket::ProtocolType SockProtocol;
|
||||
FGfdmSocket* socket;
|
||||
int precision;
|
||||
};
|
||||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "FGPropertyManager.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -110,13 +111,6 @@ bool FGPropertyNode::HasNode (const string &path)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGPropertyNode::GetName( void ) const
|
||||
{
|
||||
return getNameString();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGPropertyNode::GetPrintableName( void ) const
|
||||
{
|
||||
string temp_string(getNameString());
|
||||
|
@ -301,7 +295,7 @@ void FGPropertyNode::SetWritable (const string &name, bool state )
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPropertyManager::Untie (const string &name)
|
||||
void FGPropertyManager::Untie(const string &name)
|
||||
{
|
||||
SGPropertyNode* property = root->getNode(name.c_str());
|
||||
if (!property) {
|
||||
|
@ -309,8 +303,18 @@ void FGPropertyManager::Untie (const string &name)
|
|||
return;
|
||||
}
|
||||
|
||||
vector <SGPropertyNode_ptr>::iterator it;
|
||||
for (it = tied_properties.begin(); it != tied_properties.end(); ++it) {
|
||||
Untie(property);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPropertyManager::Untie(SGPropertyNode *property)
|
||||
{
|
||||
const string& name = property->getNameString();
|
||||
|
||||
assert(property->isTied());
|
||||
|
||||
for (auto it = tied_properties.begin(); it != tied_properties.end(); ++it) {
|
||||
if (*it == property) {
|
||||
property->untie();
|
||||
tied_properties.erase(it);
|
||||
|
|
|
@ -97,7 +97,7 @@ class FGPropertyNode : public SGPropertyNode
|
|||
/**
|
||||
* Get the name of a node
|
||||
*/
|
||||
std::string GetName( void ) const;
|
||||
const std::string& GetName( void ) const { return getNameString(); }
|
||||
|
||||
/**
|
||||
* Get the name of a node without underscores, etc.
|
||||
|
@ -413,9 +413,21 @@ class FGPropertyManager
|
|||
*
|
||||
* Classes should use this function to release control of any
|
||||
* properties they are managing.
|
||||
*
|
||||
* @param name The property name to untie (full path).
|
||||
*/
|
||||
void Untie (const std::string &name);
|
||||
|
||||
/**
|
||||
* Untie a property from an external data source.
|
||||
*
|
||||
* Classes should use this function to release control of any
|
||||
* properties they are managing.
|
||||
*
|
||||
* @param property A pointer to the property to untie.
|
||||
*/
|
||||
void Untie (SGPropertyNode* property);
|
||||
|
||||
/**
|
||||
* Unbind all properties bound by this manager to an external data source.
|
||||
*
|
||||
|
|
|
@ -150,7 +150,7 @@ bool FGScript::LoadScript(const SGPath& script, double default_dT,
|
|||
|
||||
// Make sure that the desired time is reached and executed.
|
||||
EndTime += 0.99*FDMExec->GetDeltaT();
|
||||
|
||||
|
||||
// read aircraft and initialization files
|
||||
|
||||
element = document->FindElement("use");
|
||||
|
@ -193,7 +193,7 @@ bool FGScript::LoadScript(const SGPath& script, double default_dT,
|
|||
while (element) {
|
||||
if (!FDMExec->GetInput()->Load(element))
|
||||
return false;
|
||||
|
||||
|
||||
element = document->FindNextElement("input");
|
||||
}
|
||||
|
||||
|
@ -206,7 +206,7 @@ bool FGScript::LoadScript(const SGPath& script, double default_dT,
|
|||
while (element) {
|
||||
if (!FDMExec->GetOutput()->Load(element, scriptDir))
|
||||
return false;
|
||||
|
||||
|
||||
element = document->FindNextElement("output");
|
||||
}
|
||||
|
||||
|
@ -295,7 +295,7 @@ bool FGScript::LoadScript(const SGPath& script, double default_dT,
|
|||
}
|
||||
else
|
||||
newEvent->NotifyProperties.push_back(new FGPropertyValue(notifyPropertyName, PropertyManager));
|
||||
|
||||
|
||||
string caption_attribute = notify_property_element->GetAttributeValue("caption");
|
||||
if (caption_attribute.empty()) {
|
||||
newEvent->DisplayString.push_back(notifyPropertyName);
|
||||
|
@ -496,7 +496,7 @@ bool FGScript::RunScript(void)
|
|||
} else {
|
||||
cout << endl << underon
|
||||
<< highint << thisEvent.Name << normint << underoff
|
||||
<< " (Event " << event_ctr << ")"
|
||||
<< " (Event " << event_ctr << ")"
|
||||
<< " executed at time: " << highint << currentTime << normint
|
||||
<< endl;
|
||||
}
|
||||
|
@ -573,7 +573,7 @@ void FGScript::Debug(int from)
|
|||
<< " = " << node->getDoubleValue()
|
||||
<< endl;
|
||||
}
|
||||
|
||||
|
||||
if (LocalProperties.empty()) cout << endl;
|
||||
|
||||
for (unsigned i=0; i<Events.size(); i++) {
|
||||
|
@ -597,38 +597,38 @@ void FGScript::Debug(int from)
|
|||
for (unsigned j=0; j<Events[i].SetValue.size(); j++) {
|
||||
if (Events[i].SetValue[j] == 0.0 && Events[i].Functions[j] != 0L) {
|
||||
if (Events[i].SetParam[j] == 0) {
|
||||
if (Events[i].SetParamName[j].size() == 0) {
|
||||
cerr << fgred << highint << endl
|
||||
<< " An attempt has been made to access a non-existent property" << endl
|
||||
<< " in this event. Please check the property names used, spelling, etc."
|
||||
<< reset << endl;
|
||||
exit(-1);
|
||||
if (Events[i].SetParamName[j].empty()) {
|
||||
stringstream s;
|
||||
s << " An attempt has been made to access a non-existent property" << endl
|
||||
<< " in this event. Please check the property names used, spelling, etc.";
|
||||
cerr << fgred << highint << endl << s.str() << reset << endl;
|
||||
throw BaseException(s.str());
|
||||
} else {
|
||||
cout << endl << " set " << Events[i].SetParamName[j]
|
||||
<< " to function value (Late Bound)";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cout << endl << " set "
|
||||
<< Events[i].SetParam[j]->GetRelativeName("/fdm/jsbsim/")
|
||||
<< " to function value";
|
||||
cout << endl << " set "
|
||||
<< Events[i].SetParam[j]->GetRelativeName("/fdm/jsbsim/")
|
||||
<< " to function value";
|
||||
}
|
||||
} else {
|
||||
if (Events[i].SetParam[j] == 0) {
|
||||
if (Events[i].SetParamName[j].size() == 0) {
|
||||
cerr << fgred << highint << endl
|
||||
<< " An attempt has been made to access a non-existent property" << endl
|
||||
<< " in this event. Please check the property names used, spelling, etc."
|
||||
<< reset << endl;
|
||||
exit(-1);
|
||||
if (Events[i].SetParamName[j].empty()) {
|
||||
stringstream s;
|
||||
s << " An attempt has been made to access a non-existent property" << endl
|
||||
<< " in this event. Please check the property names used, spelling, etc.";
|
||||
cerr << fgred << highint << endl << s.str() << reset << endl;
|
||||
throw BaseException(s.str());
|
||||
} else {
|
||||
cout << endl << " set " << Events[i].SetParamName[j]
|
||||
<< " to function value (Late Bound)";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cout << endl << " set "
|
||||
<< Events[i].SetParam[j]->GetRelativeName("/fdm/jsbsim/")
|
||||
<< " to " << Events[i].SetValue[j];
|
||||
}
|
||||
cout << endl << " set "
|
||||
<< Events[i].SetParam[j]->GetRelativeName("/fdm/jsbsim/")
|
||||
<< " to " << Events[i].SetValue[j];
|
||||
}
|
||||
}
|
||||
|
||||
switch (Events[i].Type[j]) {
|
||||
|
|
|
@ -81,12 +81,13 @@ static bool LoadWinSockDLL(int debug_lvl)
|
|||
}
|
||||
#endif
|
||||
|
||||
FGfdmSocket::FGfdmSocket(const string& address, int port, int protocol)
|
||||
FGfdmSocket::FGfdmSocket(const string& address, int port, int protocol, int precision)
|
||||
{
|
||||
sckt = sckt_in = 0;
|
||||
Protocol = (ProtocolType)protocol;
|
||||
connected = false;
|
||||
struct addrinfo *addr = nullptr;
|
||||
this->precision = precision;
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
if (!LoadWinSockDLL(debug_lvl)) return;
|
||||
|
@ -150,12 +151,13 @@ FGfdmSocket::FGfdmSocket(const string& address, int port, int protocol)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// assumes TCP or UDP socket on localhost, for inbound datagrams
|
||||
FGfdmSocket::FGfdmSocket(int port, int protocol)
|
||||
FGfdmSocket::FGfdmSocket(int port, int protocol, int precision)
|
||||
{
|
||||
sckt = -1;
|
||||
connected = false;
|
||||
Protocol = (ProtocolType)protocol;
|
||||
string ProtocolName;
|
||||
this->precision = precision;
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
if (!LoadWinSockDLL(debug_lvl)) return;
|
||||
|
@ -338,7 +340,7 @@ void FGfdmSocket::Append(const char* item)
|
|||
void FGfdmSocket::Append(double item)
|
||||
{
|
||||
if (buffer.tellp() > 0) buffer << ',';
|
||||
buffer << std::setw(12) << std::setprecision(7) << item;
|
||||
buffer << std::setw(12) << std::setprecision(precision) << item;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -70,10 +70,8 @@ CLASS DECLARATION
|
|||
class FGfdmSocket : public FGJSBBase
|
||||
{
|
||||
public:
|
||||
FGfdmSocket(const std::string& address, int port)
|
||||
: FGfdmSocket(address, port, ptTCP) {}
|
||||
FGfdmSocket(const std::string&, int, int);
|
||||
FGfdmSocket(int, int);
|
||||
FGfdmSocket(const std::string& address, int port, int protocol, int precision = 7);
|
||||
FGfdmSocket(int port, int protocol, int precision = 7);
|
||||
~FGfdmSocket();
|
||||
void Send(void);
|
||||
void Send(const char *data, int length);
|
||||
|
@ -104,6 +102,7 @@ private:
|
|||
struct sockaddr_in scktName;
|
||||
struct hostent *host;
|
||||
std::ostringstream buffer;
|
||||
int precision;
|
||||
bool connected;
|
||||
void Debug(int from);
|
||||
};
|
||||
|
|
|
@ -124,7 +124,7 @@ FGCondition::FGCondition(const string& test, FGPropertyManager* PropertyManager,
|
|||
|
||||
Comparison = mComparison[conditional];
|
||||
if (Comparison == ecUndef) {
|
||||
std::invalid_argument("JSBSim FGCondition: Comparison operator: \""+conditional
|
||||
throw std::invalid_argument("JSBSim FGCondition: Comparison operator: \""+conditional
|
||||
+"\" does not exist. Please check the conditional.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -890,10 +890,8 @@ void FGFunction::Load(Element* el, FGPropertyValue* var, FGFDMExec* fdmex,
|
|||
|
||||
FGFunction::~FGFunction()
|
||||
{
|
||||
if (pNode && pNode->isTied()) {
|
||||
string pName = pNode->GetFullyQualifiedName();
|
||||
PropertyManager->Untie(pName);
|
||||
}
|
||||
if (pNode && pNode->isTied())
|
||||
PropertyManager->Untie(pNode);
|
||||
|
||||
Debug(1);
|
||||
}
|
||||
|
|
|
@ -425,19 +425,16 @@ FGMatrix33 FGMatrix33::operator/(const double scalar) const
|
|||
{
|
||||
FGMatrix33 Quot;
|
||||
|
||||
if ( scalar != 0 ) {
|
||||
double tmp = 1.0/scalar;
|
||||
Quot.data[0] = data[0] * tmp;
|
||||
Quot.data[3] = data[3] * tmp;
|
||||
Quot.data[6] = data[6] * tmp;
|
||||
Quot.data[1] = data[1] * tmp;
|
||||
Quot.data[4] = data[4] * tmp;
|
||||
Quot.data[7] = data[7] * tmp;
|
||||
Quot.data[2] = data[2] * tmp;
|
||||
Quot.data[5] = data[5] * tmp;
|
||||
Quot.data[8] = data[8] * tmp;
|
||||
} else
|
||||
throw MatrixException{"Attempt to divide by zero in method FGMatrix33::operator/(const double scalar)"};
|
||||
double tmp = 1.0/scalar;
|
||||
Quot.data[0] = data[0] * tmp;
|
||||
Quot.data[3] = data[3] * tmp;
|
||||
Quot.data[6] = data[6] * tmp;
|
||||
Quot.data[1] = data[1] * tmp;
|
||||
Quot.data[4] = data[4] * tmp;
|
||||
Quot.data[7] = data[7] * tmp;
|
||||
Quot.data[2] = data[2] * tmp;
|
||||
Quot.data[5] = data[5] * tmp;
|
||||
Quot.data[8] = data[8] * tmp;
|
||||
|
||||
return Quot;
|
||||
}
|
||||
|
@ -446,19 +443,16 @@ FGMatrix33 FGMatrix33::operator/(const double scalar) const
|
|||
|
||||
FGMatrix33& FGMatrix33::operator/=(const double scalar)
|
||||
{
|
||||
if ( scalar != 0 ) {
|
||||
double tmp = 1.0/scalar;
|
||||
data[0] *= tmp;
|
||||
data[3] *= tmp;
|
||||
data[6] *= tmp;
|
||||
data[1] *= tmp;
|
||||
data[4] *= tmp;
|
||||
data[7] *= tmp;
|
||||
data[2] *= tmp;
|
||||
data[5] *= tmp;
|
||||
data[8] *= tmp;
|
||||
} else
|
||||
throw MatrixException{"Attempt to divide by zero in method FGMatrix33::operator/=(const double scalar)"};
|
||||
double tmp = 1.0/scalar;
|
||||
data[0] *= tmp;
|
||||
data[3] *= tmp;
|
||||
data[6] *= tmp;
|
||||
data[1] *= tmp;
|
||||
data[4] *= tmp;
|
||||
data[7] *= tmp;
|
||||
data[2] *= tmp;
|
||||
data[5] *= tmp;
|
||||
data[8] *= tmp;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -42,8 +42,8 @@ INCLUDES
|
|||
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "FGJSBBase.h"
|
||||
#include "FGColumnVector3.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -54,23 +54,6 @@ namespace JSBSim {
|
|||
|
||||
class FGQuaternion;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/** Exception convenience class.
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DECLARATION: MatrixException
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class MatrixException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
MatrixException(const std::string& msg) : std::runtime_error{msg} { }
|
||||
};
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
|
|
@ -158,7 +158,7 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
|
|||
std::cerr << el->ReadFrom()
|
||||
<<" An unknown table type attribute is listed: " << call_type
|
||||
<< endl;
|
||||
throw TableException("Unknown table type.");
|
||||
throw BaseException("Unknown table type.");
|
||||
}
|
||||
|
||||
// Determine and store the lookup properties for this table unless this table
|
||||
|
@ -199,7 +199,7 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
|
|||
} else if (lookup_axis == string("table")) {
|
||||
lookupProperty[eTable] = node;
|
||||
} else if (!lookup_axis.empty()) {
|
||||
throw TableException("Lookup table axis specification not understood: " + lookup_axis);
|
||||
throw BaseException("Lookup table axis specification not understood: " + lookup_axis);
|
||||
} else { // assumed single dimension table; row lookup
|
||||
lookupProperty[eRow] = node;
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
|
|||
std::cerr << el->ReadFrom()
|
||||
<< "No independentVars found, and table is not marked as internal,"
|
||||
<< " nor is it a 3D table." << endl;
|
||||
throw TableException("No independent variable found for table.");
|
||||
throw BaseException("No independent variable found for table.");
|
||||
}
|
||||
}
|
||||
// end lookup property code
|
||||
|
@ -245,8 +245,16 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
|
|||
}
|
||||
|
||||
for (i=0; i<tableData->GetNumDataLines(); i++) {
|
||||
buf << tableData->GetDataLine(i) << string(" ");
|
||||
string line = tableData->GetDataLine(i);
|
||||
if (line.find_first_not_of("0123456789.-+eE \t\n") != string::npos) {
|
||||
cerr << " In file " << tableData->GetFileName() << endl
|
||||
<< " Illegal character found in line "
|
||||
<< tableData->GetLineNumber() + i + 1 << ": " << endl << line << endl;
|
||||
throw BaseException("Illegal character");
|
||||
}
|
||||
buf << line << " ";
|
||||
}
|
||||
|
||||
switch (dimension) {
|
||||
case 1:
|
||||
nRows = tableData->GetNumDataLines();
|
||||
|
@ -267,12 +275,12 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
|
|||
if (nCols < 2) {
|
||||
std::cerr << tableData->ReadFrom()
|
||||
<< "Not enough columns in table data" << endl;
|
||||
throw TableException("Not enough columns in table data.");
|
||||
throw BaseException("Not enough columns in table data.");
|
||||
}
|
||||
} else {
|
||||
std::cerr << tableData->ReadFrom()
|
||||
<< "Not enough rows in table data" << endl;
|
||||
throw TableException("Not enough rows in the table data.");
|
||||
throw BaseException("Not enough rows in the table data.");
|
||||
}
|
||||
|
||||
Type = tt2D;
|
||||
|
@ -330,7 +338,7 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
|
|||
if (nameel != 0) std::cerr << " of table in " << nameel->GetAttributeValue("name");
|
||||
std::cerr << ":" << reset << endl
|
||||
<< " " << Data[b][1] << "<=" << Data[b-1][1] << endl;
|
||||
throw TableException("Breakpoint lookup is not monotonically increasing");
|
||||
throw BaseException("Breakpoint lookup is not monotonically increasing");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -346,7 +354,7 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
|
|||
if (nameel != 0) std::cerr << " of table in " << nameel->GetAttributeValue("name");
|
||||
std::cerr << ":" << reset << endl
|
||||
<< " " << Data[0][c] << "<=" << Data[0][c-1] << endl;
|
||||
throw TableException("FGTable: column lookup is not monotonically increasing");
|
||||
throw BaseException("FGTable: column lookup is not monotonically increasing");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -362,7 +370,7 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
|
|||
if (nameel != 0) std::cerr << " of table in " << nameel->GetAttributeValue("name");
|
||||
std::cerr << ":" << reset << endl
|
||||
<< " " << Data[r][0] << "<=" << Data[r-1][0] << endl;
|
||||
throw TableException("FGTable: row lookup is not monotonically increasing");
|
||||
throw BaseException("FGTable: row lookup is not monotonically increasing");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -393,10 +401,10 @@ FGTable::~FGTable()
|
|||
// Untie the bound property so that it makes no further reference to this
|
||||
// instance of FGTable after the destruction is completed.
|
||||
if (!Name.empty() && !internal) {
|
||||
string tmp = mkPropertyName(nullptr, "");
|
||||
string tmp = PropertyManager->mkPropertyName(Name, false);
|
||||
FGPropertyNode* node = PropertyManager->GetNode(tmp);
|
||||
if (node->isTied())
|
||||
PropertyManager->Untie(tmp);
|
||||
if (node && node->isTied())
|
||||
PropertyManager->Untie(node);
|
||||
}
|
||||
|
||||
if (nTables > 0) {
|
||||
|
@ -653,33 +661,26 @@ void FGTable::Print(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGTable::mkPropertyName(Element* el, const std::string& Prefix)
|
||||
{
|
||||
if (!Prefix.empty()) {
|
||||
if (is_number(Prefix)) {
|
||||
if (Name.find("#") != string::npos) { // if "#" is found
|
||||
Name = replace(Name, "#", Prefix);
|
||||
} else {
|
||||
cerr << el->ReadFrom()
|
||||
<< "Malformed table name with number: " << Prefix
|
||||
<< " and property name: " << Name
|
||||
<< " but no \"#\" sign for substitution." << endl;
|
||||
}
|
||||
} else {
|
||||
Name = Prefix + "/" + Name;
|
||||
}
|
||||
}
|
||||
|
||||
return PropertyManager->mkPropertyName(Name, false);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGTable::bind(Element* el, const string& Prefix)
|
||||
{
|
||||
typedef double (FGTable::*PMF)(void) const;
|
||||
|
||||
if ( !Name.empty() && !internal) {
|
||||
string tmp = mkPropertyName(el, Prefix);
|
||||
if (!Prefix.empty()) {
|
||||
if (is_number(Prefix)) {
|
||||
if (Name.find("#") != string::npos) { // if "#" is found
|
||||
Name = replace(Name, "#", Prefix);
|
||||
} else {
|
||||
cerr << el->ReadFrom()
|
||||
<< "Malformed table name with number: " << Prefix
|
||||
<< " and property name: " << Name
|
||||
<< " but no \"#\" sign for substitution." << endl;
|
||||
}
|
||||
} else {
|
||||
Name = Prefix + "/" + Name;
|
||||
}
|
||||
}
|
||||
string tmp = PropertyManager->mkPropertyName(Name, false);
|
||||
|
||||
if (PropertyManager->HasNode(tmp)) {
|
||||
FGPropertyNode* _property = PropertyManager->GetNode(tmp);
|
||||
|
@ -689,7 +690,8 @@ void FGTable::bind(Element* el, const string& Prefix)
|
|||
throw("Failed to bind the property to an existing already tied node.");
|
||||
}
|
||||
}
|
||||
PropertyManager->Tie( tmp, this, (PMF)&FGTable::GetValue);
|
||||
|
||||
PropertyManager->Tie(tmp, this, (PMF)&FGTable::GetValue);
|
||||
}
|
||||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -226,19 +226,6 @@ combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio
|
|||
@author Jon S. Berndt
|
||||
*/
|
||||
|
||||
/** Exception convenience class.
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DECLARATION: TableException
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class TableException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
TableException(const std::string& msg) : std::runtime_error{msg} { }
|
||||
};
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
@ -317,8 +304,6 @@ private:
|
|||
FGPropertyManager* const PropertyManager;
|
||||
std::string Name;
|
||||
void bind(Element* el, const std::string& Prefix);
|
||||
|
||||
std::string mkPropertyName(Element* el, const std::string& Prefix);
|
||||
void Debug(int from);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -229,9 +229,13 @@ bool FGAerodynamics::Run(bool Holding)
|
|||
vForcesAtCG = Ts2b*vFnativeAtCG;
|
||||
break;
|
||||
default:
|
||||
cerr << endl << " A proper axis type has NOT been selected. Check "
|
||||
<< "your aerodynamics definition." << endl;
|
||||
exit(-1);
|
||||
{
|
||||
stringstream s;
|
||||
s << " A proper axis type has NOT been selected. Check "
|
||||
<< "your aerodynamics definition.";
|
||||
cerr << endl << s.str() << endl;
|
||||
throw BaseException(s.str());
|
||||
}
|
||||
}
|
||||
// Calculate aerodynamic reference point shift, if any. The shift takes place
|
||||
// in the structual axis. That is, if the shift is positive, it is towards the
|
||||
|
@ -257,7 +261,7 @@ bool FGAerodynamics::Run(bool Holding)
|
|||
vMomentsMRC(axis_ctr+1) += (*f)->GetValue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Transform moments to bodyXYZ if the moments are specified in stability or
|
||||
// wind axes
|
||||
vMomentsMRCBodyXYZ.InitMatrix();
|
||||
|
@ -272,13 +276,17 @@ bool FGAerodynamics::Run(bool Holding)
|
|||
vMomentsMRCBodyXYZ = in.Tw2b*vMomentsMRC;
|
||||
break;
|
||||
default:
|
||||
cerr << endl << " A proper axis type has NOT been selected. Check "
|
||||
<< "your aerodynamics definition." << endl;
|
||||
exit(-1);
|
||||
{
|
||||
stringstream s;
|
||||
s << " A proper axis type has NOT been selected. Check "
|
||||
<< "your aerodynamics definition.";
|
||||
cerr << endl << s.str() << endl;
|
||||
throw BaseException(s.str());
|
||||
}
|
||||
}
|
||||
|
||||
vMoments = vMomentsMRCBodyXYZ + vDXYZcg*vForces; // M = r X F
|
||||
|
||||
|
||||
// Now add the "at CG" values to base forces - after the moments have been
|
||||
// transferred.
|
||||
vForces += vForcesAtCG;
|
||||
|
@ -310,7 +318,7 @@ bool FGAerodynamics::Run(bool Holding)
|
|||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGColumnVector3 FGAerodynamics::GetForcesInStabilityAxes(void) const
|
||||
{
|
||||
{
|
||||
FGColumnVector3 vFs = Tb2s*vForces;
|
||||
// Need sign flips since drag is positive and lift is positive in stability axes
|
||||
vFs(eDrag) *= -1; vFs(eLift) *= -1;
|
||||
|
@ -403,15 +411,15 @@ bool FGAerodynamics::Load(Element *document)
|
|||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// This private class function checks to verify consistency in the choice of
|
||||
// aerodynamic axes used in the config file. One set of LIFT|DRAG|SIDE, or
|
||||
// aerodynamic axes used in the config file. One set of LIFT|DRAG|SIDE, or
|
||||
// X|Y|Z, or AXIAL|NORMAL|SIDE must be chosen; mixed system axes are not allowed.
|
||||
// Note that if the "SIDE" axis specifier is entered first in a config file,
|
||||
// Note that if the "SIDE" axis specifier is entered first in a config file,
|
||||
// a warning message will be given IF the AXIAL|NORMAL specifiers are also given.
|
||||
// This is OK, and the warning is due to the SIDE specifier used for both
|
||||
// the Lift/Drag and Axial/Normal axis systems.
|
||||
// Alternatively the axis name 'X|Y|Z or ROLL|PITCH|YAW' can be specified in
|
||||
// Alternatively the axis name 'X|Y|Z or ROLL|PITCH|YAW' can be specified in
|
||||
// conjunction with a frame 'BODY|STABILITY|WIND', for example:
|
||||
// <axis name="X" frame="STABILITY"/>
|
||||
// <axis name="X" frame="STABILITY"/>
|
||||
|
||||
void FGAerodynamics::DetermineAxisSystem(Element* document)
|
||||
{
|
||||
|
@ -447,10 +455,12 @@ void FGAerodynamics::DetermineAxisSystem(Element* document)
|
|||
<< " aircraft config file. (NORMAL AXIAL)" << endl;
|
||||
}
|
||||
} else { // error
|
||||
cerr << endl << axis_element->ReadFrom()
|
||||
<< endl << " An unknown axis type, " << axis << " has been specified"
|
||||
<< " in the aircraft configuration file." << endl;
|
||||
exit(-1);
|
||||
stringstream s;
|
||||
s << axis_element->ReadFrom()
|
||||
<< endl << " An unknown axis type, " << axis << " has been specified"
|
||||
<< " in the aircraft configuration file.";
|
||||
cerr << endl << s.str() << endl;
|
||||
throw BaseException(s.str());
|
||||
}
|
||||
axis_element = document->FindNextElement("axis");
|
||||
}
|
||||
|
@ -495,8 +505,10 @@ void FGAerodynamics::ProcessAxesNameAndFrame(eAxisType& axisType, const string&
|
|||
<< " aircraft config file." << validNames << " - WIND" << endl;
|
||||
}
|
||||
else {
|
||||
cerr << endl << " Unknown axis frame type of - " << frame << endl;
|
||||
exit(-1);
|
||||
stringstream s;
|
||||
s << " Unknown axis frame type of - " << frame;
|
||||
cerr << endl << s.str() << endl;
|
||||
throw BaseException(s.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -596,7 +608,7 @@ void FGAerodynamics::bind(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// Build transformation matrices for transforming from stability axes to
|
||||
// Build transformation matrices for transforming from stability axes to
|
||||
// body axes and to wind axes. Where "a" is alpha and "B" is beta:
|
||||
//
|
||||
// The transform from body to stability axes is:
|
||||
|
|
|
@ -86,8 +86,9 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, unsigned int num,
|
|||
if (element) {
|
||||
vXYZ = element->FindElementTripletConvertTo("IN");
|
||||
} else {
|
||||
cerr << "Fatal Error: No location found for this gas cell." << endl;
|
||||
exit(-1);
|
||||
const string s("Fatal Error: No location found for this gas cell.");
|
||||
cerr << el->ReadFrom() << endl << s << endl;
|
||||
throw BaseException(s);
|
||||
}
|
||||
if ((el->FindElement("x_radius") || el->FindElement("x_width")) &&
|
||||
(el->FindElement("y_radius") || el->FindElement("y_width")) &&
|
||||
|
@ -126,7 +127,7 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, unsigned int num,
|
|||
MaxVolume = M_PI * Yradius * Zradius * Xwidth;
|
||||
} else {
|
||||
cerr << "Warning: Unsupported gas cell shape." << endl;
|
||||
MaxVolume =
|
||||
MaxVolume =
|
||||
(4.0 * M_PI * Xradius * Yradius * Zradius / 3.0 +
|
||||
M_PI * Yradius * Zradius * Xwidth +
|
||||
M_PI * Xradius * Zradius * Ywidth +
|
||||
|
@ -137,8 +138,9 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, unsigned int num,
|
|||
Xwidth * Ywidth * Zwidth);
|
||||
}
|
||||
} else {
|
||||
cerr << "Fatal Error: Gas cell shape must be given." << endl;
|
||||
exit(-1);
|
||||
const string s("Fatal Error: Gas cell shape must be given.");
|
||||
cerr << el->ReadFrom() << endl << s << endl;
|
||||
throw BaseException(s);
|
||||
}
|
||||
if (el->FindElement("max_overpressure")) {
|
||||
MaxOverpressure = el->FindElementValueAsNumberConvertTo("max_overpressure",
|
||||
|
@ -146,12 +148,12 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, unsigned int num,
|
|||
}
|
||||
if (el->FindElement("fullness")) {
|
||||
const double Fullness = el->FindElementValueAsNumber("fullness");
|
||||
if (0 <= Fullness) {
|
||||
Volume = Fullness * MaxVolume;
|
||||
if (0 <= Fullness) {
|
||||
Volume = Fullness * MaxVolume;
|
||||
} else {
|
||||
cerr << "Warning: Invalid initial gas cell fullness value." << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (el->FindElement("valve_coefficient")) {
|
||||
ValveCoefficient =
|
||||
el->FindElementValueAsNumberConvertTo("valve_coefficient",
|
||||
|
@ -171,7 +173,7 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, unsigned int num,
|
|||
if (Volume != 0.0) {
|
||||
// Calculate initial gas content.
|
||||
Contents = Pressure * Volume / (R * Temperature);
|
||||
|
||||
|
||||
// Clip to max allowed value.
|
||||
const double IdealPressure = Contents * R * Temperature / MaxVolume;
|
||||
if (IdealPressure > Pressure + MaxOverpressure) {
|
||||
|
@ -263,7 +265,7 @@ void FGGasCell::Calculate(double dt)
|
|||
const size_t no_ballonets = Ballonet.size();
|
||||
|
||||
//-- Read ballonet state --
|
||||
// NOTE: This model might need a more proper integration technique.
|
||||
// NOTE: This model might need a more proper integration technique.
|
||||
double BallonetsVolume = 0.0;
|
||||
double BallonetsHeatFlow = 0.0;
|
||||
for (i = 0; i < no_ballonets; i++) {
|
||||
|
@ -282,7 +284,7 @@ void FGGasCell::Calculate(double dt)
|
|||
dU += HeatTransferCoeff[i]->GetValue();
|
||||
}
|
||||
// Don't include dt when accounting for adiabatic expansion/contraction.
|
||||
// The rate of adiabatic cooling looks about right: ~5.4 Rankine/1000ft.
|
||||
// The rate of adiabatic cooling looks about right: ~5.4 Rankine/1000ft.
|
||||
if (Contents > 0) {
|
||||
Temperature +=
|
||||
(dU * dt - Pressure * dVolumeIdeal - BallonetsHeatFlow) /
|
||||
|
@ -354,7 +356,7 @@ void FGGasCell::Calculate(double dt)
|
|||
//-- Current buoyancy --
|
||||
// The buoyancy is computed using the atmospheres local density.
|
||||
Buoyancy = Volume * AirDensity * g;
|
||||
|
||||
|
||||
// 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.
|
||||
|
@ -372,7 +374,7 @@ void FGGasCell::Calculate(double dt)
|
|||
// Ellipsoid volume.
|
||||
Ixx = (1.0 / 5.0) * mass * (Yradius*Yradius + Zradius*Zradius);
|
||||
Iyy = (1.0 / 5.0) * mass * (Xradius*Xradius + Zradius*Zradius);
|
||||
Izz = (1.0 / 5.0) * mass * (Xradius*Xradius + Yradius*Yradius);
|
||||
Izz = (1.0 / 5.0) * mass * (Xradius*Xradius + Yradius*Yradius);
|
||||
} else if ((Xradius == 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&
|
||||
(Xwidth != 0.0) && (Ywidth == 0.0) && (Zwidth == 0.0)) {
|
||||
// Cylindrical volume (might not be valid with an elliptical cross-section).
|
||||
|
@ -407,7 +409,7 @@ void FGGasCell::Calculate(double dt)
|
|||
// Add the mass, moment and inertia of any ballonets.
|
||||
for (i = 0; i < no_ballonets; i++) {
|
||||
Mass += Ballonet[i]->GetMass();
|
||||
|
||||
|
||||
// Add ballonet moments due to mass (in the structural frame).
|
||||
gasCellM(eX) +=
|
||||
Ballonet[i]->GetXYZ(eX) * Ballonet[i]->GetMass()*slugtolb;
|
||||
|
@ -415,7 +417,7 @@ void FGGasCell::Calculate(double dt)
|
|||
Ballonet[i]->GetXYZ(eY) * Ballonet[i]->GetMass()*slugtolb;
|
||||
gasCellM(eZ) +=
|
||||
Ballonet[i]->GetXYZ(eZ) * Ballonet[i]->GetMass()*slugtolb;
|
||||
|
||||
|
||||
gasCellJ += Ballonet[i]->GetInertia();
|
||||
}
|
||||
}
|
||||
|
@ -451,9 +453,9 @@ void FGGasCell::Debug(int from)
|
|||
cout << " Cell location (X, Y, Z) (in.): " << vXYZ(eX) << ", " <<
|
||||
vXYZ(eY) << ", " << vXYZ(eZ) << endl;
|
||||
cout << " Maximum volume: " << MaxVolume << " ft3" << endl;
|
||||
cout << " Relief valve release pressure: " << MaxOverpressure <<
|
||||
cout << " Relief valve release pressure: " << MaxOverpressure <<
|
||||
" lbs/ft2" << endl;
|
||||
cout << " Manual valve coefficient: " << ValveCoefficient <<
|
||||
cout << " Manual valve coefficient: " << ValveCoefficient <<
|
||||
" ft4*sec/slug" << endl;
|
||||
cout << " Initial temperature: " << Temperature << " Rankine" <<
|
||||
endl;
|
||||
|
@ -471,7 +473,7 @@ void FGGasCell::Debug(int from)
|
|||
}
|
||||
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
|
||||
}
|
||||
if (debug_lvl & 8 ) { // Runtime state variables
|
||||
if (debug_lvl & 8 ) { // Runtime state variables
|
||||
cout << " " << type << " cell holds " << Contents << " mol " << endl;
|
||||
cout << " Temperature: " << Temperature << " Rankine" << endl;
|
||||
cout << " Pressure: " << Pressure << " lbs/ft2" << endl;
|
||||
|
@ -517,8 +519,9 @@ FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, unsigned int num,
|
|||
if (element) {
|
||||
vXYZ = element->FindElementTripletConvertTo("IN");
|
||||
} else {
|
||||
cerr << "Fatal Error: No location found for this ballonet." << endl;
|
||||
exit(-1);
|
||||
const string s("Fatal Error: No location found for this ballonet.");
|
||||
cerr << el->ReadFrom() << endl << s << endl;
|
||||
throw BaseException(s);
|
||||
}
|
||||
if ((el->FindElement("x_radius") || el->FindElement("x_width")) &&
|
||||
(el->FindElement("y_radius") || el->FindElement("y_width")) &&
|
||||
|
@ -557,7 +560,7 @@ FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, unsigned int num,
|
|||
MaxVolume = M_PI * Yradius * Zradius * Xwidth;
|
||||
} else {
|
||||
cerr << "Warning: Unsupported ballonet shape." << endl;
|
||||
MaxVolume =
|
||||
MaxVolume =
|
||||
(4.0 * M_PI * Xradius * Yradius * Zradius / 3.0 +
|
||||
M_PI * Yradius * Zradius * Xwidth +
|
||||
M_PI * Xradius * Zradius * Ywidth +
|
||||
|
@ -568,8 +571,9 @@ FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, unsigned int num,
|
|||
Xwidth * Ywidth * Zwidth);
|
||||
}
|
||||
} else {
|
||||
cerr << "Fatal Error: Ballonet shape must be given." << endl;
|
||||
exit(-1);
|
||||
const string s("Fatal Error: Ballonet shape must be given.");
|
||||
cerr << el->ReadFrom() << endl << s << endl;
|
||||
throw BaseException(s);
|
||||
}
|
||||
if (el->FindElement("max_overpressure")) {
|
||||
MaxOverpressure = el->FindElementValueAsNumberConvertTo("max_overpressure",
|
||||
|
@ -577,12 +581,12 @@ FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, unsigned int num,
|
|||
}
|
||||
if (el->FindElement("fullness")) {
|
||||
const double Fullness = el->FindElementValueAsNumber("fullness");
|
||||
if (0 <= Fullness) {
|
||||
Volume = Fullness * MaxVolume;
|
||||
if (0 <= Fullness) {
|
||||
Volume = Fullness * MaxVolume;
|
||||
} else {
|
||||
cerr << "Warning: Invalid initial ballonet fullness value." << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (el->FindElement("valve_coefficient")) {
|
||||
ValveCoefficient =
|
||||
el->FindElementValueAsNumberConvertTo("valve_coefficient",
|
||||
|
@ -600,7 +604,7 @@ FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, unsigned int num,
|
|||
if (Volume != 0.0) {
|
||||
// Calculate initial air content.
|
||||
Contents = Pressure * Volume / (R * Temperature);
|
||||
|
||||
|
||||
// Clip to max allowed value.
|
||||
const double IdealPressure = Contents * R * Temperature / MaxVolume;
|
||||
if (IdealPressure > Pressure + MaxOverpressure) {
|
||||
|
@ -746,7 +750,7 @@ void FGBallonet::Calculate(double dt)
|
|||
// Ellipsoid volume.
|
||||
Ixx = (1.0 / 5.0) * mass * (Yradius*Yradius + Zradius*Zradius);
|
||||
Iyy = (1.0 / 5.0) * mass * (Xradius*Xradius + Zradius*Zradius);
|
||||
Izz = (1.0 / 5.0) * mass * (Xradius*Xradius + Yradius*Yradius);
|
||||
Izz = (1.0 / 5.0) * mass * (Xradius*Xradius + Yradius*Yradius);
|
||||
} else if ((Xradius == 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&
|
||||
(Xwidth != 0.0) && (Ywidth == 0.0) && (Zwidth == 0.0)) {
|
||||
// Cylindrical volume (might not be valid with an elliptical cross-section).
|
||||
|
@ -798,9 +802,9 @@ void FGBallonet::Debug(int from)
|
|||
cout << " Location (X, Y, Z) (in.): " << vXYZ(eX) << ", " <<
|
||||
vXYZ(eY) << ", " << vXYZ(eZ) << endl;
|
||||
cout << " Maximum volume: " << MaxVolume << " ft3" << endl;
|
||||
cout << " Relief valve release pressure: " << MaxOverpressure <<
|
||||
cout << " Relief valve release pressure: " << MaxOverpressure <<
|
||||
" lbs/ft2" << endl;
|
||||
cout << " Relief valve coefficient: " << ValveCoefficient <<
|
||||
cout << " Relief valve coefficient: " << ValveCoefficient <<
|
||||
" ft4*sec/slug" << endl;
|
||||
cout << " Initial temperature: " << Temperature << " Rankine" <<
|
||||
endl;
|
||||
|
@ -818,7 +822,7 @@ void FGBallonet::Debug(int from)
|
|||
}
|
||||
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
|
||||
}
|
||||
if (debug_lvl & 8 ) { // Runtime state variables
|
||||
if (debug_lvl & 8 ) { // Runtime state variables
|
||||
cout << " Ballonet holds " << Contents <<
|
||||
" mol air" << endl;
|
||||
cout << " Temperature: " << Temperature << " Rankine" << endl;
|
||||
|
|
|
@ -43,7 +43,7 @@ INCLUDES
|
|||
#include "input_output/FGUDPInputSocket.h"
|
||||
#include "input_output/FGXMLFileRead.h"
|
||||
#include "input_output/FGModelLoader.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
@ -84,7 +84,7 @@ bool FGInput::Load(Element* el)
|
|||
Element* element = ModelLoader.Open(el);
|
||||
|
||||
if (!element) return false;
|
||||
|
||||
|
||||
FGModel::PreLoad(element, FDMExec);
|
||||
|
||||
size_t idx = InputTypes.size();
|
||||
|
@ -152,6 +152,11 @@ bool FGInput::SetDirectivesFile(const SGPath& fname)
|
|||
{
|
||||
FGXMLFileRead XMLFile;
|
||||
Element* document = XMLFile.LoadXMLDocument(fname);
|
||||
if (!document) {
|
||||
stringstream s;
|
||||
s << "Could not read directive file: " << fname;
|
||||
throw BaseException(s.str());
|
||||
}
|
||||
bool result = Load(document);
|
||||
|
||||
if (!result)
|
||||
|
|
|
@ -180,7 +180,12 @@ FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number, const struct Inputs&
|
|||
|
||||
Element* element = el->FindElement("location");
|
||||
if (element) vXYZn = element->FindElementTripletConvertTo("IN");
|
||||
else {cerr << "No location given for contact " << name << endl; exit(-1);}
|
||||
else {
|
||||
stringstream s;
|
||||
s << "No location given for contact " << name;
|
||||
cerr << endl << s.str() << endl;
|
||||
throw BaseException(s.str());
|
||||
}
|
||||
SetTransformType(FGForce::tCustom);
|
||||
|
||||
element = el->FindElement("orientation");
|
||||
|
|
|
@ -117,7 +117,7 @@ static FGMatrix33 ReadInertiaMatrix(Element* document)
|
|||
|
||||
// Transform the inertia products from the structural frame to the body frame
|
||||
// and create the inertia matrix.
|
||||
if (document->GetAttributeValue("negated_crossproduct_inertia") == string("false"))
|
||||
if (document->GetAttributeValue("negated_crossproduct_inertia") == string("false"))
|
||||
return FGMatrix33( bixx, bixy, -bixz,
|
||||
bixy, biyy, biyz,
|
||||
-bixz, biyz, bizz );
|
||||
|
@ -268,9 +268,11 @@ void FGMassBalance::AddPointMass(Element* el)
|
|||
Element* loc_element = el->FindElement("location");
|
||||
string pointmass_name = el->GetAttributeValue("name");
|
||||
if (!loc_element) {
|
||||
cerr << el->ReadFrom() << "Pointmass " << pointmass_name
|
||||
<< " has no location." << endl;
|
||||
exit(-1);
|
||||
stringstream s;
|
||||
s << el->ReadFrom() << "Pointmass " << pointmass_name
|
||||
<< " has no location.";
|
||||
cerr << endl << s.str() << endl;
|
||||
throw BaseException(s.str());
|
||||
}
|
||||
|
||||
double w = el->FindElementValueAsNumberConvertTo("weight", "LBS");
|
||||
|
@ -449,11 +451,11 @@ void FGMassBalance::PointMass::bind(FGPropertyManager* PropertyManager,
|
|||
|
||||
void FGMassBalance::GetMassPropertiesReport(int i)
|
||||
{
|
||||
cout << endl << fgblue << highint
|
||||
cout << endl << fgblue << highint
|
||||
<< " Mass Properties Report (English units: lbf, in, slug-ft^2)"
|
||||
<< reset << endl;
|
||||
cout << " " << underon << " Weight CG-X CG-Y"
|
||||
<< " CG-Z Ixx Iyy Izz"
|
||||
<< " CG-Z Ixx Iyy Izz"
|
||||
<< " Ixy Ixz Iyz" << underoff << endl;
|
||||
cout.precision(1);
|
||||
cout << highint << setw(34) << left << " Base Vehicle " << normint
|
||||
|
@ -469,13 +471,13 @@ void FGMassBalance::GetMassPropertiesReport(int i)
|
|||
<< right << setw(10) << pmweight << setw(8) << pm->GetLocation()(eX)
|
||||
<< setw(8) << pm->GetLocation()(eY) << setw(8) << pm->GetLocation()(eZ)
|
||||
<< setw(12) << pm->GetPointMassMoI(1,1) << setw(12) << pm->GetPointMassMoI(2,2) << setw(12) << pm->GetPointMassMoI(3,3)
|
||||
<< setw(12) << pm->GetPointMassMoI(1,2) << setw(12) << pm->GetPointMassMoI(1,3) << setw(12) << pm->GetPointMassMoI(2,3) << endl;
|
||||
<< setw(12) << pm->GetPointMassMoI(1,2) << setw(12) << pm->GetPointMassMoI(1,3) << setw(12) << pm->GetPointMassMoI(2,3) << endl;
|
||||
}
|
||||
|
||||
cout << FDMExec->GetPropulsionTankReport();
|
||||
|
||||
cout << " " << underon << setw(136) << " " << underoff << endl;
|
||||
cout << highint << left << setw(30) << " Total: " << right << setw(14) << Weight
|
||||
cout << highint << left << setw(30) << " Total: " << right << setw(14) << Weight
|
||||
<< setw(8) << vXYZcg(eX)
|
||||
<< setw(8) << vXYZcg(eY)
|
||||
<< setw(8) << vXYZcg(eZ)
|
||||
|
|
|
@ -173,8 +173,13 @@ bool FGOutput::SetDirectivesFile(const SGPath& fname)
|
|||
{
|
||||
FGXMLFileRead XMLFile;
|
||||
Element* document = XMLFile.LoadXMLDocument(fname);
|
||||
bool result = Load(document);
|
||||
if (!document) {
|
||||
stringstream s;
|
||||
s << "Could not read directive file: " << fname;
|
||||
throw BaseException(s.str());
|
||||
}
|
||||
|
||||
bool result = Load(document);
|
||||
if (!result)
|
||||
cerr << endl << "Aircraft output element has problems in file " << fname << endl;
|
||||
|
||||
|
|
|
@ -688,7 +688,7 @@ void FGPropagate::WriteStateFile(int num)
|
|||
|
||||
if (num == 0) return;
|
||||
|
||||
SGPath path = FDMExec->GetFullAircraftPath();
|
||||
SGPath path = FDMExec->GetOutputPath();
|
||||
|
||||
if (path.isNull()) path = SGPath("initfile.");
|
||||
else path.append("initfile.");
|
||||
|
@ -968,16 +968,22 @@ void FGPropagate::Debug(int from)
|
|||
if (debug_lvl & 16) { // Sanity checking
|
||||
if (from == 2) { // State sanity checking
|
||||
if (fabs(VState.vPQR.Magnitude()) > 1000.0) {
|
||||
cerr << endl << "Vehicle rotation rate is excessive (>1000 rad/sec): " << VState.vPQR.Magnitude() << endl;
|
||||
exit(-1);
|
||||
stringstream s;
|
||||
s << "Vehicle rotation rate is excessive (>1000 rad/sec): " << VState.vPQR.Magnitude();
|
||||
cerr << endl << s.str() << endl;
|
||||
throw BaseException(s.str());
|
||||
}
|
||||
if (fabs(VState.vUVW.Magnitude()) > 1.0e10) {
|
||||
cerr << endl << "Vehicle velocity is excessive (>1e10 ft/sec): " << VState.vUVW.Magnitude() << endl;
|
||||
exit(-1);
|
||||
stringstream s;
|
||||
s << "Vehicle velocity is excessive (>1e10 ft/sec): " << VState.vUVW.Magnitude();
|
||||
cerr << endl << s.str() << endl;
|
||||
throw BaseException(s.str());
|
||||
}
|
||||
if (fabs(GetDistanceAGL()) > 1e10) {
|
||||
cerr << endl << "Vehicle altitude is excessive (>1e10 ft): " << GetDistanceAGL() << endl;
|
||||
exit(-1);
|
||||
stringstream s;
|
||||
s << "Vehicle altitude is excessive (>1e10 ft): " << GetDistanceAGL();
|
||||
cerr << endl << s.str() << endl;
|
||||
throw BaseException(s.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,34 +52,29 @@ CLASS IMPLEMENTATION
|
|||
FGKinemat::FGKinemat(FGFCS* fcs, Element* element)
|
||||
: FGFCSComponent(fcs, element)
|
||||
{
|
||||
Element *traverse_element, *setting_element;
|
||||
double tmpDetent;
|
||||
double tmpTime;
|
||||
|
||||
CheckInputNodes(1, 1, element);
|
||||
|
||||
Detents.clear();
|
||||
TransitionTimes.clear();
|
||||
|
||||
Output = 0;
|
||||
DoScale = true;
|
||||
|
||||
if (element->FindElement("noscale")) DoScale = false;
|
||||
|
||||
traverse_element = element->FindElement("traverse");
|
||||
setting_element = traverse_element->FindElement("setting");
|
||||
Element* traverse_element = element->FindElement("traverse");
|
||||
Element* setting_element = traverse_element->FindElement("setting");
|
||||
while (setting_element) {
|
||||
tmpDetent = setting_element->FindElementValueAsNumber("position");
|
||||
tmpTime = setting_element->FindElementValueAsNumber("time");
|
||||
double tmpDetent = setting_element->FindElementValueAsNumber("position");
|
||||
double tmpTime = setting_element->FindElementValueAsNumber("time");
|
||||
Detents.push_back(tmpDetent);
|
||||
TransitionTimes.push_back(tmpTime);
|
||||
setting_element = traverse_element->FindNextElement("setting");
|
||||
}
|
||||
|
||||
if (Detents.size() <= 1) {
|
||||
cerr << "Kinematic component " << Name
|
||||
<< " must have more than 1 setting element" << endl;
|
||||
exit(-1);
|
||||
stringstream s;
|
||||
s << "Kinematic component " << Name
|
||||
<< " must have more than 1 setting element";
|
||||
cerr << element->ReadFrom() << endl << s.str() << endl;
|
||||
throw BaseException(s.str());
|
||||
}
|
||||
|
||||
bind(element);
|
||||
|
|
|
@ -182,7 +182,24 @@ bool FGWaypoint::Run(void )
|
|||
double target_longitude_rad = target_longitude->GetValue() * target_longitude_unit;
|
||||
source.SetPosition(source_longitude_rad, source_latitude_rad, radius);
|
||||
|
||||
if (fabs(target_latitude_rad) > M_PI/2.0) {
|
||||
cerr << endl;
|
||||
cerr << "Target latitude in waypoint \"" << Name << "\" must be less than or equal to 90 degrees." << endl;
|
||||
cerr << "(is longitude being mistakenly supplied?)" << endl;
|
||||
cerr << endl;
|
||||
throw("Waypoint target latitude exceeded 90 degrees.");
|
||||
}
|
||||
|
||||
if (fabs(source_latitude_rad) > M_PI/2.0) {
|
||||
cerr << endl;
|
||||
cerr << "Source latitude in waypoint \"" << Name << "\" must be less than or equal to 90 degrees." << endl;
|
||||
cerr << "(is longitude being mistakenly supplied?)" << endl;
|
||||
cerr << endl;
|
||||
throw("Source latitude exceeded 90 degrees.");
|
||||
}
|
||||
|
||||
if (WaypointType == eHeading) { // Calculate Heading
|
||||
|
||||
double heading_to_waypoint_rad = source.GetHeadingTo(target_longitude_rad,
|
||||
target_latitude_rad);
|
||||
|
||||
|
@ -190,11 +207,12 @@ bool FGWaypoint::Run(void )
|
|||
else Output = heading_to_waypoint_rad;
|
||||
|
||||
} else { // Calculate Distance
|
||||
|
||||
double wp_distance = source.GetDistanceTo(target_longitude_rad,
|
||||
target_latitude_rad);
|
||||
|
||||
if (eUnit == eMeters) Output = FeetToMeters(wp_distance);
|
||||
else Output = wp_distance;
|
||||
|
||||
}
|
||||
|
||||
Clip();
|
||||
|
|
|
@ -56,8 +56,6 @@ FGEngine::FGEngine(int engine_number, struct Inputs& input)
|
|||
: in(input), EngineNumber(engine_number)
|
||||
{
|
||||
Type = etUnknown;
|
||||
X = Y = Z = 0.0;
|
||||
EnginePitch = EngineYaw = 0.0;
|
||||
SLFuelFlowMax = 0.0;
|
||||
FuelExpended = 0.0;
|
||||
MaxThrottle = 1.0;
|
||||
|
@ -113,18 +111,6 @@ unsigned int FGEngine::GetSourceTank(unsigned int i) const
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGEngine::SetPlacement(const FGColumnVector3& location,
|
||||
const FGColumnVector3& orientation)
|
||||
{
|
||||
X = location(eX);
|
||||
Y = location(eY);
|
||||
Z = location(eZ);
|
||||
EnginePitch = orientation(ePitch);
|
||||
EngineYaw = orientation (eYaw);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGEngine::GetThrust(void) const
|
||||
{
|
||||
return Thruster->GetThrust();
|
||||
|
@ -200,19 +186,17 @@ bool FGEngine::Load(FGFDMExec *exec, Element *engine_element)
|
|||
// Call ModelFunctions loader
|
||||
FGModelFunctions::Load(engine_element, exec, to_string((int)EngineNumber));
|
||||
|
||||
// Find and set engine location
|
||||
|
||||
// If engine location and/or orientation is supplied issue a warning since they
|
||||
// are ignored. What counts is the location and orientation of the thruster.
|
||||
local_element = parent_element->FindElement("location");
|
||||
if (local_element) location = local_element->FindElementTripletConvertTo("IN");
|
||||
// else cerr << "No engine location found for this engine." << endl;
|
||||
// Jon: The engine location is not important - the nozzle location is.
|
||||
if (local_element)
|
||||
cerr << local_element->ReadFrom()
|
||||
<< "Engine location ignored, only thruster location is used." << endl;
|
||||
|
||||
local_element = parent_element->FindElement("orient");
|
||||
if (local_element) orientation = local_element->FindElementTripletConvertTo("RAD");
|
||||
// else cerr << "No engine orientation found for this engine." << endl;
|
||||
// Jon: The engine orientation has a default and is not normally used.
|
||||
|
||||
SetPlacement(location, orientation);
|
||||
if (local_element)
|
||||
cerr << local_element->ReadFrom()
|
||||
<< "Engine orientation ignored, only thruster orientation is used." << endl;
|
||||
|
||||
// Load thruster
|
||||
local_element = parent_element->FindElement("thruster");
|
||||
|
|
|
@ -71,17 +71,6 @@ CLASS DOCUMENTATION
|
|||
<h3>Configuration File Format:</h3>
|
||||
@code
|
||||
<engine file="{string}">
|
||||
<location unit="{IN | M}">
|
||||
<x> {number} </x>
|
||||
<y> {number} </y>
|
||||
<z> {number} </z>
|
||||
</location>
|
||||
<!-- optional orientation definition -->
|
||||
<orient unit="{RAD | DEG}">
|
||||
<roll> {number} </roll>
|
||||
<pitch> {number} </pitch>
|
||||
<yaw> {number} </yaw>
|
||||
</orient>
|
||||
<feed> {integer} </feed>
|
||||
... optional more feed tank index numbers ...
|
||||
<thruster file="{string}">
|
||||
|
@ -183,9 +172,6 @@ public:
|
|||
|
||||
virtual double GetThrust(void) const;
|
||||
|
||||
/// Sets engine placement information
|
||||
virtual void SetPlacement(const FGColumnVector3& location, const FGColumnVector3& orientation);
|
||||
|
||||
/** The fuel need is calculated based on power levels and flow rate for that
|
||||
power level. It is also turned from a rate into an actual amount (pounds)
|
||||
by multiplying it by the delta T and the rate.
|
||||
|
@ -216,9 +202,6 @@ protected:
|
|||
std::string Name;
|
||||
const int EngineNumber;
|
||||
EngineType Type;
|
||||
double X, Y, Z;
|
||||
double EnginePitch;
|
||||
double EngineYaw;
|
||||
double SLFuelFlowMax;
|
||||
double MaxThrottle;
|
||||
double MinThrottle;
|
||||
|
|
|
@ -106,8 +106,11 @@ const FGMatrix33& FGForce::Transform(void) const
|
|||
case tNone:
|
||||
return mT;
|
||||
default:
|
||||
cout << "Unrecognized tranform requested from FGForce::Transform()" << endl;
|
||||
exit(1);
|
||||
{
|
||||
const string s("Unrecognized tranform requested from FGForce::Transform()");
|
||||
cout << s << endl;
|
||||
throw BaseException(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,13 +57,14 @@ FGNozzle::FGNozzle(FGFDMExec* FDMExec, Element* nozzle_element, int num)
|
|||
if (nozzle_element->FindElement("area"))
|
||||
Area = nozzle_element->FindElementValueAsNumberConvertTo("area", "FT2");
|
||||
else {
|
||||
cerr << "Fatal Error: Nozzle exit area must be given in nozzle config file." << endl;
|
||||
exit(-1);
|
||||
const string s("Fatal Error: Nozzle exit area must be given in nozzle config file.");
|
||||
cerr << s << endl;
|
||||
throw BaseException(s);
|
||||
}
|
||||
|
||||
Thrust = 0;
|
||||
Type = ttNozzle;
|
||||
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -193,10 +193,9 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
|
|||
switch (grainType) {
|
||||
case gtCYLINDRICAL:
|
||||
if (Radius <= InnerRadius) {
|
||||
cerr << element_Grain->ReadFrom()
|
||||
<< "The bore diameter should be smaller than the total grain diameter!"
|
||||
<< endl;
|
||||
exit(-1);
|
||||
const string s("The bore diameter should be smaller than the total grain diameter!");
|
||||
cerr << element_Grain->ReadFrom() << endl << s << endl;
|
||||
throw BaseException(s);
|
||||
}
|
||||
Volume = M_PI * Length * (Radius*Radius - InnerRadius*InnerRadius); // cubic inches
|
||||
break;
|
||||
|
@ -207,10 +206,11 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
|
|||
Volume = 1; // Volume is irrelevant for the FUNCTION type, but it can't be zero!
|
||||
break;
|
||||
case gtUNKNOWN:
|
||||
cerr << el->ReadFrom()
|
||||
<< "Unknown grain type found in this rocket engine definition."
|
||||
<< endl;
|
||||
exit(-1);
|
||||
{
|
||||
const string s("Unknown grain type found in this rocket engine definition.");
|
||||
cerr << el->ReadFrom() << endl << s << endl;
|
||||
throw BaseException(s);
|
||||
}
|
||||
}
|
||||
Density = (Capacity*lbtoslug)/Volume; // slugs/in^3
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
|
|||
Area = 40.0 * pow(Capacity/1975, 0.666666667);
|
||||
|
||||
// A named fuel type will override a previous density value
|
||||
if (!strFuelName.empty()) Density = ProcessFuelName(strFuelName);
|
||||
if (!strFuelName.empty()) Density = ProcessFuelName(strFuelName);
|
||||
|
||||
bind(PropertyManager);
|
||||
|
||||
|
@ -375,8 +375,9 @@ void FGTank::CalculateInertias(void)
|
|||
} else if (Contents <= 0.0) {
|
||||
Volume = 0;
|
||||
} else {
|
||||
cerr << endl << " Solid propellant grain density is zero!" << endl << endl;
|
||||
exit(-1);
|
||||
const string s(" Solid propellant grain density is zero!");
|
||||
cerr << endl << s << endl;
|
||||
throw BaseException(s);
|
||||
}
|
||||
|
||||
switch (grainType) {
|
||||
|
@ -399,9 +400,11 @@ void FGTank::CalculateInertias(void)
|
|||
Izz = function_izz->GetValue()*izz_unit;
|
||||
break;
|
||||
default:
|
||||
cerr << "Unknown grain type found." << endl;
|
||||
exit(-1);
|
||||
break;
|
||||
{
|
||||
const string s("Unknown grain type found.");
|
||||
cerr << s << endl;
|
||||
throw BaseException(s);
|
||||
}
|
||||
}
|
||||
|
||||
} else { // assume liquid propellant: shrinking snowball
|
||||
|
@ -415,7 +418,7 @@ void FGTank::CalculateInertias(void)
|
|||
|
||||
double FGTank::ProcessFuelName(const std::string& name)
|
||||
{
|
||||
if (name == "AVGAS") return 6.02;
|
||||
if (name == "AVGAS") return 6.02;
|
||||
else if (name == "JET-A") return 6.74;
|
||||
else if (name == "JET-A1") return 6.74;
|
||||
else if (name == "JET-B") return 6.48;
|
||||
|
@ -442,7 +445,7 @@ double FGTank::ProcessFuelName(const std::string& name)
|
|||
else if (name == "AVCAT") return 6.81;
|
||||
else {
|
||||
cerr << "Unknown fuel type specified: "<< name << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return 6.6;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue