1
0
Fork 0
This commit is contained in:
Torsten Dreyer 2011-04-14 11:42:15 +02:00
commit 06bd56a8e8
85 changed files with 4793 additions and 531 deletions

View file

@ -71,7 +71,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.84 2011/01/16 16:26:14 bcoconni Exp $";
static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.91 2011/04/05 20:20:21 andgi Exp $";
static const char *IdHdr = ID_FDMEXEC;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -116,6 +116,10 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root)
dT = 1.0/120.0; // a default timestep size. This is needed for when JSBSim is
// run in standalone mode with no initialization file.
AircraftPath = "aircraft";
EnginePath = "engine";
SystemsPath = "systems";
try {
char* num = getenv("JSBSIM_DEBUG");
if (num) debug_lvl = atoi(num); // set debug level
@ -154,12 +158,13 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root)
Constructing = true;
typedef int (FGFDMExec::*iPMF)(void) const;
// instance->Tie("simulation/do_trim_analysis", this, (iPMF)0, &FGFDMExec::DoTrimAnalysis);
instance->Tie("simulation/do_simple_trim", this, (iPMF)0, &FGFDMExec::DoTrim);
instance->Tie("simulation/reset", this, (iPMF)0, &FGFDMExec::ResetToInitialConditions);
// instance->Tie("simulation/do_trim_analysis", this, (iPMF)0, &FGFDMExec::DoTrimAnalysis, false);
instance->Tie("simulation/do_simple_trim", this, (iPMF)0, &FGFDMExec::DoTrim, false);
instance->Tie("simulation/reset", this, (iPMF)0, &FGFDMExec::ResetToInitialConditions, false);
instance->Tie("simulation/terminate", (int *)&Terminate);
instance->Tie("simulation/sim-time-sec", this, &FGFDMExec::GetSimTime);
instance->Tie("simulation/jsbsim-debug", this, &FGFDMExec::GetDebugLevel, &FGFDMExec::SetDebugLevel);
instance->Tie("simulation/frame", (int *)&Frame, false);
Constructing = false;
}
@ -350,6 +355,8 @@ bool FGFDMExec::RunIC(void)
void FGFDMExec::Initialize(FGInitialCondition *FGIC)
{
Setsim_time(0.0);
Propagate->SetInitialState( FGIC );
Atmosphere->Run();
@ -358,6 +365,9 @@ void FGFDMExec::Initialize(FGInitialCondition *FGIC)
FGIC->GetWindDFpsIC() );
FGColumnVector3 vAeroUVW;
//ToDo: move this to the Auxiliary class !?
vAeroUVW = Propagate->GetUVW() + Propagate->GetTl2b()*Atmosphere->GetTotalWindNED();
double alpha, beta;
@ -629,7 +639,9 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
// Process the output element[s]. This element is OPTIONAL, and there may be more than one.
unsigned int idx=0;
typedef int (FGOutput::*iOPMF)(void) const;
typedef double (FGOutput::*iOPMF)(void) const;
typedef int (FGFDMExec::*iOPV)(void) const;
typedef void (FGFDMExec::*vOPI)(int) const;
element = document->FindElement("output");
while (element) {
if (debug_lvl > 0) cout << endl << " Output data set: " << idx << " ";
@ -643,7 +655,8 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
} else {
Outputs.push_back(Output);
string outputProp = CreateIndexedPropertyName("simulation/output",idx);
instance->Tie(outputProp+"/log_rate_hz", Output, (iOPMF)0, &FGOutput::SetRate);
instance->Tie(outputProp+"/log_rate_hz", Output, (iOPMF)0, &FGOutput::SetRate, false);
instance->Tie("simulation/force-output", this, (iOPV)0, &FGFDMExec::ForceOutput, false);
idx++;
}
element = document->FindNextElement("output");
@ -679,15 +692,6 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
<< fgdef << endl;
}
// Late bind previously undefined FCS inputs.
try {
FCS->LateBind();
} catch (string prop) {
cerr << endl << fgred << " Could not late bind property " << prop
<< ". Aborting." << reset << endl;
result = false;
}
if (result) {
struct PropertyCatalogStructure masterPCS;
masterPCS.base_string = "";
@ -918,6 +922,13 @@ void FGFDMExec::EnableOutput(void)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGFDMExec::ForceOutput(int idx)
{
if (idx >= 0 && idx < Outputs.size()) Outputs[idx]->Print();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGFDMExec::SetOutputDirectives(const string& fname)
{
bool result;
@ -930,9 +941,9 @@ bool FGFDMExec::SetOutputDirectives(const string& fname)
if (result) {
Outputs.push_back(Output);
typedef int (FGOutput::*iOPMF)(void) const;
typedef double (FGOutput::*iOPMF)(void) const;
string outputProp = CreateIndexedPropertyName("simulation/output",Outputs.size()-1);
instance->Tie(outputProp+"/log_rate_hz", Output, (iOPMF)0, &FGOutput::SetRate);
instance->Tie(outputProp+"/log_rate_hz", Output, (iOPMF)0, &FGOutput::SetRate, false);
}
return result;

View file

@ -44,11 +44,9 @@ INCLUDES
#include <vector>
#include <string>
//#include "models/FGModel.h"
#include "models/FGOutput.h"
#include "models/FGInput.h"
#include "initialization/FGTrim.h"
#include "initialization/FGInitialCondition.h"
#include "FGJSBBase.h"
#include "input_output/FGPropertyManager.h"
#include "input_output/FGGroundCallback.h"
@ -60,7 +58,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_FDMEXEC "$Id: FGFDMExec.h,v 1.56 2010/11/18 20:37:10 jberndt Exp $"
#define ID_FDMEXEC "$Id: FGFDMExec.h,v 1.63 2011/02/19 16:44:41 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -183,7 +181,7 @@ CLASS DOCUMENTATION
property actually maps toa function call of DoTrim().
@author Jon S. Berndt
@version $Revision: 1.56 $
@version $Revision: 1.63 $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -286,8 +284,11 @@ public:
/** Loads 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.
@return true if successfully loadsd; false otherwise. */
bool LoadScript(const string& Script, double deltaT);
bool LoadScript(const string& Script, double deltaT=0.0);
/** Sets the path to the engine config file directories.
@param path path to the directory under which engine config
@ -401,6 +402,9 @@ public:
*/
bool SetOutputDirectives(const string& fname);
/** Forces the specified output object to print its items once */
void ForceOutput(int idx=0);
/** Sets (or overrides) the output filename
@param fname the name of the file to output data to
@return true if successful, false if there is no output specified for the flight model */
@ -514,7 +518,7 @@ public:
@param rootDir the string containing the root directory. */
void SetRootDir(const string& rootDir) {RootDir = rootDir;}
/** Retrieves teh Root Directory.
/** Retrieves the Root Directory.
@return the string representing the root (base) JSBSim directory. */
const string& GetRootDir(void) const {return RootDir;}

View file

@ -61,7 +61,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.56 2011/01/23 12:13:44 bcoconni Exp $";
static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.59 2011/04/03 13:18:51 bcoconni Exp $";
static const char *IdHdr = ID_INITIALCONDITION;
//******************************************************************************
@ -700,6 +700,8 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt)
case setve:
SetVtrueFpsIC(ve0 * sqrt(rho/rhoSL));
break;
default: // Make the compiler stop complaining about missing enums
break;
}
position.SetRadius(alt + sea_level_radius);
@ -998,6 +1000,18 @@ bool FGInitialCondition::Load_v1(void)
SetTargetNlfIC(document->FindElementValueAsNumber("targetNlf"));
}
// 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() );
p = vOmegaLocal(eP);
q = vOmegaLocal(eR);
r = vOmegaLocal(eQ);
return result;
}
@ -1032,7 +1046,7 @@ bool FGInitialCondition::Load_v2(void)
if (position_el->FindElement("radius")) {
position.SetRadius(position_el->FindElementValueAsNumberConvertTo("radius", "FT"));
} else if (position_el->FindElement("altitudeAGL")) {
position.SetRadius(sea_level_radius + terrain_elevation + position_el->FindElementValueAsNumberConvertTo("altitude", "FT"));
position.SetRadius(sea_level_radius + terrain_elevation + position_el->FindElementValueAsNumberConvertTo("altitudeAGL", "FT"));
} else if (position_el->FindElement("altitudeMSL")) {
position.SetRadius(sea_level_radius + position_el->FindElementValueAsNumberConvertTo("altitudeMSL", "FT"));
} else {
@ -1096,7 +1110,7 @@ bool FGInitialCondition::Load_v2(void)
//
// Or, using quaternions (note reverse ordering compared to matrix representation):
//
// Q_b/l = Q_e/l * Q_b/i
// Q_b/l = Q_i/l * Q_b/i
FGQuaternion QuatI2Body = FGQuaternion(vOrient);
QuatI2Body.Normalize();
@ -1196,6 +1210,9 @@ bool FGInitialCondition::Load_v2(void)
FGColumnVector3 vLocalRate;
Element* attrate_el = document->FindElement("attitude_rate");
// 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),
@ -1209,11 +1226,11 @@ bool FGInitialCondition::Load_v2(void)
FGColumnVector3 vAttRate = attrate_el->FindElementTripletConvertTo("RAD/SEC");
if (frame == "eci") {
vLocalRate = Tl2b * (position.GetTi2l() * (vAttRate - vOmegaEarth) - vOmegaLocal);
vLocalRate = Tl2b * position.GetTi2l() * (vAttRate - vOmegaEarth);
} else if (frame == "ecef") {
vLocalRate = Tl2b * (position.GetTec2l() * vAttRate - vOmegaLocal);
vLocalRate = Tl2b * position.GetTec2l() * vAttRate;
} else if (frame == "local") {
vLocalRate = vAttRate;
vLocalRate = vAttRate + vOmegaLocal;
} else if (!frame.empty()) { // misspelling of frame
cerr << endl << fgred << " Attitude rate frame type: \"" << frame
@ -1221,11 +1238,11 @@ bool FGInitialCondition::Load_v2(void)
result = false;
} else if (frame.empty()) {
vLocalRate = vOmegaLocal;
}
} else { // Body frame attitude rate assumed 0 relative to local.
vLocalRate.InitMatrix();
vLocalRate = vOmegaLocal;
}
p = vLocalRate(eP);

View file

@ -41,19 +41,10 @@ scheme. */
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <cstdlib>
#include <iomanip>
#include "FGTrim.h"
#include "models/FGAtmosphere.h"
#include "FGInitialCondition.h"
#include "models/FGAircraft.h"
#include "models/FGMassBalance.h"
#include "models/FGGroundReactions.h"
#include "models/FGInertial.h"
#include "models/FGAerodynamics.h"
#include "models/FGPropulsion.h"
#include "models/propulsion/FGEngine.h"
#include "math/FGColumnVector3.h"
#if _MSC_VER
#pragma warning (disable : 4786 4788)
@ -63,7 +54,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGTrim.cpp,v 1.13 2010/04/23 17:23:40 dpculp Exp $";
static const char *IdSrc = "$Id: FGTrim.cpp,v 1.15 2011/02/19 16:29:29 bcoconni Exp $";
static const char *IdHdr = ID_TRIM;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -241,7 +232,7 @@ bool FGTrim::DoTrim(void) {
fdmex->DisableOutput();
setEngineTrimMode(true);
fdmex->SetTrimStatus(true);
fgic->SetPRadpsIC(0.0);
fgic->SetQRadpsIC(0.0);
@ -358,7 +349,7 @@ bool FGTrim::DoTrim(void) {
for(i=0;i < fdmex->GetGroundReactions()->GetNumGearUnits();i++){
fdmex->GetGroundReactions()->GetGearUnit(i)->SetReport(true);
}
setEngineTrimMode(false);
fdmex->SetTrimStatus(false);
fdmex->EnableOutput();
return !trim_failed;
}
@ -625,15 +616,6 @@ void FGTrim::setDebug(void) {
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGTrim::setEngineTrimMode(bool mode) {
FGPropulsion* prop = fdmex->GetPropulsion();
for (unsigned int i=0; i<prop->GetNumEngines(); i++) {
prop->GetEngine(i)->SetTrimMode(mode);
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGTrim::SetMode(TrimMode tt) {
ClearStates();
mode=tt;

View file

@ -60,7 +60,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_TRIM "$Id: FGTrim.h,v 1.7 2010/04/23 17:23:40 dpculp Exp $"
#define ID_TRIM "$Id: FGTrim.h,v 1.8 2011/01/24 13:01:55 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -120,7 +120,7 @@ CLASS DOCUMENTATION
@endcode
@author Tony Peden
@version "$Id: FGTrim.h,v 1.7 2010/04/23 17:23:40 dpculp Exp $"
@version "$Id: FGTrim.h,v 1.8 2011/01/24 13:01:55 jberndt Exp $"
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -176,7 +176,6 @@ private:
void setupTurn(void);
void updateRates(void);
void setEngineTrimMode(bool mode);
void setDebug(void);
public:

71
src/FDM/JSBSim/input_output/FGPropertyManager.cpp Normal file → Executable file
View file

@ -49,17 +49,17 @@ COMMENTS, REFERENCES, and NOTES [use "class documentation" below for API docs]
namespace JSBSim {
bool FGPropertyManager::suppress_warning = true;
std::vector<std::string> FGPropertyManager::tied_properties;
std::vector<SGPropertyNode_ptr> FGPropertyManager::tied_properties;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPropertyManager::Unbind(void)
{
vector<string>::iterator it;
vector<SGPropertyNode_ptr>::iterator it;
for (it = tied_properties.begin();it < tied_properties.end();it++)
{
Untie(*it);
}
(*it)->untie();
tied_properties.clear();
}
@ -102,7 +102,6 @@ FGPropertyManager::GetNode (const string &relpath, int index, bool create)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGPropertyManager::HasNode (const string &path)
{
// Checking if a node exists shouldn't write a warning if it doesn't exist
@ -314,11 +313,17 @@ void FGPropertyManager::Untie (const string &name)
void FGPropertyManager::Tie (const string &name, bool *pointer, bool useDefault)
{
if (!tie(name.c_str(), SGRawValuePointer<bool>(pointer), useDefault))
SGPropertyNode* property = getNode(name.c_str(), true);
if (!property) {
cerr << "Could not get or create property " << name << endl;
return;
}
if (!property->tie(SGRawValuePointer<bool>(pointer), useDefault))
cerr << "Failed to tie property " << name << " to a pointer" << endl;
else {
tied_properties.push_back(name);
if (debug_lvl & 0x20) std::cout << name << std::endl;
tied_properties.push_back(property);
if (debug_lvl & 0x20) cout << name << endl;
}
}
@ -327,11 +332,17 @@ void FGPropertyManager::Tie (const string &name, bool *pointer, bool useDefault)
void FGPropertyManager::Tie (const string &name, int *pointer,
bool useDefault )
{
if (!tie(name.c_str(), SGRawValuePointer<int>(pointer), useDefault))
SGPropertyNode* property = getNode(name.c_str(), true);
if (!property) {
cerr << "Could not get or create property " << name << endl;
return;
}
if (!property->tie(SGRawValuePointer<int>(pointer), useDefault))
cerr << "Failed to tie property " << name << " to a pointer" << endl;
else {
tied_properties.push_back(name);
if (debug_lvl & 0x20) std::cout << name << std::endl;
tied_properties.push_back(property);
if (debug_lvl & 0x20) cout << name << endl;
}
}
@ -340,11 +351,17 @@ void FGPropertyManager::Tie (const string &name, int *pointer,
void FGPropertyManager::Tie (const string &name, long *pointer,
bool useDefault )
{
if (!tie(name.c_str(), SGRawValuePointer<long>(pointer), useDefault))
SGPropertyNode* property = getNode(name.c_str(), true);
if (!property) {
cerr << "Could not get or create property " << name << endl;
return;
}
if (!property->tie(SGRawValuePointer<long>(pointer), useDefault))
cerr << "Failed to tie property " << name << " to a pointer" << endl;
else {
tied_properties.push_back(name);
if (debug_lvl & 0x20) std::cout << name << std::endl;
tied_properties.push_back(property);
if (debug_lvl & 0x20) cout << name << endl;
}
}
@ -353,11 +370,17 @@ void FGPropertyManager::Tie (const string &name, long *pointer,
void FGPropertyManager::Tie (const string &name, float *pointer,
bool useDefault )
{
if (!tie(name.c_str(), SGRawValuePointer<float>(pointer), useDefault))
SGPropertyNode* property = getNode(name.c_str(), true);
if (!property) {
cerr << "Could not get or create property " << name << endl;
return;
}
if (!property->tie(SGRawValuePointer<float>(pointer), useDefault))
cerr << "Failed to tie property " << name << " to a pointer" << endl;
else {
tied_properties.push_back(name);
if (debug_lvl & 0x20) std::cout << name << std::endl;
tied_properties.push_back(property);
if (debug_lvl & 0x20) cout << name << endl;
}
}
@ -365,11 +388,17 @@ void FGPropertyManager::Tie (const string &name, float *pointer,
void FGPropertyManager::Tie (const string &name, double *pointer, bool useDefault)
{
if (!tie(name.c_str(), SGRawValuePointer<double>(pointer), useDefault))
SGPropertyNode* property = getNode(name.c_str(), true);
if (!property) {
cerr << "Could not get or create property " << name << endl;
return;
}
if (!property->tie(SGRawValuePointer<double>(pointer), useDefault))
cerr << "Failed to tie property " << name << " to a pointer" << endl;
else {
tied_properties.push_back(name);
if (debug_lvl & 0x20) std::cout << name << std::endl;
tied_properties.push_back(property);
if (debug_lvl & 0x20) cout << name << endl;
}
}

View file

@ -53,7 +53,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_PROPERTYMANAGER "$Id: FGPropertyManager.h,v 1.17 2010/07/08 11:36:28 jberndt Exp $"
#define ID_PROPERTYMANAGER "$Id: FGPropertyManager.h,v 1.20 2011/02/13 00:42:45 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -77,7 +77,7 @@ class FGPropertyManager : public SGPropertyNode, public FGJSBBase
{
private:
static bool suppress_warning;
static std::vector<std::string> tied_properties;
static std::vector<SGPropertyNode_ptr> tied_properties;
public:
/// Constructor
FGPropertyManager(void) {suppress_warning = false;}
@ -532,10 +532,16 @@ class FGPropertyManager : public SGPropertyNode, public FGJSBBase
template <class V> inline void
Tie (const std::string &name, V (*getter)(), void (*setter)(V) = 0, bool useDefault = true)
{
if (!tie(name.c_str(), SGRawValueFunctions<V>(getter, setter), useDefault))
std::cout << "Failed to tie property " << name << " to functions" << std::endl;
SGPropertyNode* property = getNode(name.c_str(), true);
if (!property) {
std::cerr << "Could not get or create property " << name << std::endl;
return;
}
if (!property->tie(SGRawValueFunctions<V>(getter, setter), useDefault))
std::cerr << "Failed to tie property " << name << " to functions" << std::endl;
else {
tied_properties.push_back(name);
tied_properties.push_back(property);
if (debug_lvl & 0x20) std::cout << name << std::endl;
}
}
@ -562,10 +568,16 @@ class FGPropertyManager : public SGPropertyNode, public FGJSBBase
template <class V> inline void Tie (const std::string &name, int index, V (*getter)(int),
void (*setter)(int, V) = 0, bool useDefault = true)
{
if (!tie(name.c_str(), SGRawValueFunctionsIndexed<V>(index, getter, setter), useDefault))
std::cout << "Failed to tie property " << name << " to indexed functions" << std::endl;
SGPropertyNode* property = getNode(name.c_str(), true);
if (!property) {
std::cerr << "Could not get or create property " << name << std::endl;
return;
}
if (!property->tie(SGRawValueFunctionsIndexed<V>(index, getter, setter), useDefault))
std::cerr << "Failed to tie property " << name << " to indexed functions" << std::endl;
else {
tied_properties.push_back(name);
tied_properties.push_back(property);
if (debug_lvl & 0x20) std::cout << name << std::endl;
}
}
@ -594,10 +606,16 @@ class FGPropertyManager : public SGPropertyNode, public FGJSBBase
Tie (const std::string &name, T * obj, V (T::*getter)() const,
void (T::*setter)(V) = 0, bool useDefault = true)
{
if (!tie(name.c_str(), SGRawValueMethods<T,V>(*obj, getter, setter), useDefault))
std::cout << "Failed to tie property " << name << " to object methods" << std::endl;
SGPropertyNode* property = getNode(name.c_str(), true);
if (!property) {
std::cerr << "Could not get or create property " << name << std::endl;
return;
}
if (!property->tie(SGRawValueMethods<T,V>(*obj, getter, setter), useDefault))
std::cerr << "Failed to tie property " << name << " to object methods" << std::endl;
else {
tied_properties.push_back(name);
tied_properties.push_back(property);
if (debug_lvl & 0x20) std::cout << name << std::endl;
}
}
@ -625,10 +643,16 @@ class FGPropertyManager : public SGPropertyNode, public FGJSBBase
Tie (const std::string &name, T * obj, int index, V (T::*getter)(int) const,
void (T::*setter)(int, V) = 0, bool useDefault = true)
{
if (!tie(name.c_str(), SGRawValueMethodsIndexed<T,V>(*obj, index, getter, setter), useDefault))
std::cout << "Failed to tie property " << name << " to indexed object methods" << std::endl;
SGPropertyNode* property = getNode(name.c_str(), true);
if (!property) {
std::cerr << "Could not get or create property " << name << std::endl;
return;
}
if (!property->tie(SGRawValueMethodsIndexed<T,V>(*obj, index, getter, setter), useDefault))
std::cerr << "Failed to tie property " << name << " to indexed object methods" << std::endl;
else {
tied_properties.push_back(name);
tied_properties.push_back(property);
if (debug_lvl & 0x20) std::cout << name << std::endl;
}
}

40
src/FDM/JSBSim/input_output/FGScript.cpp Normal file → Executable file
View file

@ -54,7 +54,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGScript.cpp,v 1.43 2011/01/16 15:27:34 jberndt Exp $";
static const char *IdSrc = "$Id: FGScript.cpp,v 1.46 2011/02/18 12:44:16 jberndt Exp $";
static const char *IdHdr = ID_FGSCRIPT;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -78,12 +78,19 @@ FGScript::FGScript(FGFDMExec* fgex) : FDMExec(fgex)
FGScript::~FGScript()
{
unsigned int i;
unsigned int i, j;
for (i=0; i<local_properties.size(); i++) delete local_properties[i];
for (i=0; i<local_properties.size(); i++) {
delete local_properties[i]->value;
delete local_properties[i];
}
local_properties.clear();
for (i=0; i<Events.size(); i++) delete Events[i].Condition;
for (i=0; i<Events.size(); i++) {
delete Events[i].Condition;
for (j=0; j<Events[i].Functions.size(); j++)
delete Events[i].Functions[j];
}
Events.clear();
Debug(1);
@ -139,6 +146,8 @@ bool FGScript::LoadScript(string script, double deltaT)
StartTime = run_element->GetAttributeValueAsNumber("start");
FDMExec->Setsim_time(StartTime);
EndTime = run_element->GetAttributeValueAsNumber("end");
// Make sure that the desired time is reached and executed.
EndTime += 0.99*FDMExec->GetDeltaT();
if (deltaT == 0.0)
dt = run_element->GetAttributeValueAsNumber("dt");
@ -240,11 +249,13 @@ bool FGScript::LoadScript(string script, double deltaT)
newCondition = new FGCondition(condition_element, PropertyManager);
} catch(string str) {
cout << endl << fgred << str << reset << endl << endl;
delete newEvent;
return false;
}
newEvent->Condition = newCondition;
} else {
cerr << "No condition specified in script event " << newEvent->Name << endl;
delete newEvent;
return false;
}
@ -258,16 +269,29 @@ bool FGScript::LoadScript(string script, double deltaT)
// Notify about when this event is triggered?
if ((notify_element = event_element->FindElement("notify")) != 0) {
newEvent->Notify = true;
// Check here for new <description> tag that gets echoed
string notify_description = notify_element->FindElementValue("description");
if (!notify_description.empty()) {
newEvent->Description = notify_description;
}
notify_property_element = notify_element->FindElement("property");
while (notify_property_element) {
notifyPropertyName = notify_property_element->GetDataLine();
if (PropertyManager->GetNode(notifyPropertyName)) {
newEvent->NotifyProperties.push_back( PropertyManager->GetNode(notifyPropertyName) );
string caption_attribute = notify_property_element->GetAttributeValue("caption");
if (caption_attribute.empty()) {
newEvent->DisplayString.push_back(notifyPropertyName);
} else {
newEvent->DisplayString.push_back(caption_attribute);
}
} else {
cout << endl << fgred << " Could not find the property named "
<< notifyPropertyName << " in script" << endl << " \""
<< ScriptName << "\". Execution is aborted. Please recheck "
<< "your input files and scripts." << reset << endl;
delete newEvent->Condition;
delete newEvent;
return false;
}
notify_property_element = notify_element->FindNextElement("property");
@ -339,7 +363,7 @@ bool FGScript::RunScript(void)
double currentTime = FDMExec->GetSimTime();
double newSetValue = 0;
if (currentTime > EndTime) return false; //Script done!
if (currentTime > EndTime) return false;
// Iterate over all events.
for (unsigned int ev_ctr=0; ev_ctr < Events.size(); ev_ctr++) {
@ -426,8 +450,12 @@ bool FGScript::RunScript(void)
if (Events[ev_ctr].Notify && !Events[ev_ctr].Notified) {
cout << endl << " Event " << event_ctr << " (" << Events[ev_ctr].Name << ")"
<< " executed at time: " << currentTime << endl;
if (!Events[ev_ctr].Description.empty()) {
cout << " " << Events[ev_ctr].Description << endl;
}
for (j=0; j<Events[ev_ctr].NotifyProperties.size();j++) {
cout << " " << Events[ev_ctr].NotifyProperties[j]->GetRelativeName()
// cout << " " << Events[ev_ctr].NotifyProperties[j]->GetRelativeName()
cout << " " << Events[ev_ctr].DisplayString[j]
<< " = " << Events[ev_ctr].NotifyProperties[j]->getDoubleValue() << endl;
}
cout << endl;

View file

@ -48,7 +48,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_FGSCRIPT "$Id: FGScript.h,v 1.18 2010/04/11 13:44:42 jberndt Exp $"
#define ID_FGSCRIPT "$Id: FGScript.h,v 1.20 2011/02/11 12:43:28 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -157,7 +157,7 @@ CLASS DOCUMENTATION
comes the &quot;run&quot; section, where the conditions are
described in &quot;event&quot; clauses.</p>
@author Jon S. Berndt
@version "$Id: FGScript.h,v 1.18 2010/04/11 13:44:42 jberndt Exp $"
@version "$Id: FGScript.h,v 1.20 2011/02/11 12:43:28 jberndt Exp $"
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -178,7 +178,7 @@ public:
has been supplied on the command line, it will be override the script-
specified simulation step size.
@param script the filename (including path name, if any) for the script.
@param deltaT a simulation step size from the command line
@param deltaT a simulation step size.
@return true if successful */
bool LoadScript(string script, double deltaT);
@ -215,8 +215,10 @@ private:
double StartTime;
double TimeSpan;
string Name;
string Description;
vector <FGPropertyManager*> SetParam;
vector <FGPropertyManager*> NotifyProperties;
vector <string> DisplayString;
vector <eAction> Action;
vector <eType> Type;
vector <double> SetValue;

8
src/FDM/JSBSim/input_output/FGXMLElement.cpp Normal file → Executable file
View file

@ -42,7 +42,7 @@ FORWARD DECLARATIONS
namespace JSBSim {
static const char *IdSrc = "$Id: FGXMLElement.cpp,v 1.31 2010/09/29 02:22:03 jberndt Exp $";
static const char *IdSrc = "$Id: FGXMLElement.cpp,v 1.32 2011/02/13 00:42:45 jberndt Exp $";
static const char *IdHdr = ID_XMLELEMENT;
bool Element::converterIsInitialized = false;
@ -64,6 +64,8 @@ Element::Element(const string& nm)
// Length
convert["M"]["FT"] = 3.2808399;
convert["FT"]["M"] = 1.0/convert["M"]["FT"];
convert["KM"]["FT"] = 3280.8399;
convert["FT"]["KM"] = 1.0/convert["KM"]["FT"];
convert["FT"]["IN"] = 12.0;
convert["IN"]["FT"] = 1.0/convert["FT"]["IN"];
convert["IN"]["M"] = convert["IN"]["FT"] * convert["FT"]["M"];
@ -121,6 +123,8 @@ Element::Element(const string& nm)
convert["FT/S"]["M/S"] = 1.0/convert["M/S"]["FT/S"];
convert["M/SEC"]["FT/SEC"] = 3.2808399;
convert["FT/SEC"]["M/SEC"] = 1.0/convert["M/SEC"]["FT/SEC"];
convert["KM/SEC"]["FT/SEC"] = 3280.8399;
convert["FT/SEC"]["KM/SEC"] = 1.0/convert["KM/SEC"]["FT/SEC"];
// Torque
convert["FT*LBS"]["N*M"] = 1.35581795;
convert["N*M"]["FT*LBS"] = 1/convert["FT*LBS"]["N*M"];
@ -153,6 +157,7 @@ Element::Element(const string& nm)
// Length
convert["M"]["M"] = 1.00;
convert["KM"]["KM"] = 1.00;
convert["FT"]["FT"] = 1.00;
convert["IN"]["IN"] = 1.00;
// Area
@ -195,6 +200,7 @@ Element::Element(const string& nm)
convert["KTS"]["KTS"] = 1.00;
convert["M/S"]["M/S"] = 1.0;
convert["M/SEC"]["M/SEC"] = 1.0;
convert["KM/SEC"]["KM/SEC"] = 1.0;
// Torque
convert["FT*LBS"]["FT*LBS"] = 1.00;
convert["N*M"]["N*M"] = 1.00;

View file

@ -35,6 +35,7 @@ INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGCondition.h"
#include "FGPropertyValue.h"
#include "input_output/FGXMLElement.h"
#include "input_output/FGPropertyManager.h"
#include <iostream>
@ -44,7 +45,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGCondition.cpp,v 1.13 2010/07/14 05:50:40 ehofman Exp $";
static const char *IdSrc = "$Id: FGCondition.cpp,v 1.14 2011/04/05 20:20:21 andgi Exp $";
static const char *IdHdr = ID_CONDITION;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -122,12 +123,11 @@ FGCondition::FGCondition(const string& test, FGPropertyManager* PropertyManager)
exit(-1);
}
TestParam1 = PropertyManager->GetNode(property1, false);
if (!TestParam1) {
cerr << fgred << " In condition: " << test << ". Unknown property "
<< property1 << " referenced." << endl
<< "Creating property. Check usage." << reset << endl;
TestParam1 = PropertyManager->GetNode(property1, true);
FGPropertyManager *node = PropertyManager->GetNode(property1, false);
if (node) {
TestParam1 = new FGPropertyValue(node);
} else {
TestParam1 = new FGPropertyValue(property1, PropertyManager);
}
Comparison = mComparison[conditional];
if (Comparison == ecUndef) {
@ -136,12 +136,11 @@ FGCondition::FGCondition(const string& test, FGPropertyManager* PropertyManager)
if (is_number(property2)) {
TestValue = atof(property2.c_str());
} else {
TestParam2 = PropertyManager->GetNode(property2, false);
if (!TestParam2) {
cerr << fgred << " In condition: " << test << ". Unknown property "
<< property2 << " referenced." << endl
<< "Creating property. Check usage." << reset << endl;
TestParam2 = PropertyManager->GetNode(property2, true);
node = PropertyManager->GetNode(property2, false);
if (node) {
TestParam2 = new FGPropertyValue(node);
} else {
TestParam2 = new FGPropertyValue(property2, PropertyManager);
}
}
}
@ -174,6 +173,8 @@ void FGCondition::InitializeConditionals(void)
FGCondition::~FGCondition(void)
{
delete TestParam1;
delete TestParam2;
for (unsigned int i=0; i<conditions.size(); i++) delete conditions[i];
Debug(1);
@ -267,11 +268,11 @@ void FGCondition::PrintCondition(void )
} else {
if (TestParam2 != 0L)
cout << " " << TestParam1->GetRelativeName() << " "
cout << " " << TestParam1->GetName() << " "
<< conditional << " "
<< TestParam2->GetRelativeName();
<< TestParam2->GetName();
else
cout << " " << TestParam1->GetRelativeName() << " "
cout << " " << TestParam1->GetName() << " "
<< conditional << " " << TestValue;
}
}

View file

@ -44,7 +44,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_CONDITION "$Id: FGCondition.h,v 1.5 2009/10/24 22:59:30 jberndt Exp $"
#define ID_CONDITION "$Id: FGCondition.h,v 1.6 2011/04/05 20:20:21 andgi Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -53,6 +53,7 @@ FORWARD DECLARATIONS
namespace JSBSim {
class FGPropertyManager;
class FGPropertyValue;
class Element;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -82,7 +83,8 @@ private:
std::map <std::string, eComparison> mComparison;
eLogic Logic;
FGPropertyManager *TestParam1, *TestParam2, *PropertyManager;
FGPropertyManager *PropertyManager;
FGPropertyValue *TestParam1, *TestParam2;
double TestValue;
eComparison Comparison;
bool isGroup;

20
src/FDM/JSBSim/math/FGFunction.cpp Normal file → Executable file
View file

@ -43,7 +43,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGFunction.cpp,v 1.35 2010/08/28 12:41:56 jberndt Exp $";
static const char *IdSrc = "$Id: FGFunction.cpp,v 1.36 2011/04/05 20:20:21 andgi Exp $";
static const char *IdHdr = ID_FUNCTION;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -177,9 +177,10 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
newNode = PropertyManager->GetNode(property_name);
Parameters.push_back(new FGPropertyValue( newNode ));
} else {
cerr << fgcyan << "The property " + property_name + " is initially undefined."
cerr << fgcyan << "Warning: The property " + property_name + " is initially undefined."
<< reset << endl;
Parameters.push_back(new FGPropertyValue( property_name ));
Parameters.push_back(new FGPropertyValue( property_name,
PropertyManager ));
}
} else if (operation == value_string || operation == v_string) {
Parameters.push_back(new FGRealValue(element->GetDataAsNumber()));
@ -252,17 +253,8 @@ double FGFunction::GetValue(void) const
if (cached) return cachedValue;
try {
temp = Parameters[0]->GetValue();
} catch (string prop) {
if (PropertyManager->HasNode(prop)) {
((FGPropertyValue*)Parameters[0])->SetNode(PropertyManager->GetNode(prop));
temp = Parameters[0]->GetValue();
} else {
throw("Property " + prop + " was not defined anywhere.");
}
}
temp = Parameters[0]->GetValue();
switch (Type) {
case eTopLevel:
break;

6
src/FDM/JSBSim/math/FGParameter.h Normal file → Executable file
View file

@ -40,7 +40,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_PARAMETER "$Id: FGParameter.h,v 1.5 2009/08/30 03:51:28 jberndt Exp $"
#define ID_PARAMETER "$Id: FGParameter.h,v 1.6 2011/04/05 20:20:21 andgi Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -65,6 +65,10 @@ class FGParameter : public FGJSBBase
public:
virtual ~FGParameter(void) {};
virtual double GetValue(void) const = 0;
virtual std::string GetName(void) const = 0;
// SGPropertyNode impersonation.
double getDoubleValue(void) const { return GetValue(); }
protected:
};

38
src/FDM/JSBSim/math/FGPropertyValue.cpp Normal file → Executable file
View file

@ -6,6 +6,7 @@ Date started: 12/10/2004
Purpose: Stores property values
------------- Copyright (C) 2001 Jon S. Berndt (jon@jsbsim.org) -------------
------ Copyright (C) 2010 - 2011 Anders Gidenstam (anders(at)gidenstam.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
@ -32,36 +33,53 @@ INCLUDES
namespace JSBSim {
static const char *IdSrc = "$Id: FGPropertyValue.cpp,v 1.6 2010/08/24 10:30:14 jberndt Exp $";
static const char *IdSrc = "$Id: FGPropertyValue.cpp,v 1.7 2011/04/05 20:20:21 andgi Exp $";
static const char *IdHdr = ID_PROPERTYVALUE;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGPropertyValue::FGPropertyValue(FGPropertyManager* propNode) : PropertyManager(propNode)
FGPropertyValue::FGPropertyValue(FGPropertyManager* propNode)
: PropertyManager(0L), PropertyNode(propNode)
{
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGPropertyValue::FGPropertyValue(std::string propName) : PropertyManager(0L)
FGPropertyValue::FGPropertyValue(std::string propName, FGPropertyManager* propertyManager)
: PropertyManager(propertyManager), PropertyNode(0L), PropertyName(propName)
{
PropertyName = propName;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGPropertyValue::GetValue(void) const
{
double val;
try {
val = PropertyManager->getDoubleValue();
} catch (...) {
throw(PropertyName);
FGPropertyManager* node = PropertyNode;
if (!PropertyNode) {
// The node cannot be cached since this is a const method.
node = PropertyManager->GetNode(PropertyName);
if (!node) {
throw(std::string("FGPropertyValue::GetValue() The property " +
PropertyName + " does not exist."));
}
}
return val;
return node->getDoubleValue();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
std::string FGPropertyValue::GetName(void) const
{
if (PropertyNode) {
return PropertyNode->GetName();
} else {
return PropertyName;
}
}
}

16
src/FDM/JSBSim/math/FGPropertyValue.h Normal file → Executable file
View file

@ -5,6 +5,7 @@ Author: Jon Berndt
Date started: December 10 2004
------------- Copyright (C) 2001 Jon S. Berndt (jon@jsbsim.org) -------------
------ Copyright (C) 2010 - 2011 Anders Gidenstam (anders(at)gidenstam.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
@ -41,7 +42,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_PROPERTYVALUE "$Id: FGPropertyValue.h,v 1.8 2010/08/24 10:30:14 jberndt Exp $"
#define ID_PROPERTYVALUE "$Id: FGPropertyValue.h,v 1.9 2011/04/05 20:20:21 andgi Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -53,8 +54,8 @@ namespace JSBSim {
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Represents a property value
@author Jon Berndt
/** Represents a property value which can use late binding.
@author Jon Berndt, Anders Gidenstam
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -66,14 +67,17 @@ class FGPropertyValue : public FGParameter
public:
FGPropertyValue(FGPropertyManager* propNode);
FGPropertyValue(std::string propName);
FGPropertyValue(std::string propName, FGPropertyManager* propertyManager);
~FGPropertyValue() {};
double GetValue(void) const;
void SetNode(FGPropertyManager* node) {PropertyManager = node;}
void SetNode(FGPropertyManager* node) {PropertyNode = node;}
std::string GetName(void) const;
private:
FGPropertyManager* PropertyManager;
FGPropertyManager* PropertyManager; // Property root used to do late binding.
FGPropertyManager* PropertyNode;
std::string PropertyName;
};

View file

@ -40,7 +40,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_REALVALUE "$Id: FGRealValue.h,v 1.4 2009/08/30 03:51:28 jberndt Exp $"
#define ID_REALVALUE "$Id: FGRealValue.h,v 1.5 2011/04/05 20:20:21 andgi Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -68,6 +68,7 @@ public:
~FGRealValue() {};
double GetValue(void) const;
std::string GetName(void) const {return "constant";}
private:
double Value;

View file

@ -47,7 +47,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_TABLE "$Id: FGTable.h,v 1.12 2010/09/16 11:01:24 jberndt Exp $"
#define ID_TABLE "$Id: FGTable.h,v 1.13 2011/04/05 20:20:21 andgi Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -233,7 +233,7 @@ combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio
@endcode
@author Jon S. Berndt
@version $Id: FGTable.h,v 1.12 2010/09/16 11:01:24 jberndt Exp $
@version $Id: FGTable.h,v 1.13 2011/04/05 20:20:21 andgi Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -292,6 +292,8 @@ public:
void Print(void);
std::string GetName(void) const {return Name;}
private:
enum type {tt1D, tt2D, tt3D} Type;
enum axis {eRow=0, eColumn, eTable};

View file

@ -52,7 +52,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGAerodynamics.cpp,v 1.36 2011/01/19 12:41:19 jberndt Exp $";
static const char *IdSrc = "$Id: FGAerodynamics.cpp,v 1.37 2011/03/11 13:02:26 jberndt Exp $";
static const char *IdHdr = ID_AERODYNAMICS;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -80,7 +80,7 @@ FGAerodynamics::FGAerodynamics(FGFDMExec* FDMExec) : FGModel(FDMExec)
axisType = atNone;
Coeff = new CoeffArray[6];
AeroFunctions = new AeroFunctionArray[6];
impending_stall = stall_hyst = 0.0;
alphaclmin = alphaclmax = 0.0;
@ -103,10 +103,10 @@ FGAerodynamics::~FGAerodynamics()
unsigned int i,j;
for (i=0; i<6; i++)
for (j=0; j<Coeff[i].size(); j++)
delete Coeff[i][j];
for (j=0; j<AeroFunctions[i].size(); j++)
delete AeroFunctions[i][j];
delete[] Coeff;
delete[] AeroFunctions;
delete AeroRPShift;
@ -142,7 +142,7 @@ bool FGAerodynamics::Run(void)
const double alpha=FDMExec->GetAuxiliary()->Getalpha();
const double twovel=2*FDMExec->GetAuxiliary()->GetVt();
const double qbar = FDMExec->GetAuxiliary()->Getqbar();
const double wingarea = FDMExec->GetAircraft()->GetWingArea();
const double wingarea = FDMExec->GetAircraft()->GetWingArea(); // TODO: Make these constants constant!
const double wingspan = FDMExec->GetAircraft()->GetWingSpan();
const double wingchord = FDMExec->GetAircraft()->Getcbar();
const double wingincidence = FDMExec->GetAircraft()->GetWingIncidence();
@ -177,8 +177,8 @@ bool FGAerodynamics::Run(void)
vFnative.InitMatrix();
for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
for (ctr=0; ctr < Coeff[axis_ctr].size(); ctr++) {
vFnative(axis_ctr+1) += Coeff[axis_ctr][ctr]->GetValue();
for (ctr=0; ctr < AeroFunctions[axis_ctr].size(); ctr++) {
vFnative(axis_ctr+1) += AeroFunctions[axis_ctr][ctr]->GetValue();
}
}
@ -224,8 +224,8 @@ bool FGAerodynamics::Run(void)
vMoments = vDXYZcg*vForces; // M = r X F
for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
for (ctr = 0; ctr < Coeff[axis_ctr+3].size(); ctr++) {
vMoments(axis_ctr+1) += Coeff[axis_ctr+3][ctr]->GetValue();
for (ctr = 0; ctr < AeroFunctions[axis_ctr+3].size(); ctr++) {
vMoments(axis_ctr+1) += AeroFunctions[axis_ctr+3][ctr]->GetValue();
}
}
@ -349,7 +349,7 @@ bool FGAerodynamics::Load(Element *element)
axis_element = document->FindElement("axis");
while (axis_element) {
CoeffArray ca;
AeroFunctionArray ca;
axis = axis_element->GetAttributeValue("name");
function_element = axis_element->FindElement("function");
while (function_element) {
@ -363,7 +363,7 @@ bool FGAerodynamics::Load(Element *element)
}
function_element = axis_element->FindNextElement("function");
}
Coeff[AxisIdx[axis]] = ca;
AeroFunctions[AxisIdx[axis]] = ca;
axis_element = document->FindNextElement("axis");
}
@ -427,35 +427,35 @@ void FGAerodynamics::DetermineAxisSystem()
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGAerodynamics::GetCoefficientStrings(const string& delimeter) const
string FGAerodynamics::GetAeroFunctionStrings(const string& delimeter) const
{
string CoeffStrings = "";
string AeroFunctionStrings = "";
bool firstime = true;
unsigned int axis, sd;
for (axis = 0; axis < 6; axis++) {
for (sd = 0; sd < Coeff[axis].size(); sd++) {
for (sd = 0; sd < AeroFunctions[axis].size(); sd++) {
if (firstime) {
firstime = false;
} else {
CoeffStrings += delimeter;
AeroFunctionStrings += delimeter;
}
CoeffStrings += Coeff[axis][sd]->GetName();
AeroFunctionStrings += AeroFunctions[axis][sd]->GetName();
}
}
return CoeffStrings;
return AeroFunctionStrings;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGAerodynamics::GetCoefficientValues(const string& delimeter) const
string FGAerodynamics::GetAeroFunctionValues(const string& delimeter) const
{
ostringstream buf;
for (unsigned int axis = 0; axis < 6; axis++) {
for (unsigned int sd = 0; sd < Coeff[axis].size(); sd++) {
for (unsigned int sd = 0; sd < AeroFunctions[axis].size(); sd++) {
if (buf.tellp() > 0) buf << delimeter;
buf << setw(9) << Coeff[axis][sd]->GetValue();
buf << setw(9) << AeroFunctions[axis][sd]->GetValue();
}
}

View file

@ -52,7 +52,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_AERODYNAMICS "$Id: FGAerodynamics.h,v 1.21 2010/11/18 12:38:06 jberndt Exp $"
#define ID_AERODYNAMICS "$Id: FGAerodynamics.h,v 1.22 2011/03/11 13:02:26 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -89,7 +89,7 @@ CLASS DOCUMENTATION
{function contents}
</function>
<axis name="{LIFT | DRAG | SIDE | ROLL | PITCH | YAW}">
{force coefficient definitions}
{force or moment definitions}
</axis>
{additional axis definitions}
</aerodynamics>
@ -103,13 +103,13 @@ CLASS DOCUMENTATION
<br>
2) Axial-Normal coordinate system:
@code
<axis name="{AXIAL | NORMAL}">
<axis name="{AXIAL | NORMAL | SIDE}">
@endcode
<br>
Systems may NOT be combined, or a load error will occur.
@author Jon S. Berndt, Tony Peden
@version $Revision: 1.21 $
@version $Revision: 1.22 $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -186,16 +186,16 @@ public:
void SetAlphaCLMax(double tt) { alphaclmax=tt; }
void SetAlphaCLMin(double tt) { alphaclmin=tt; }
/** Gets the strings for the current set of coefficients.
/** Gets the strings for the current set of aero functions.
@param delimeter either a tab or comma string depending on output type
@return a string containing the descriptive names for all coefficients */
std::string GetCoefficientStrings(const std::string& delimeter) const;
@return a string containing the descriptive names for all aero functions */
std::string GetAeroFunctionStrings(const std::string& delimeter) const;
/** Gets the coefficient values.
/** Gets the aero function values.
@param delimeter either a tab or comma string depending on output type
@return a string containing the numeric values for the current set of
coefficients */
std::string GetCoefficientValues(const std::string& delimeter) const;
aero functions */
std::string GetAeroFunctionValues(const std::string& delimeter) const;
/** Calculates and returns the wind-to-body axis transformation matrix.
@return a reference to the wind-to-body transformation matrix.
@ -207,15 +207,15 @@ public:
*/
FGMatrix33& GetTb2w(void);
std::vector <FGFunction*> * GetCoeff(void) const { return Coeff; }
std::vector <FGFunction*> * GetAeroFunctions(void) const { return AeroFunctions; }
private:
enum eAxisType {atNone, atLiftDrag, atAxialNormal, atBodyXYZ} axisType;
typedef std::map<std::string,int> AxisIndex;
AxisIndex AxisIdx;
FGFunction* AeroRPShift;
typedef vector <FGFunction*> CoeffArray;
CoeffArray* Coeff;
typedef vector <FGFunction*> AeroFunctionArray;
AeroFunctionArray* AeroFunctions;
FGColumnVector3 vFnative;
FGColumnVector3 vFw;
FGColumnVector3 vForces;

View file

@ -61,7 +61,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGAtmosphere.cpp,v 1.41 2010/11/30 12:19:57 jberndt Exp $";
static const char *IdSrc = "$Id: FGAtmosphere.cpp,v 1.42 2011/02/18 12:44:16 jberndt Exp $";
static const char *IdHdr = ID_ATMOSPHERE;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -124,6 +124,7 @@ FGAtmosphere::FGAtmosphere(FGFDMExec* fdmex) : FGModel(fdmex)
FGAtmosphere::~FGAtmosphere()
{
delete(POE_Table);
Debug(1);
}

26
src/FDM/JSBSim/models/FGAuxiliary.cpp Normal file → Executable file
View file

@ -59,7 +59,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGAuxiliary.cpp,v 1.45 2010/11/18 12:38:06 jberndt Exp $";
static const char *IdSrc = "$Id: FGAuxiliary.cpp,v 1.47 2011/03/29 11:49:27 jberndt Exp $";
static const char *IdHdr = ID_AUXILIARY;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -180,33 +180,30 @@ bool FGAuxiliary::Run()
vAeroUVW = vUVW - wind;
Vt = vAeroUVW.Magnitude();
double Vt2 = Vt*Vt;
alpha = beta = adot = bdot = 0;
double mUW = (vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
if ( Vt > 1.0 ) {
if (vAeroUVW(eW) != 0.0)
alpha = vAeroUVW(eU)*vAeroUVW(eU) > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0;
if (vAeroUVW(eV) != 0.0)
beta = vAeroUVW(eU)*vAeroUVW(eU)+vAeroUVW(eW)*vAeroUVW(eW) > 0.0 ? atan2(vAeroUVW(eV),
sqrt(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW))) : 0.0;
beta = mUW > 0.0 ? atan2(vAeroUVW(eV), sqrt(mUW)) : 0.0;
double mUW = (vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
double signU=1;
if (vAeroUVW(eU) < 0.0) signU=-1;
if ( mUW < 1.0 ) {
adot = 0.0;
bdot = 0.0;
} else {
if ( mUW >= 1.0 ) {
adot = (vAeroUVW(eU)*vUVWdot(eW) - vAeroUVW(eW)*vUVWdot(eU))/mUW;
bdot = (signU*mUW*vUVWdot(eV) - vAeroUVW(eV)*(vAeroUVW(eU)*vUVWdot(eU)
+ vAeroUVW(eW)*vUVWdot(eW)))/(Vt*Vt*sqrt(mUW));
bdot = (signU*mUW*vUVWdot(eV)
- vAeroUVW(eV)*(vAeroUVW(eU)*vUVWdot(eU) + vAeroUVW(eW)*vUVWdot(eW)))/(Vt2*sqrt(mUW));
}
} else {
alpha = beta = adot = bdot = 0;
}
Re = Vt * FDMExec->GetAircraft()->Getcbar() / FDMExec->GetAtmosphere()->GetKinematicViscosity();
qbar = 0.5*density*Vt*Vt;
qbarUW = 0.5*density*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
qbar = 0.5*density*Vt2;
qbarUW = 0.5*density*(mUW);
qbarUV = 0.5*density*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eV)*vAeroUVW(eV));
Mach = Vt / soundspeed;
MachU = vMachUVW(eU) = vAeroUVW(eU) / soundspeed;
@ -291,6 +288,7 @@ bool FGAuxiliary::Run()
//
// A positive headwind is blowing with you, a negative headwind is blowing against you.
// psi is the direction the wind is blowing *towards*.
// ToDo: should this simply be in the atmosphere class? Same with Get Crosswind.
double FGAuxiliary::GetHeadWind(void) const
{

View file

@ -45,7 +45,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGBuoyantForces.cpp,v 1.14 2010/11/18 12:38:06 jberndt Exp $";
static const char *IdSrc = "$Id: FGBuoyantForces.cpp,v 1.16 2011/03/23 11:58:29 jberndt Exp $";
static const char *IdHdr = ID_BUOYANTFORCES;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -213,13 +213,13 @@ string FGBuoyantForces::GetBuoyancyStrings(string delimeter)
}
for (axis = 0; axis < 6; axis++) {
for (sd = 0; sd < Coeff[axis].size(); sd++) {
for (sd = 0; sd < AeroFunctions[axis].size(); sd++) {
if (firstime) {
firstime = false;
} else {
CoeffStrings += delimeter;
}
CoeffStrings += Coeff[axis][sd]->GetName();
CoeffStrings += AeroFunctions[axis][sd]->GetName();
}
}
*/
@ -243,13 +243,13 @@ string FGBuoyantForces::GetBuoyancyValues(string delimeter)
}
for (unsigned int axis = 0; axis < 6; axis++) {
for (unsigned int sd = 0; sd < Coeff[axis].size(); sd++) {
for (unsigned int sd = 0; sd < AeroFunctions[axis].size(); sd++) {
if (firstime) {
firstime = false;
} else {
SDValues += delimeter;
}
SDValues += Coeff[axis][sd]->GetValueAsString();
SDValues += AeroFunctions[axis][sd]->GetValueAsString();
}
}
*/
@ -260,19 +260,20 @@ string FGBuoyantForces::GetBuoyancyValues(string delimeter)
void FGBuoyantForces::bind(void)
{
typedef double (FGBuoyantForces::*PMF)(int) const;
typedef double (FGBuoyantForces::*PGF)(int) const;
typedef void (FGBuoyantForces::*PSF)(int, double);
PropertyManager->Tie("moments/l-buoyancy-lbsft", this, eL,
(PMF)&FGBuoyantForces::GetMoments);
(PGF)&FGBuoyantForces::GetMoments, (PSF)0, false);
PropertyManager->Tie("moments/m-buoyancy-lbsft", this, eM,
(PMF)&FGBuoyantForces::GetMoments);
(PGF)&FGBuoyantForces::GetMoments, (PSF)0, false);
PropertyManager->Tie("moments/n-buoyancy-lbsft", this, eN,
(PMF)&FGBuoyantForces::GetMoments);
(PGF)&FGBuoyantForces::GetMoments, (PSF)0, false);
PropertyManager->Tie("forces/fbx-buoyancy-lbs", this, eX,
(PMF)&FGBuoyantForces::GetForces);
(PGF)&FGBuoyantForces::GetForces, (PSF)0, false);
PropertyManager->Tie("forces/fby-buoyancy-lbs", this, eY,
(PMF)&FGBuoyantForces::GetForces);
(PGF)&FGBuoyantForces::GetForces, (PSF)0, false);
PropertyManager->Tie("forces/fbz-buoyancy-lbs", this, eZ,
(PMF)&FGBuoyantForces::GetForces);
(PGF)&FGBuoyantForces::GetForces, (PSF)0, false);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -63,7 +63,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGFCS.cpp,v 1.72 2010/11/18 12:38:06 jberndt Exp $";
static const char *IdSrc = "$Id: FGFCS.cpp,v 1.73 2011/04/05 20:20:21 andgi Exp $";
static const char *IdHdr = ID_FCS;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -182,17 +182,6 @@ bool FGFCS::InitModel(void)
return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGFCS::LateBind(void)
{
unsigned int i;
for (i=0; i<Systems.size(); i++) Systems[i]->LateBind();
for (i=0; i<APComponents.size(); i++) APComponents[i]->LateBind();
for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->LateBind();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Notes: In this logic the default engine commands are set. This is simply a

View file

@ -51,7 +51,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_FCS "$Id: FGFCS.h,v 1.31 2010/09/22 11:33:40 jberndt Exp $"
#define ID_FCS "$Id: FGFCS.h,v 1.35 2011/04/05 20:20:21 andgi Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -168,7 +168,7 @@ CLASS DOCUMENTATION
@property gear/tailhook-pos-norm
@author Jon S. Berndt
@version $Revision: 1.31 $
@version $Revision: 1.35 $
@see FGActuator
@see FGDeadBand
@see FGFCSFunction
@ -540,7 +540,7 @@ public:
FGPropertyManager* GetPropertyManager(void) { return PropertyManager; }
void LateBind(void);
bool GetTrimStatus(void) const { return FDMExec->GetTrimStatus(); }
private:
double DaCmd, DeCmd, DrCmd, DsCmd, DfCmd, DsbCmd, DspCmd;

View file

@ -62,7 +62,7 @@ DEFINITIONS
GLOBAL DATA
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
static const char *IdSrc = "$Id: FGLGear.cpp,v 1.79 2010/11/28 13:20:47 bcoconni Exp $";
static const char *IdSrc = "$Id: FGLGear.cpp,v 1.80 2011/01/24 13:01:56 jberndt Exp $";
static const char *IdHdr = ID_LGEAR;
// Body To Structural (body frame is rotated 180 deg about Y and lengths are given in
@ -374,13 +374,15 @@ FGColumnVector3& FGLGear::GetBodyForces(void)
}
}
ReportTakeoffOrLanding();
if (!fdmex->GetTrimStatus()) {
ReportTakeoffOrLanding();
// Require both WOW and LastWOW to be true before checking crash conditions
// to allow the WOW flag to be used in terminating a scripted run.
if (WOW && lastWOW) CrashDetect();
// Require both WOW and LastWOW to be true before checking crash conditions
// to allow the WOW flag to be used in terminating a scripted run.
if (WOW && lastWOW) CrashDetect();
lastWOW = WOW;
lastWOW = WOW;
}
return FGForce::GetBodyForces();
}

View file

@ -57,7 +57,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGModel.cpp,v 1.16 2010/11/18 12:38:06 jberndt Exp $";
static const char *IdSrc = "$Id: FGModel.cpp,v 1.17 2011/02/16 12:30:53 jberndt Exp $";
static const char *IdHdr = ID_MODEL;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -77,7 +77,7 @@ FGModel::FGModel(FGFDMExec* fdmex)
//must be brought up now.
PropertyManager = FDMExec->GetPropertyManager();
exe_ctr = 1;
exe_ctr = 0;
rate = 1;
if (debug_lvl & 2) cout << " FGModel Base Class" << endl;
@ -105,7 +105,7 @@ bool FGModel::Run()
if (rate == 1) return false; // Fast exit if nothing to do
if (exe_ctr >= rate) exe_ctr = 1;
if (exe_ctr >= rate) exe_ctr = 0;
if (exe_ctr++ == 1) return false;
else return true;

View file

@ -74,7 +74,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGOutput.cpp,v 1.50 2010/11/18 12:38:06 jberndt Exp $";
static const char *IdSrc = "$Id: FGOutput.cpp,v 1.54 2011/03/11 13:02:26 jberndt Exp $";
static const char *IdHdr = ID_OUTPUT;
// (stolen from FGFS native_fdm.cxx)
@ -182,21 +182,9 @@ bool FGOutput::Run(void)
{
if (FGModel::Run()) return true;
if (enabled && !FDMExec->IntegrationSuspended()&& !FDMExec->Holding()) {
if (enabled && !FDMExec->IntegrationSuspended() && !FDMExec->Holding()) {
RunPreFunctions();
if (Type == otSocket) {
SocketOutput();
} else if (Type == otFlightGear) {
FlightGearSocketOutput();
} else if (Type == otCSV || Type == otTab) {
DelimitedOutput(Filename);
} else if (Type == otTerminal) {
// Not done yet
} else if (Type == otNone) {
// Do nothing
} else {
// Not a valid type of output
}
Print();
RunPostFunctions();
}
return false;
@ -204,6 +192,25 @@ bool FGOutput::Run(void)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGOutput::Print(void)
{
if (Type == otSocket) {
SocketOutput();
} else if (Type == otFlightGear) {
FlightGearSocketOutput();
} else if (Type == otCSV || Type == otTab) {
DelimitedOutput(Filename);
} else if (Type == otTerminal) {
// Not done yet
} else if (Type == otNone) {
// Do nothing
} else {
// Not a valid type of output
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGOutput::SetType(const string& type)
{
if (type == "CSV") {
@ -296,6 +303,7 @@ void FGOutput::DelimitedOutput(const string& fname)
outstream << "UBody" + delimeter + "VBody" + delimeter + "WBody" + delimeter;
outstream << "Aero V_{X Body} (ft/s)" + delimeter + "Aero V_{Y Body} (ft/s)" + delimeter + "Aero V_{Z Body} (ft/s)" + delimeter;
outstream << "V_{X_{inertial}} (ft/s)" + delimeter + "V_{Y_{inertial}} (ft/s)" + delimeter + "V_{Z_{inertial}} (ft/s)" + delimeter;
outstream << "V_{X_{ecef}} (ft/s)" + delimeter + "V_{Y_{ecef}} (ft/s)" + delimeter + "V_{Z_{ecef}} (ft/s)" + delimeter;
outstream << "V_{North} (ft/s)" + delimeter + "V_{East} (ft/s)" + delimeter + "V_{Down} (ft/s)";
}
if (SubSystems & ssForces) {
@ -359,8 +367,8 @@ void FGOutput::DelimitedOutput(const string& fname)
outstream << "Distance AGL (ft)" + delimeter;
outstream << "Terrain Elevation (ft)";
}
if (SubSystems & ssCoefficients) {
scratch = Aerodynamics->GetCoefficientStrings(delimeter);
if (SubSystems & ssAeroFunctions) {
scratch = Aerodynamics->GetAeroFunctionStrings(delimeter);
if (scratch.length() != 0) outstream << delimeter << scratch;
}
if (SubSystems & ssFCS) {
@ -415,6 +423,7 @@ void FGOutput::DelimitedOutput(const string& fname)
outstream << setprecision(12) << Propagate->GetUVW().Dump(delimeter) << delimeter;
outstream << Auxiliary->GetAeroUVW().Dump(delimeter) << delimeter;
outstream << Propagate->GetInertialVelocity().Dump(delimeter) << delimeter;
outstream << Propagate->GetECEFVelocity().Dump(delimeter) << delimeter;
outstream << Propagate->GetVel().Dump(delimeter);
outstream.precision(10);
}
@ -475,8 +484,8 @@ void FGOutput::DelimitedOutput(const string& fname)
outstream << Propagate->GetTerrainElevation();
outstream.precision(10);
}
if (SubSystems & ssCoefficients) {
scratch = Aerodynamics->GetCoefficientValues(delimeter);
if (SubSystems & ssAeroFunctions) {
scratch = Aerodynamics->GetAeroFunctionValues(delimeter);
if (scratch.length() != 0) outstream << delimeter << scratch;
}
if (SubSystems & ssFCS) {
@ -826,8 +835,8 @@ void FGOutput::SocketOutput(void)
socket->Append("Latitude (deg)");
socket->Append("Longitude (deg)");
}
if (SubSystems & ssCoefficients) {
scratch = Aerodynamics->GetCoefficientStrings(",");
if (SubSystems & ssAeroFunctions) {
scratch = Aerodynamics->GetAeroFunctionStrings(",");
if (scratch.length() != 0) socket->Append(scratch);
}
if (SubSystems & ssFCS) {
@ -932,8 +941,8 @@ void FGOutput::SocketOutput(void)
socket->Append(Propagate->GetLocation().GetLatitudeDeg());
socket->Append(Propagate->GetLocation().GetLongitudeDeg());
}
if (SubSystems & ssCoefficients) {
scratch = Aerodynamics->GetCoefficientValues(",");
if (SubSystems & ssAeroFunctions) {
scratch = Aerodynamics->GetAeroFunctionValues(",");
if (scratch.length() != 0) socket->Append(scratch);
}
if (SubSystems & ssFCS) {
@ -974,7 +983,7 @@ bool FGOutput::Load(Element* element)
{
string parameter="";
string name="";
int OutRate = 0;
double OutRate = 0.0;
unsigned int port;
Element *property_element;
@ -1003,7 +1012,7 @@ bool FGOutput::Load(Element* element)
BaseFilename = Filename = name;
}
if (!document->GetAttributeValue("rate").empty()) {
OutRate = (int)document->GetAttributeValueAsNumber("rate");
OutRate = document->GetAttributeValueAsNumber("rate");
} else {
OutRate = 1;
}
@ -1027,7 +1036,7 @@ bool FGOutput::Load(Element* element)
if (document->FindElementValue("position") == string("ON"))
SubSystems += ssPropagate;
if (document->FindElementValue("coefficients") == string("ON"))
SubSystems += ssCoefficients;
SubSystems += ssAeroFunctions;
if (document->FindElementValue("ground_reactions") == string("ON"))
SubSystems += ssGroundReactions;
if (document->FindElementValue("fcs") == string("ON"))
@ -1058,7 +1067,7 @@ bool FGOutput::Load(Element* element)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGOutput::SetRate(int rtHz)
void FGOutput::SetRate(double rtHz)
{
rtHz = rtHz>1000?1000:(rtHz<0?0:rtHz);
if (rtHz > 0) {
@ -1128,7 +1137,7 @@ void FGOutput::Debug(int from)
if (SubSystems & ssMoments) cout << " Moments parameters logged" << endl;
if (SubSystems & ssAtmosphere) cout << " Atmosphere parameters logged" << endl;
if (SubSystems & ssMassProps) cout << " Mass parameters logged" << endl;
if (SubSystems & ssCoefficients) cout << " Coefficient parameters logged" << endl;
if (SubSystems & ssAeroFunctions) cout << " Coefficient parameters logged" << endl;
if (SubSystems & ssPropagate) cout << " Propagate parameters logged" << endl;
if (SubSystems & ssGroundReactions) cout << " Ground parameters logged" << endl;
if (SubSystems & ssFCS) cout << " FCS parameters logged" << endl;

View file

@ -51,7 +51,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_OUTPUT "$Id: FGOutput.h,v 1.19 2010/10/31 04:48:46 jberndt Exp $"
#define ID_OUTPUT "$Id: FGOutput.h,v 1.22 2011/03/11 13:02:26 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -124,7 +124,7 @@ CLASS DOCUMENTATION
propulsion ON|OFF
</pre>
NOTE that Time is always output with the data.
@version $Id: FGOutput.h,v 1.19 2010/10/31 04:48:46 jberndt Exp $
@version $Id: FGOutput.h,v 1.22 2011/03/11 13:02:26 jberndt Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -140,6 +140,7 @@ public:
bool InitModel(void);
bool Run(void);
void Print(void);
void DelimitedOutput(const std::string&);
void SocketOutput(void);
void FlightGearSocketOutput(void);
@ -153,7 +154,7 @@ public:
void SetSubsystems(int tt) {SubSystems = tt;}
void SetOutputFileName(const std::string& fname) {Filename = fname;}
void SetDirectivesFile(const std::string& fname) {DirectivesFile = fname;}
void SetRate(int rt);
void SetRate(double rt);
void Enable(void) { enabled = true; }
void Disable(void) { enabled = false; }
bool Toggle(void) {enabled = !enabled; return enabled;}
@ -171,7 +172,7 @@ public:
/** Subsystem: Moments (= 32) */ ssMoments = 32,
/** Subsystem: Atmosphere (= 64) */ ssAtmosphere = 64,
/** Subsystem: Mass Properties (= 128) */ ssMassProps = 128,
/** Subsystem: Coefficients (= 256) */ ssCoefficients = 256,
/** Subsystem: Coefficients (= 256) */ ssAeroFunctions = 256,
/** Subsystem: Propagate (= 512) */ ssPropagate = 512,
/** Subsystem: Ground Reactions (= 1024) */ ssGroundReactions = 1024,
/** Subsystem: FCS (= 2048) */ ssFCS = 2048,

View file

@ -71,29 +71,35 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGPropagate.cpp,v 1.76 2011/01/16 16:10:59 bcoconni Exp $";
static const char *IdSrc = "$Id: FGPropagate.cpp,v 1.85 2011/04/03 19:24:58 jberndt Exp $";
static const char *IdHdr = ID_PROPAGATE;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex),
LocalTerrainRadius(0), SeaLevelRadius(0), VehicleRadius(0)
FGPropagate::FGPropagate(FGFDMExec* fdmex)
: FGModel(fdmex),
LocalTerrainRadius(0),
SeaLevelRadius(0),
VehicleRadius(0)
{
Debug(0);
Name = "FGPropagate";
gravType = gtWGS84;
vPQRdot.InitMatrix();
vPQRidot.InitMatrix();
vQtrndot = FGQuaternion(0,0,0);
vUVWdot.InitMatrix();
vUVWidot.InitMatrix();
vInertialVelocity.InitMatrix();
integrator_rotational_rate = eAdamsBashforth2;
integrator_translational_rate = eTrapezoidal;
integrator_rotational_position = eAdamsBashforth2;
integrator_translational_position = eTrapezoidal;
/// These define the indices use to select the various integrators.
// eNone = 0, eRectEuler, eTrapezoidal, eAdamsBashforth2, eAdamsBashforth3, eAdamsBashforth4};
integrator_rotational_rate = eRectEuler;
integrator_translational_rate = eAdamsBashforth2;
integrator_rotational_position = eRectEuler;
integrator_translational_position = eAdamsBashforth3;
VState.dqPQRidot.resize(4, FGColumnVector3(0.0,0.0,0.0));
VState.dqUVWidot.resize(4, FGColumnVector3(0.0,0.0,0.0));
@ -124,9 +130,9 @@ bool FGPropagate::InitModel(void)
VState.vLocation.SetEllipse(FDMExec->GetInertial()->GetSemimajor(), FDMExec->GetInertial()->GetSemiminor());
vOmegaEarth = FGColumnVector3( 0.0, 0.0, FDMExec->GetInertial()->omega() ); // Earth rotation vector
vPQRdot.InitMatrix();
vPQRidot.InitMatrix();
vQtrndot = FGQuaternion(0,0,0);
vUVWdot.InitMatrix();
vUVWidot.InitMatrix();
vInertialVelocity.InitMatrix();
VState.dqPQRidot.resize(4, FGColumnVector3(0.0,0.0,0.0));
@ -189,23 +195,13 @@ void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
VehicleRadius = GetRadius();
double radInv = 1.0/VehicleRadius;
// Refer to Stevens and Lewis, 1.5-14a, pg. 49.
// This is the rotation rate of the "Local" frame, expressed in the local frame.
FGColumnVector3 vOmegaLocal = FGColumnVector3(
radInv*vVel(eEast),
-radInv*vVel(eNorth),
-radInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
// Set the angular velocities of the body frame relative to the ECEF frame,
// expressed in the body frame. Effectively, this is:
// w_b/e = w_b/l + w_l/e
// expressed in the body frame.
VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
FGIC->GetQRadpsIC(),
FGIC->GetRRadpsIC() ) + Tl2b*vOmegaLocal;
FGIC->GetRRadpsIC() );
VState.vPQRi = VState.vPQR + Ti2b * vOmegaEarth;
VState.vPQRi_i = Tb2i * VState.vPQRi;
// Make an initial run and set past values
InitializeDerivatives();
@ -245,11 +241,10 @@ bool FGPropagate::Run(void)
CalculateUVWdot(); // Translational rate derivative
ResolveFrictionForces(dt); // Update rate derivatives with friction forces
CalculateQuatdot(); // Angular orientation derivative
CalculateUVW(); // Translational position derivative (velocities are integrated in the inertial frame)
// Propagate rotational / translational velocity, angular /translational position, respectively.
Integrate(VState.vPQRi_i, vPQRidot, VState.dqPQRidot, dt, integrator_rotational_rate); // ECI integration
Integrate(VState.vPQRi, vPQRidot, VState.dqPQRidot, dt, integrator_rotational_rate);
Integrate(VState.qAttitudeECI, vQtrndot, VState.dqQtrndot, dt, integrator_rotational_position);
Integrate(VState.vInertialPosition, VState.vInertialVelocity, VState.dqInertialVelocity, dt, integrator_translational_position);
Integrate(VState.vInertialVelocity, vUVWidot, VState.dqUVWidot, dt, integrator_translational_rate);
@ -278,12 +273,13 @@ bool FGPropagate::Run(void)
// orientation quaternion and vLocation vector.
UpdateBodyMatrices();
CalculateUVW(); // Translational position derivative (velocities are integrated in the inertial frame)
// Set auxililary state variables
RecomputeLocalTerrainRadius();
VehicleRadius = GetRadius(); // Calculate current aircraft radius from center of planet
VState.vPQRi = Ti2b * VState.vPQRi_i;
VState.vPQR = VState.vPQRi - Ti2b * vOmegaEarth;
VState.qAttitudeLocal = Tl2b.GetQuaternion();
@ -321,8 +317,8 @@ void FGPropagate::CalculatePQRdot(void)
// moments and the total inertial angular velocity expressed in the body
// frame.
vPQRdot = Jinv*(vMoments - VState.vPQRi*(J*VState.vPQRi));
vPQRidot = Tb2i * vPQRdot;
vPQRidot = Jinv*(vMoments - VState.vPQRi*(J*VState.vPQRi));
vPQRdot = vPQRidot - VState.vPQRi * (Ti2b * vOmegaEarth);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -605,7 +601,7 @@ void FGPropagate::ResolveFrictionForces(double dt)
vUVWdot += invMass * Fc;
vUVWidot += invMass * Tb2i * Fc;
vPQRdot += Jinv * Mc;
vPQRidot += Tb2i* Jinv * Mc;
vPQRidot += Jinv * Mc;
// Save the value of the Lagrange multipliers to accelerate the convergence
// of the Gauss-Seidel algorithm at next iteration.
@ -658,8 +654,7 @@ void FGPropagate::SetInertialVelocity(FGColumnVector3 Vi) {
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPropagate::SetInertialRates(FGColumnVector3 vRates) {
VState.vPQRi_i = vRates;
VState.vPQRi = Ti2b * VState.vPQRi_i;
VState.vPQRi = Ti2b * vRates;
VState.vPQR = VState.vPQRi - Ti2b * vOmegaEarth;
}
@ -681,7 +676,7 @@ void FGPropagate::InitializeDerivatives(void)
VState.dqQtrndot.clear();
for (int i=0; i<4; i++) {
VState.dqPQRidot.push_front(vPQRidot);
VState.dqUVWidot.push_front(vUVWdot);
VState.dqUVWidot.push_front(vUVWidot);
VState.dqInertialVelocity.push_front(VState.vInertialVelocity);
VState.dqQtrndot.push_front(vQtrndot);
}
@ -739,7 +734,6 @@ void FGPropagate::SetVState(const VehicleState& vstate)
vVel = Tb2l * VState.vUVW;
VState.vPQR = vstate.vPQR;
VState.vPQRi = VState.vPQR + Ti2b * vOmegaEarth;
VState.vPQRi_i = Tb2i * VState.vPQRi;
VState.vInertialPosition = vstate.vInertialPosition;
InitializeDerivatives();

View file

@ -49,7 +49,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_PROPAGATE "$Id: FGPropagate.h,v 1.55 2011/01/16 16:10:59 bcoconni Exp $"
#define ID_PROPAGATE "$Id: FGPropagate.h,v 1.58 2011/04/03 19:24:58 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -102,7 +102,7 @@ CLASS DOCUMENTATION
@endcode
@author Jon S. Berndt, Mathias Froehlich
@version $Id: FGPropagate.h,v 1.55 2011/01/16 16:10:59 bcoconni Exp $
@version $Id: FGPropagate.h,v 1.58 2011/04/03 19:24:58 jberndt Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -135,11 +135,6 @@ public:
units rad/sec */
FGColumnVector3 vPQRi;
/** The angular velocity vector for the vehicle body frame relative to the
ECI frame, expressed in the ECI frame.
units rad/sec */
FGColumnVector3 vPQRi_i;
/** The current orientation of the vehicle, that is, the orientation of the
body frame relative to the local, NED frame. */
FGQuaternion qAttitudeLocal;
@ -338,6 +333,10 @@ public:
*/
const FGColumnVector3& GetInertialPosition(void) const { return VState.vInertialPosition; }
/** Calculates and retrieves the velocity vector relative to the earth centered earth fixed (ECEF) frame.
*/
const FGColumnVector3 GetECEFVelocity(void) const {return Tb2ec * VState.vUVW; }
/** Returns the current altitude above sea level.
This function returns the altitude above sea level.
units ft
@ -581,8 +580,8 @@ public:
void RecomputeLocalTerrainRadius(void);
void NudgeBodyLocation(FGColumnVector3 deltaLoc) {
vDeltaXYZEC = Tb2ec*deltaLoc;
VState.vLocation -= vDeltaXYZEC;
VState.vInertialPosition -= Tb2i*deltaLoc;
VState.vLocation -= Tb2ec*deltaLoc;
}
struct LagrangeMultiplier {
@ -602,8 +601,7 @@ private:
struct VehicleState VState;
FGColumnVector3 vVel;
FGColumnVector3 vPQRdot;
FGColumnVector3 vPQRidot;
FGColumnVector3 vPQRdot, vPQRidot;
FGColumnVector3 vUVWdot, vUVWidot;
FGColumnVector3 vInertialVelocity;
FGColumnVector3 vLocation;

View file

@ -65,7 +65,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGPropulsion.cpp,v 1.43 2010/11/18 12:38:06 jberndt Exp $";
static const char *IdSrc = "$Id: FGPropulsion.cpp,v 1.45 2011/02/13 00:42:45 jberndt Exp $";
static const char *IdHdr = ID_PROPULSION;
extern short debug_lvl;
@ -194,14 +194,16 @@ bool FGPropulsion::GetSteadyState(void)
double currentThrust = 0, lastThrust = -1;
int steady_count = 0, j = 0;
bool steady = false;
bool TrimMode = FDMExec->GetTrimStatus();
vForces.InitMatrix();
vMoments.InitMatrix();
if (!FGModel::Run()) {
FDMExec->SetTrimStatus(true);
for (unsigned int i=0; i<numEngines; i++) {
// cout << " Finding steady state for engine " << i << endl;
Engines[i]->SetTrimMode(true);
steady=false;
steady_count=0;
j=0;
@ -225,9 +227,10 @@ bool FGPropulsion::GetSteadyState(void)
// }
vForces += Engines[i]->GetBodyForces(); // sum body frame forces
vMoments += Engines[i]->GetMoments(); // sum body frame moments
Engines[i]->SetTrimMode(false);
}
FDMExec->SetTrimStatus(TrimMode);
return false;
} else {
return true;
@ -648,13 +651,13 @@ void FGPropulsion::bind(void)
IsBound = true;
PropertyManager->Tie("propulsion/set-running", this, (iPMF)0, &FGPropulsion::InitRunning, false);
if (HaveTurbineEngine) {
PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter, true);
PropertyManager->Tie("propulsion/cutoff_cmd", this, (iPMF)0, &FGPropulsion::SetCutoff, true);
PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter, false);
PropertyManager->Tie("propulsion/cutoff_cmd", this, (iPMF)0, &FGPropulsion::SetCutoff, false);
}
if (HavePistonEngine) {
PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter, true);
PropertyManager->Tie("propulsion/magneto_cmd", this, (iPMF)0, &FGPropulsion::SetMagnetos, true);
PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter, false);
PropertyManager->Tie("propulsion/magneto_cmd", this, (iPMF)0, &FGPropulsion::SetMagnetos, false);
}
PropertyManager->Tie("propulsion/active_engine", this, (iPMF)&FGPropulsion::GetActiveEngine,

View file

@ -43,7 +43,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGActuator.cpp,v 1.14 2009/10/24 22:59:30 jberndt Exp $";
static const char *IdSrc = "$Id: FGActuator.cpp,v 1.17 2011/02/13 00:42:45 jberndt Exp $";
static const char *IdHdr = ID_ACTUATOR;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -114,10 +114,12 @@ bool FGActuator::Run(void )
// the Input will be further processed and the eventual Output
// will be overwritten from this perfect value.
if (lag != 0.0) Lag(); // models actuator lag
if (rate_limit != 0) RateLimit(); // limit the actuator rate
if (!fcs->GetTrimStatus()) {
if (lag != 0.0) Lag(); // models actuator lag
if (rate_limit != 0) RateLimit(); // limit the actuator rate
}
if (deadband_width != 0.0) Deadband();
if (hysteresis_width != 0.0) Hysteresis();
if (!fcs->GetTrimStatus() && hysteresis_width != 0.0) Hysteresis();
if (bias != 0.0) Bias(); // models a finite bias
if (fail_stuck) Output = PreviousOutput;
@ -187,6 +189,18 @@ void FGActuator::RateLimit(void)
void FGActuator::Deadband(void)
{
// Note: this function acts cumulatively on the "Output" parameter. So, "Output"
// is - for the purposes of this Deadband method - really the input to the
// method.
double input = Output;
if (input < -deadband_width/2.0) {
Output = (input + deadband_width/2.0);
} else if (input > deadband_width/2.0) {
Output = (input - deadband_width/2.0);
} else {
Output = 0.0;
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -232,9 +246,9 @@ void FGActuator::Debug(int from)
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
if (InputSigns[0] < 0)
cout << " INPUT: -" << InputNodes[0]->getName() << endl;
cout << " INPUT: -" << InputNames[0] << endl;
else
cout << " INPUT: " << InputNodes[0]->getName() << endl;
cout << " INPUT: " << InputNames[0] << endl;
if (IsOutput) {
for (unsigned int i=0; i<OutputNodes.size(); i++)

View file

@ -142,7 +142,7 @@ void FGDeadBand::Debug(int from)
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
cout << " INPUT: " << InputNodes[0]->getName() << endl;
cout << " INPUT: " << InputNodes[0]->GetName() << endl;
if (WidthPropertyNode != 0) {
cout << " DEADBAND WIDTH: " << WidthPropertyNode->GetName() << endl;
} else {

View file

@ -40,6 +40,7 @@ INCLUDES
#include "FGFCSComponent.h"
#include "input_output/FGPropertyManager.h"
#include "input_output/FGXMLElement.h"
#include "math/FGPropertyValue.h"
#include <iostream>
#include <cstdlib>
@ -47,7 +48,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGFCSComponent.cpp,v 1.29 2010/09/07 00:40:03 jberndt Exp $";
static const char *IdSrc = "$Id: FGFCSComponent.cpp,v 1.30 2011/04/05 20:20:21 andgi Exp $";
static const char *IdHdr = ID_FCSCOMPONENT;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -111,8 +112,6 @@ FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
Name = element->GetAttributeValue("name");
FGPropertyManager *tmp=0;
input_element = element->FindElement("input");
while (input_element) {
input = input_element->GetDataLine();
@ -122,14 +121,14 @@ FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
} else {
InputSigns.push_back( 1.0);
}
FGPropertyManager* node = 0L;
if (PropertyManager->HasNode(input)) {
tmp = PropertyManager->GetNode(input);
node = PropertyManager->GetNode(input);
InputNodes.push_back(new FGPropertyValue( node ));
} else {
tmp = 0L;
// cerr << fgcyan << "In component: " + Name + " property "
// + input + " is initially undefined." << reset << endl;
InputNodes.push_back(new FGPropertyValue( input,
PropertyManager ));
}
InputNodes.push_back( tmp );
InputNames.push_back( input );
input_element = element->FindNextElement("input");
@ -200,6 +199,9 @@ FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
FGFCSComponent::~FGFCSComponent()
{
Debug(1);
for (unsigned int i=0; i<InputNodes.size(); i++) {
delete InputNodes[i];
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -238,24 +240,6 @@ void FGFCSComponent::Clip(void)
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGFCSComponent::LateBind(void)
{
FGPropertyManager* node = 0L;
for (unsigned int i=0; i<InputNodes.size(); i++) {
if (!InputNodes[i]) {
if (PropertyManager->HasNode(InputNames[i])) {
node = PropertyManager->GetNode(InputNames[i]);
InputNodes[i] = node;
} else {
throw(InputNames[i]);
}
}
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// The old way of naming FCS components allowed upper or lower case, spaces, etc.

View file

@ -38,6 +38,7 @@ INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGJSBBase.h"
#include "math/FGPropertyValue.h"
#include <string>
#include <vector>
@ -45,7 +46,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_FCSCOMPONENT "$Id: FGFCSComponent.h,v 1.17 2010/08/21 22:56:11 jberndt Exp $"
#define ID_FCSCOMPONENT "$Id: FGFCSComponent.h,v 1.18 2011/04/05 20:20:21 andgi Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -80,7 +81,7 @@ CLASS DOCUMENTATION
- FGActuator
@author Jon S. Berndt
@version $Id: FGFCSComponent.h,v 1.17 2010/08/21 22:56:11 jberndt Exp $
@version $Id: FGFCSComponent.h,v 1.18 2011/04/05 20:20:21 andgi Exp $
@see Documentation for the FGFCS class, and for the configuration file class
*/
@ -98,7 +99,6 @@ public:
virtual bool Run(void);
virtual void SetOutput(void);
void LateBind(void);
double GetOutput (void) const {return Output;}
std::string GetName(void) const {return Name;}
std::string GetType(void) const { return Type; }
@ -111,7 +111,7 @@ protected:
std::vector <FGPropertyManager*> OutputNodes;
FGPropertyManager* ClipMinPropertyNode;
FGPropertyManager* ClipMaxPropertyNode;
std::vector <FGPropertyManager*> InputNodes;
std::vector <FGPropertyValue*> InputNodes;
std::vector <std::string> InputNames;
std::vector <float> InputSigns;
std::vector <double> output_array;

View file

@ -121,7 +121,7 @@ void FGFCSFunction::Debug(int from)
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
if (InputNodes.size()>0)
cout << " INPUT: " << InputNodes[0]->getName() << endl;
cout << " INPUT: " << InputNodes[0]->GetName() << endl;
// cout << " Function: " << endl;
if (IsOutput) {
for (unsigned int i=0; i<OutputNodes.size(); i++)

View file

@ -259,7 +259,7 @@ void FGFilter::Debug(int from)
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
cout << " INPUT: " << InputNodes[0]->getName() << endl;
cout << " INPUT: " << InputNodes[0]->GetName() << endl;
switch (FilterType) {
case eLag:
if (PropertySign[1] < 0.0) sgn="-";

View file

@ -209,9 +209,9 @@ void FGGain::Debug(int from)
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
if (InputSigns[0] < 0)
cout << " INPUT: -" << InputNodes[0]->getName() << endl;
cout << " INPUT: -" << InputNodes[0]->GetName() << endl;
else
cout << " INPUT: " << InputNodes[0]->getName() << endl;
cout << " INPUT: " << InputNodes[0]->GetName() << endl;
if (GainPropertyNode != 0) {
cout << " GAIN: " << GainPropertyNode->GetName() << endl;

View file

@ -188,7 +188,7 @@ void FGKinemat::Debug(int from)
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
cout << " INPUT: " << InputNodes[0]->getName() << endl;
cout << " INPUT: " << InputNodes[0]->GetName() << endl;
cout << " DETENTS: " << NumDetents << endl;
for (int i=0;i<NumDetents;i++) {
cout << " " << Detents[i] << " " << TransitionTimes[i] << endl;

View file

@ -189,9 +189,9 @@ void FGPID::Debug(int from)
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
if (InputSigns[0] < 0)
cout << " INPUT: -" << InputNodes[0]->getName() << endl;
cout << " INPUT: -" << InputNodes[0]->GetName() << endl;
else
cout << " INPUT: " << InputNodes[0]->getName() << endl;
cout << " INPUT: " << InputNodes[0]->GetName() << endl;
if (IsOutput) {
for (unsigned int i=0; i<OutputNodes.size(); i++)

View file

@ -293,9 +293,9 @@ void FGSensor::Debug(int from)
if (from == 0) { // Constructor
if (InputSigns.size() > 0) {
if (InputSigns[0] < 0)
cout << " INPUT: -" << InputNodes[0]->getName() << endl;
cout << " INPUT: -" << InputNodes[0]->GetName() << endl;
else
cout << " INPUT: " << InputNodes[0]->getName() << endl;
cout << " INPUT: " << InputNodes[0]->GetName() << endl;
}
if (bits != 0) {
if (quant_property.empty())

View file

@ -69,7 +69,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGSwitch.cpp,v 1.19 2009/10/24 22:59:30 jberndt Exp $";
static const char *IdSrc = "$Id: FGSwitch.cpp,v 1.20 2011/04/05 20:20:21 andgi Exp $";
static const char *IdHdr = ID_SWITCH;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -135,7 +135,13 @@ FGSwitch::FGSwitch(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
} else {
current_test->sign = 1.0;
}
current_test->OutputProp = PropertyManager->GetNode(value);
FGPropertyManager *node = PropertyManager->GetNode(value, false);
if (node) {
current_test->OutputProp = new FGPropertyValue(node);
} else {
current_test->OutputProp = new FGPropertyValue(value,
PropertyManager);
}
}
}
}
@ -151,6 +157,7 @@ FGSwitch::~FGSwitch()
{
for (unsigned int i=0; i<tests.size(); i++) {
for (unsigned int j=0; j<tests[i]->conditions.size(); j++) delete tests[i]->conditions[j];
delete tests[i]->OutputProp;
delete tests[i];
}

View file

@ -40,12 +40,13 @@ INCLUDES
#include "FGFCSComponent.h"
#include "input_output/FGXMLElement.h"
#include "math/FGCondition.h"
#include "math/FGPropertyValue.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_SWITCH "$Id: FGSwitch.h,v 1.13 2009/10/02 10:30:09 jberndt Exp $"
#define ID_SWITCH "$Id: FGSwitch.h,v 1.14 2011/04/05 20:20:21 andgi Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -124,7 +125,7 @@ ap/attitude_hold takes the value 1), the value of the switch component will be
whatever value fcs/roll-ap-error-summer is.
@author Jon S. Berndt
@version $Id: FGSwitch.h,v 1.13 2009/10/02 10:30:09 jberndt Exp $
@version $Id: FGSwitch.h,v 1.14 2011/04/05 20:20:21 andgi Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -156,12 +157,12 @@ private:
vector <FGCondition*> conditions;
eLogic Logic;
double OutputVal;
FGPropertyManager *OutputProp;
FGPropertyValue *OutputProp;
float sign;
double GetValue(void) {
if (OutputProp == 0L) return OutputVal;
else return OutputProp->getDoubleValue()*sign;
else return OutputProp->GetValue()*sign;
}
test(void) { // constructor for the test structure

View file

@ -50,7 +50,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGElectric.cpp,v 1.9 2010/08/21 17:13:48 jberndt Exp $";
static const char *IdSrc = "$Id: FGElectric.cpp,v 1.10 2011/03/10 01:35:25 dpculp Exp $";
static const char *IdHdr = ID_ELECTRIC;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -92,16 +92,21 @@ void FGElectric::Calculate(void)
RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
HP = PowerWatts * Throttle / hptowatts;
PowerAvailable = (HP * hptoftlbssec) - Thruster->GetPowerRequired();
Thruster->Calculate(PowerAvailable);
Thruster->Calculate(HP * hptoftlbssec);
RunPostFunctions();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGElectric::CalcFuelNeed(void)
{
return 0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGElectric::GetEngineLabels(const string& delimiter)
{
std::ostringstream buf;
@ -174,10 +179,4 @@ void FGElectric::Debug(int from)
}
}
double
FGElectric::CalcFuelNeed(void)
{
return 0;
}
} // namespace JSBSim

View file

@ -45,7 +45,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_ELECTRIC "$Id: FGElectric.h,v 1.9 2010/08/21 18:07:59 jberndt Exp $";
#define ID_ELECTRIC "$Id: FGElectric.h,v 1.10 2011/03/10 01:35:25 dpculp Exp $";
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -65,7 +65,7 @@ CLASS DOCUMENTATION
there is no battery model available, so this motor does not consume any
energy. There is no internal friction.
@author David Culp
@version "$Id: FGElectric.h,v 1.9 2010/08/21 18:07:59 jberndt Exp $"
@version "$Id: FGElectric.h,v 1.10 2011/03/10 01:35:25 dpculp Exp $"
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -81,7 +81,7 @@ public:
~FGElectric();
void Calculate(void);
double GetPowerAvailable(void) {return PowerAvailable;}
double GetPowerAvailable(void) {return (HP * hptoftlbssec);}
double getRPM(void) {return RPM;}
std::string GetEngineLabels(const std::string& delimiter);
std::string GetEngineValues(const std::string& delimiter);
@ -91,7 +91,6 @@ private:
double CalcFuelNeed(void);
double BrakeHorsePower;
double PowerAvailable;
// timestep
double dt;
@ -101,7 +100,7 @@ private:
double PowerWatts; // maximum engine power
double RPM; // revolutions per minute
double HP;
double HP; // engine output, in horsepower
void Debug(int from);
};

View file

@ -54,7 +54,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGEngine.cpp,v 1.40 2010/10/15 11:32:41 jberndt Exp $";
static const char *IdSrc = "$Id: FGEngine.cpp,v 1.42 2011/03/03 12:16:26 jberndt Exp $";
static const char *IdHdr = ID_ENGINE;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -151,6 +151,8 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
PropertyManager->Tie( property_name.c_str(), Thruster, &FGThruster::GetThrust);
property_name = base_property_name + "/fuel-flow-rate-pps";
PropertyManager->Tie( property_name.c_str(), this, &FGEngine::GetFuelFlowRate);
property_name = base_property_name + "/fuel-used-lbs";
PropertyManager->Tie( property_name.c_str(), this, &FGEngine::GetFuelUsedLbs);
PostLoad(engine_element, PropertyManager, to_string(EngineNumber));
@ -177,11 +179,11 @@ void FGEngine::ResetToIC(void)
FuelExpended = 0.0;
Starved = Running = Cranking = false;
PctPower = 0.0;
TrimMode = false;
FuelFlow_gph = 0.0;
FuelFlow_pph = 0.0;
FuelFlowRate = 0.0;
FuelFreeze = false;
FuelUsedLbs = 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -194,7 +196,7 @@ void FGEngine::ResetToIC(void)
void FGEngine::ConsumeFuel(void)
{
if (FuelFreeze) return;
if (TrimMode) return;
if (FDMExec->GetTrimStatus()) return;
unsigned int i;
double Fshortage, FuelNeeded;
@ -240,6 +242,7 @@ void FGEngine::ConsumeFuel(void)
Tank = Propulsion->GetTank(FeedList[i]);
Tank->Drain(FuelNeeded);
}
FuelUsedLbs += FuelToBurn;
}

View file

@ -55,7 +55,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_ENGINE "$Id: FGEngine.h,v 1.21 2010/08/21 17:13:48 jberndt Exp $"
#define ID_ENGINE "$Id: FGEngine.h,v 1.23 2011/03/03 12:16:26 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -118,7 +118,7 @@ CLASS DOCUMENTATION
documentation for engine and thruster classes.
</pre>
@author Jon S. Berndt
@version $Id: FGEngine.h,v 1.21 2010/08/21 17:13:48 jberndt Exp $
@version $Id: FGEngine.h,v 1.23 2011/03/03 12:16:26 jberndt Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -146,6 +146,7 @@ public:
virtual double getFuelFlow_gph () const {return FuelFlow_gph;}
virtual double getFuelFlow_pph () const {return FuelFlow_pph;}
virtual double GetFuelFlowRate(void) const {return FuelFlowRate;}
virtual double GetFuelUsedLbs(void) const {return FuelUsedLbs;}
virtual bool GetStarved(void) { return Starved; }
virtual bool GetRunning(void) const { return Running; }
virtual bool GetCranking(void) { return Cranking; }
@ -173,9 +174,6 @@ public:
virtual double GetPowerAvailable(void) {return 0.0;};
virtual bool GetTrimMode(void) {return TrimMode;}
virtual void SetTrimMode(bool state) {TrimMode = state;}
virtual FGColumnVector3& GetBodyForces(void);
virtual FGColumnVector3& GetMoments(void);
@ -219,12 +217,12 @@ protected:
bool Starved;
bool Running;
bool Cranking;
bool TrimMode;
bool FuelFreeze;
double FuelFlow_gph;
double FuelFlow_pph;
double FuelDensity;
double FuelUsedLbs;
FGFDMExec* FDMExec;
FGAtmosphere* Atmosphere;

View file

@ -53,7 +53,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGForce.cpp,v 1.14 2009/10/24 22:59:30 jberndt Exp $";
static const char *IdSrc = "$Id: FGForce.cpp,v 1.15 2011/02/17 00:20:52 jberndt Exp $";
static const char *IdHdr = ID_FORCE;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -62,9 +62,20 @@ FGForce::FGForce(FGFDMExec *FDMExec) :
fdmex(FDMExec),
ttype(tNone)
{
mT(1,1) = 1; //identity matrix
mT(2,2) = 1;
mT(3,3) = 1;
vFn.InitMatrix();
vMn.InitMatrix();
vH.InitMatrix();
vOrient.InitMatrix();
vXYZn.InitMatrix();
vActingXYZn.InitMatrix();
vFb.InitMatrix();
vM.InitMatrix();
vDXYZ.InitMatrix();
mT.InitMatrix(1., 0., 0.,
0., 1., 0.,
0., 0., 1.);
Debug(0);
}

View file

@ -53,7 +53,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGPiston.cpp,v 1.54 2010/11/30 12:17:10 jberndt Exp $";
static const char *IdSrc = "$Id: FGPiston.cpp,v 1.55 2011/03/10 01:35:25 dpculp Exp $";
static const char *IdHdr = ID_PISTON;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -442,8 +442,7 @@ void FGPiston::Calculate(void)
((FGPropeller*)Thruster)->SetFeather(FCS->GetPropFeather(EngineNumber));
}
PowerAvailable = (HP * hptoftlbssec) - Thruster->GetPowerRequired();
Thruster->Calculate(PowerAvailable);
Thruster->Calculate(HP * hptoftlbssec);
RunPostFunctions();
}
@ -872,7 +871,7 @@ string FGPiston::GetEngineLabels(const string& delimiter)
{
std::ostringstream buf;
buf << Name << " Power Available (engine " << EngineNumber << " in HP)" << delimiter
buf << Name << " Power Available (engine " << EngineNumber << " in ft-lbs/sec)" << delimiter
<< Name << " HP (engine " << EngineNumber << ")" << delimiter
<< Name << " equivalent ratio (engine " << EngineNumber << ")" << delimiter
<< Name << " MAP (engine " << EngineNumber << " in inHg)" << delimiter
@ -887,7 +886,7 @@ string FGPiston::GetEngineValues(const string& delimiter)
{
std::ostringstream buf;
buf << PowerAvailable << delimiter << HP << delimiter
buf << (HP * hptoftlbssec) << delimiter << HP << delimiter
<< equivalence_ratio << delimiter << ManifoldPressure_inHg << delimiter
<< Thruster->GetThrusterValues(EngineNumber, delimiter);

View file

@ -46,7 +46,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_PISTON "$Id: FGPiston.h,v 1.25 2010/11/30 12:17:10 jberndt Exp $";
#define ID_PISTON "$Id: FGPiston.h,v 1.26 2011/03/10 01:35:25 dpculp Exp $";
#define FG_MAX_BOOST_SPEEDS 3
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -182,7 +182,7 @@ CLASS DOCUMENTATION
@author Dave Luff (engine operational code)
@author David Megginson (initial porting and additional code)
@author Ron Jensen (additional engine code)
@version $Id: FGPiston.h,v 1.25 2010/11/30 12:17:10 jberndt Exp $
@version $Id: FGPiston.h,v 1.26 2011/03/10 01:35:25 dpculp Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -201,7 +201,7 @@ public:
std::string GetEngineValues(const std::string& delimiter);
void Calculate(void);
double GetPowerAvailable(void) const {return PowerAvailable;}
double GetPowerAvailable(void) const {return (HP * hptoftlbssec);}
double CalcFuelNeed(void);
void ResetToIC(void);
@ -227,7 +227,6 @@ private:
double FMEP;
double FMEPDynamic;
double FMEPStatic;
double PowerAvailable;
// timestep
double dt;

View file

@ -48,7 +48,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGPropeller.cpp,v 1.32 2010/10/21 03:27:40 jberndt Exp $";
static const char *IdSrc = "$Id: FGPropeller.cpp,v 1.33 2011/03/10 01:35:25 dpculp Exp $";
static const char *IdHdr = ID_PROPELLER;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -185,23 +185,22 @@ FGPropeller::~FGPropeller()
// We must be getting the aerodynamic velocity here, NOT the inertial velocity.
// We need the velocity with respect to the wind.
//
// Note that PowerAvailable is the excess power available after the drag of the
// propeller has been subtracted. At equilibrium, PowerAvailable will be zero -
// indicating that the propeller will not accelerate or decelerate.
// Remembering that Torque * omega = Power, we can derive the torque on the
// propeller and its acceleration to give a new RPM. The current RPM will be
// used to calculate thrust.
//
// Because RPM could be zero, we need to be creative about what RPM is stated as.
double FGPropeller::Calculate(double PowerAvailable)
double FGPropeller::Calculate(double EnginePower)
{
double omega, alpha, beta;
double omega, alpha, beta, PowerAvailable;
double Vel = fdmex->GetAuxiliary()->GetAeroUVW(eU);
double rho = fdmex->GetAtmosphere()->GetDensity();
double RPS = RPM/60.0;
PowerAvailable = EnginePower - GetPowerRequired();
// Calculate helical tip Mach
double Area = 0.25*Diameter*Diameter*M_PI;
double Vtip = RPS * Diameter * M_PI;

View file

@ -45,7 +45,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_PROPELLER "$Id: FGPropeller.h,v 1.16 2010/04/09 12:44:06 jberndt Exp $"
#define ID_PROPELLER "$Id: FGPropeller.h,v 1.17 2011/03/10 01:35:25 dpculp Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -141,7 +141,7 @@ CLASS DOCUMENTATION
<li>Various NACA Technical Notes and Reports</li>
</ul>
@author Jon S. Berndt
@version $Id: FGPropeller.h,v 1.16 2010/04/09 12:44:06 jberndt Exp $
@version $Id: FGPropeller.h,v 1.17 2011/03/10 01:35:25 dpculp Exp $
@see FGEngine
@see FGThruster
*/
@ -247,7 +247,7 @@ public:
accelerate the prop. It could be negative, dictating that the propeller
would be slowed.
@return the thrust in pounds */
double Calculate(double PowerAvailable);
double Calculate(double EnginePower);
FGColumnVector3 GetPFactor(void);
string GetThrusterLabels(int id, string delimeter);
string GetThrusterValues(int id, string delimeter);

View file

@ -49,7 +49,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGRocket.cpp,v 1.22 2010/12/30 13:35:09 jberndt Exp $";
static const char *IdSrc = "$Id: FGRocket.cpp,v 1.23 2011/01/24 13:01:56 jberndt Exp $";
static const char *IdHdr = ID_ROCKET;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -202,7 +202,7 @@ void FGRocket::ConsumeFuel(void)
double Fshortage=0, Oshortage=0, TanksWithFuel=0, TanksWithOxidizer=0;
if (FuelFreeze) return;
if (TrimMode) return;
if (FDMExec->GetTrimStatus()) return;
// Count how many assigned tanks have fuel for this engine at this time.
// If there is/are fuel tanks but no oxidizer tanks, this indicates

View file

@ -34,6 +34,8 @@ HISTORY
11/15/10 T.Kreitler treated flow solver bug, flow and torque calculations
simplified, tiploss influence removed from flapping angles
01/10/11 T.Kreitler changed to single rotor model
03/06/11 T.Kreitler added brake, clutch, and experimental free-wheeling-unit,
reasonable estimate for inflowlag
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
@ -56,7 +58,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGRotor.cpp,v 1.11 2011/01/17 22:09:59 jberndt Exp $";
static const char *IdSrc = "$Id: FGRotor.cpp,v 1.12 2011/03/10 01:35:25 dpculp Exp $";
static const char *IdHdr = ID_ROTOR;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -109,7 +111,11 @@ FGRotor::FGRotor(FGFDMExec *exec, Element* rotor_element, int num)
// control
ControlMap(eMainCtrl),
CollectiveCtrl(0.0), LateralCtrl(0.0), LongitudinalCtrl(0.0)
CollectiveCtrl(0.0), LateralCtrl(0.0), LongitudinalCtrl(0.0),
BrakeCtrlNorm(0.0), MaxBrakePower(0.0),
// free-wheeling-unit (FWU)
FreeWheelPresent(0), FreeWheelThresh(0.0), FreeWheelTransmission(0.0)
{
FGColumnVector3 location(0.0, 0.0, 0.0), orientation(0.0, 0.0, 0.0);
@ -190,6 +196,9 @@ FGRotor::FGRotor(FGFDMExec *exec, Element* rotor_element, int num)
// calculation would cause jumps too. 1Hz seems sufficient.
damp_hagl = Filter(1.0,dt);
// avoid too abrupt changes in power transmission
FreeWheelLag = Filter(200.0,dt);
// enable import-export
BindModel();
@ -248,7 +257,7 @@ double FGRotor::ConfigValue(Element* el, const string& ename, double default_val
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// 1. read configuration and try to fill holes, ymmv
// 2. calculate derived parameters and transforms
// 2. calculate derived parameters
void FGRotor::Configure(Element* rotor_element)
{
@ -279,22 +288,24 @@ void FGRotor::Configure(Element* rotor_element)
estimate = sqr(BladeChord) * sqr(Radius - HingeOffset) * 0.57;
BladeFlappingMoment = ConfigValueConv(rotor_element, "flappingmoment", estimate, "SLUG*FT2");
BladeFlappingMoment = Constrain(0.001, BladeFlappingMoment, 1e9);
BladeFlappingMoment = Constrain(1.0e-6, BladeFlappingMoment, 1e9);
// guess mass from moment of a thin stick, and multiply by the blades cg distance
estimate = ( 3.0 * BladeFlappingMoment / sqr(Radius) ) * (0.45 * Radius) ;
BladeMassMoment = ConfigValue(rotor_element, "massmoment", estimate); // unit is slug-ft
BladeMassMoment = Constrain(0.001, BladeMassMoment, 1e9);
TipLossB = ConfigValue(rotor_element, "tiplossfactor", 1.0, silent);
estimate = 1.1 * BladeFlappingMoment * BladeNum;
PolarMoment = ConfigValueConv(rotor_element, "polarmoment", estimate, "SLUG*FT2");
PolarMoment = Constrain(0.001, PolarMoment, 1e9);
PolarMoment = Constrain(1e-6, PolarMoment, 1e9);
InflowLag = ConfigValue(rotor_element, "inflowlag", 0.2, yell); // fixme, depends on size
InflowLag = Constrain(1e-6, InflowLag, 2.0);
// "inflowlag" is treated further down.
TipLossB = ConfigValue(rotor_element, "tiplossfactor", 1.0, silent);
estimate = 0.01 * PolarMoment ; // guesses for huey, bo105 20-30hp
MaxBrakePower = ConfigValueConv(rotor_element, "maxbrakepower", estimate, "HP");
MaxBrakePower *= hptoftlbssec;
// ground effect
if (rotor_element->FindElement("cgroundeffect")) {
@ -309,6 +320,17 @@ void FGRotor::Configure(Element* rotor_element)
GroundEffectExp = ConfigValue(rotor_element, "groundeffectexp", 0.0);
GroundEffectShift = ConfigValueConv(rotor_element, "groundeffectshift", 0.0, "FT");
// handle optional free-wheeling-unit (FWU)
FreeWheelPresent = 0;
FreeWheelTransmission = 1.0;
if (rotor_element->FindElement("freewheelthresh")) {
FreeWheelThresh = rotor_element->FindElementValueAsNumber("freewheelthresh");
if (FreeWheelThresh > 1.0) {
FreeWheelPresent = 1;
FreeWheelTransmission = 0.0;
}
}
// precalc often used powers
R[0]=1.0; R[1]=Radius; R[2]=R[1]*R[1]; R[3]=R[2]*R[1]; R[4]=R[3]*R[1];
B[0]=1.0; B[1]=TipLossB; B[2]=B[1]*B[1]; B[3]=B[2]*B[1]; B[4]=B[3]*B[1];
@ -317,6 +339,13 @@ void FGRotor::Configure(Element* rotor_element)
LockNumberByRho = LiftCurveSlope * BladeChord * R[4] / BladeFlappingMoment;
Solidity = BladeNum * BladeChord / (M_PI * Radius);
// estimate inflow lag, see /GE49/ eqn(1)
double omega_tmp = (NominalRPM/60.0)*2.0*M_PI;
estimate = 16.0/(LockNumberByRho*rho * omega_tmp ); // 16/(gamma*Omega)
// printf("# Est. InflowLag: %f\n", estimate);
InflowLag = ConfigValue(rotor_element, "inflowlag", estimate, yell);
InflowLag = Constrain(1.0e-6, InflowLag, 2.0);
return;
} // Configure
@ -362,7 +391,7 @@ FGColumnVector3 FGRotor::fus_angvel_body2ca( const FGColumnVector3 &pqr)
av_w_fus(eP)= av_s_fus(eP)*cos(beta_orient) + av_s_fus(eQ)*sin(beta_orient);
av_w_fus(eQ)= - av_s_fus(eP)*sin(beta_orient) + av_s_fus(eQ)*cos(beta_orient);
av_w_fus(eR)= av_s_fus(eR);
return av_w_fus;
}
@ -382,7 +411,7 @@ void FGRotor::calc_flow_and_thrust( double theta_0, double Uw, double Ww,
double ct_over_sigma = 0.0;
double c0, ct_l, ct_t0, ct_t1;
double mu2;
double mu2;
mu = Uw/(Omega*Radius); // /SH79/ eqn(24)
mu2 = sqr(mu);
@ -390,7 +419,7 @@ void FGRotor::calc_flow_and_thrust( double theta_0, double Uw, double Ww,
ct_t0 = (1.0/3.0*B[3] + 1.0/2.0 * TipLossB*mu2 - 4.0/(9.0*M_PI) * mu*mu2 ) * theta_0;
ct_t1 = (1.0/4.0*B[4] + 1.0/4.0 * B[2]*mu2) * BladeTwist;
ct_l = (1.0/2.0*B[2] + 1.0/4.0 * mu2) * lambda; // first time
ct_l = (1.0/2.0*B[2] + 1.0/4.0 * mu2) * lambda; // first time
c0 = (LiftCurveSlope/2.0)*(ct_l + ct_t0 + ct_t1) * Solidity;
c0 = c0 / ( 2.0 * sqrt( sqr(mu) + sqr(lambda) ) + 1e-15);
@ -473,7 +502,7 @@ void FGRotor::calc_flapping_angles(double theta_0, const FGColumnVector3 &pqr_fu
void FGRotor::calc_drag_and_side_forces(double theta_0)
{
double cy_over_sigma ;
double cy_over_sigma;
double t075 = theta_0 + 0.75 * BladeTwist;
H_drag = Thrust * a_dw;
@ -494,7 +523,7 @@ void FGRotor::calc_drag_and_side_forces(double theta_0)
// Simplified version of /SH79/ eqn(36). Uses an estimate for blade drag
// (a new config parameter to come...).
// From "Bramwell's Helicopter Dynamics" ­ second edition, eqn(3.43) and (3.44)
// From "Bramwell's Helicopter Dynamics", second edition, eqn(3.43) and (3.44)
void FGRotor::calc_torque(double theta_0)
{
@ -560,7 +589,7 @@ void FGRotor::CalcStatePart1(void)
FGColumnVector3 vHub_ca, avFus_ca;
double h_agl_ft, filtered_hagl = 0.0;
double ge_factor = 1.0;
double ge_factor = 1.0;
// fetch needed values from environment
Vt = fdmex->GetAuxiliary()->GetVt(); // total vehicle velocity including wind
@ -637,18 +666,52 @@ void FGRotor::CalcStatePart2(double PowerAvailable)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGRotor::GetPowerRequired(void)
{
CalcStatePart1();
PowerRequired = Torque * Omega;
return PowerRequired;
// Simulation of a free-wheeling-unit (FWU). Might need improvements.
void FGRotor::calc_freewheel_state(double p_source, double p_load) {
// engine is off/detached, release.
if (p_source<1e-3) {
FreeWheelTransmission = 0.0;
return;
}
// engine is driving the rotor, engage.
if (p_source >= p_load) {
FreeWheelTransmission = 1.0;
return;
}
// releases if engine is detached, but stays calm if
// the load changes due to rotor dynamics.
if (p_source > 0.0 && p_load/(p_source+0.1) > FreeWheelThresh ) {
FreeWheelTransmission = 0.0;
return;
}
return;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGRotor::Calculate(double PowerAvailable)
double FGRotor::Calculate(double EnginePower)
{
CalcStatePart2(PowerAvailable);
double FWmult = 1.0;
double DeltaPower;
CalcStatePart1();
PowerRequired = Torque * Omega + BrakeCtrlNorm * MaxBrakePower;
if (FreeWheelPresent) {
calc_freewheel_state(EnginePower * ClutchCtrlNorm, PowerRequired);
FWmult = FreeWheelLag.execute(FreeWheelTransmission);
}
DeltaPower = EnginePower * ClutchCtrlNorm * FWmult - PowerRequired;
CalcStatePart2(DeltaPower);
return Thrust;
}
@ -702,7 +765,7 @@ bool FGRotor::BindModel(void)
property_name = base_property_name + "/phi-downwash-rad";
PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetPhiDW );
switch (ControlMap) {
case eTailCtrl:
property_name = base_property_name + "/antitorque-ctrl-rad";
@ -725,6 +788,11 @@ bool FGRotor::BindModel(void)
PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetLongitudinalCtrl, &FGRotor::SetLongitudinalCtrl);
}
property_name = base_property_name + "/brake-ctrl-norm";
PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetBrakeCtrl, &FGRotor::SetBrakeCtrl);
property_name = base_property_name + "/free-wheel-transmission";
PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetFreeWheelTransmission);
if (ExternalRPM) {
if (RPMdefinition == -1) {
property_name = base_property_name + "/x-rpm-dict";
@ -826,6 +894,7 @@ void FGRotor::Debug(int from)
cout << " Tip Loss = " << TipLossB << endl;
cout << " Lock Number = " << LockNumberByRho * 0.002356 << " (SL)" << endl;
cout << " Solidity = " << Solidity << endl;
cout << " Max Brake Power = " << MaxBrakePower/hptoftlbssec << " HP" << endl;
switch (ControlMap) {
case eTailCtrl: ControlMapName = "Tail Rotor"; break;
@ -834,6 +903,12 @@ void FGRotor::Debug(int from)
}
cout << " Control Mapping = " << ControlMapName << endl;
if (FreeWheelPresent) {
cout << " Free Wheel Threshold = " << FreeWheelThresh << endl;
} else {
cout << " No FWU present" << endl;
}
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification

View file

@ -27,6 +27,7 @@ HISTORY
--------------------------------------------------------------------------------
01/01/10 T.Kreitler test implementation
01/10/11 T.Kreitler changed to single rotor model
03/06/11 T.Kreitler added brake, clutch, and experimental free-wheeling-unit
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
@ -45,7 +46,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_ROTOR "$Id: FGRotor.h,v 1.8 2011/01/17 22:09:59 jberndt Exp $"
#define ID_ROTOR "$Id: FGRotor.h,v 1.9 2011/03/10 01:35:25 dpculp Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -76,12 +77,15 @@ CLASS DOCUMENTATION
<polarmoment unit="{MOMENT}"> {number} </polarmoment>
<inflowlag> {number} </inflowlag>
<tiplossfactor> {number} </tiplossfactor>
<maxbrakepower unit="{POWER}"> {number} </maxbrakepower>
<controlmap> {MAIN|TAIL|TANDEM} </controlmap>
<ExternalRPM> {number} </ExternalRPM>
<groundeffectexp> {number} </groundeffectexp>
<groundeffectshift unit="{LENGTH}"> {number} </groundeffectshift>
<freewheelthresh> {number} </freewheelthresh>
</rotor>
// LENGTH means any of the supported units, same for ANGLE and MOMENT.
@ -108,10 +112,11 @@ CLASS DOCUMENTATION
\<massmoment> - Blade mass moment. Mass of a single blade times the blade's
cg-distance from the hub, optional.
\<polarmoment> - Moment of inertia for the whole rotor disk, optional.
\<inflowlag> - Rotor inflow time constant, sec. Smaller values yield to
quicker responses to control input (defaults to 0.2).
\<inflowlag> - Rotor inflow time constant, sec. Smaller values yield to quicker
responses (typical values for main rotor: 0.1 - 0.2 s).
\<tiplossfactor> - Tip-loss factor. The Blade fraction that produces lift.
Value usually ranges between 0.95 - 1.0, optional (B).
\<maxbrakepower> - Rotor brake, 20-30 hp should work for a mid size helicopter.
\<controlmap> - Defines the control inputs used (see notes).
\<ExternalRPM> - Links the rotor to another rotor, or an user controllable property.
@ -125,6 +130,10 @@ CLASS DOCUMENTATION
Omitting or setting to 0.0 disables the effect calculation.
\<groundeffectshift> - Further adjustment of ground effect, approx. hub height or slightly above.
\<freewheelthresh> - Ratio of thruster power to engine power. The FWU will release when above
the threshold. The value shouldn't be too close to 1.0, 1.5 seems ok.
0 disables this feature, which is also the default.
</pre>
<h3>Notes:</h3>
@ -165,8 +174,6 @@ CLASS DOCUMENTATION
<h4>- Engine issues -</h4>
Currently the rotor can only be driven with piston and electrical engines. An adaption
for the turboprop engine might become available in the future.
In order to keep the rotor speed constant, use of a RPM-Governor system is
encouraged (see examples).
@ -188,11 +195,13 @@ CLASS DOCUMENTATION
<dt>/AM50/</dt><dd>Amer, Kenneth B.,"Theory of Helicopter Damping in Pitch or Roll and a
Comparison With Flight Measurements", NACA TN-2136, 1950.</dd>
<dt>/TA77/</dt><dd>Talbot, Peter D., Corliss, Lloyd D., "A Mathematical Force and Moment
Model of a UH-1H Helicopter for Flight Dynamics Simulations", NASA TM-73,254, 1977.</dd>
Model of a UH-1H Helicopter for Flight Dynamics Simulations", NASA TM-73,254, 1977.</dd>
<dt>/GE49/</dt><dd>Gessow, Alfred, Amer, Kenneth B. "An Introduction to the Physical
Aspects of Helicopter Stability", NACA TN-1982, 1949.</dd>
</dl>
@author Thomas Kreitler
@version $Id: FGRotor.h,v 1.8 2011/01/17 22:09:59 jberndt Exp $
@version $Id: FGRotor.h,v 1.9 2011/03/10 01:35:25 dpculp Exp $
*/
@ -216,14 +225,11 @@ public:
/// Destructor for FGRotor
~FGRotor();
/** Returns the power required by the rotor. Well, to achieve this the rotor
is cycled through the whole machinery, yielding to a new state.
(hmm, sort of a huge side effect)
*/
double GetPowerRequired(void);
/** Returns the power required by the rotor. */
double GetPowerRequired(void)const { return PowerRequired; }
/** Returns the scalar thrust of the rotor, and adjusts the RPM value. */
double Calculate(double PowerAvailable);
double Calculate(double EnginePower);
/// Retrieves the RPMs of the rotor.
@ -257,6 +263,8 @@ public:
double GetCT(void) const { return C_T; }
/// Retrieves the torque
double GetTorque(void) const { return Torque; }
/// Retrieves the state of the free-wheeling-unit (FWU).
double GetFreeWheelTransmission(void) const { return FreeWheelTransmission; }
/// Downwash angle - currently only valid for a rotor that spins horizontally
double GetThetaDW(void) const { return theta_downwash; }
@ -269,6 +277,8 @@ public:
double GetLateralCtrl(void) const { return LateralCtrl; }
/// Retrieves the longitudinal control input in radians.
double GetLongitudinalCtrl(void) const { return LongitudinalCtrl; }
/// Retrieves the normalized brake control input.
double GetBrakeCtrl(void) const { return BrakeCtrlNorm; }
/// Sets the collective control input in radians.
void SetCollectiveCtrl(double c) { CollectiveCtrl = c; }
@ -276,6 +286,8 @@ public:
void SetLateralCtrl(double c) { LateralCtrl = c; }
/// Sets the longitudinal control input in radians.
void SetLongitudinalCtrl(double c) { LongitudinalCtrl = c; }
/// Sets the normalized brake control input.
void SetBrakeCtrl(double c) { BrakeCtrlNorm = c; }
// Stubs. Only main rotor RPM is returned
string GetThrusterLabels(int id, string delimeter);
@ -303,6 +315,8 @@ private:
void calc_drag_and_side_forces(double theta_0);
void calc_torque(double theta_0);
void calc_freewheel_state(double pwr_in, double pwr_out);
// transformations
FGColumnVector3 hub_vel_body2ca( const FGColumnVector3 &uvw, const FGColumnVector3 &pqr,
double a_ic = 0.0 , double b_ic = 0.0 );
@ -380,6 +394,15 @@ private:
double LateralCtrl;
double LongitudinalCtrl;
double BrakeCtrlNorm, MaxBrakePower;
// free-wheeling-unit (FWU)
int FreeWheelPresent; // 'installed' or not
double FreeWheelThresh; // when to release
Filter FreeWheelLag;
double FreeWheelTransmission; // state, 0: free, 1:locked
};
}

View file

@ -45,7 +45,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGThruster.cpp,v 1.13 2010/08/21 22:56:11 jberndt Exp $";
static const char *IdSrc = "$Id: FGThruster.cpp,v 1.14 2011/03/10 01:35:25 dpculp Exp $";
static const char *IdHdr = ID_THRUSTER;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -66,6 +66,7 @@ FGThruster::FGThruster(FGFDMExec *FDMExec, Element *el, int num ): FGForce(FDMEx
GearRatio = 1.0;
ReverserAngle = 0.0;
ClutchCtrlNorm = 1.0;
EngineNum = num;
PropertyManager = FDMExec->GetPropertyManager();
@ -98,6 +99,13 @@ FGThruster::FGThruster(FGFDMExec *FDMExec, Element *el, int num ): FGForce(FDMEx
&FGThruster::SetReverserAngle);
}
if (el->GetName() == "rotor") // At this time only a rotor can have a clutch.
{
property_name = base_property_name + "/clutch-ctrl-norm";
PropertyManager->Tie( property_name.c_str(), (FGThruster *)this, &FGThruster::GetClutchCtrl,
&FGThruster::SetClutchCtrl);
}
Debug(0);
}

View file

@ -46,7 +46,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_THRUSTER "$Id: FGThruster.h,v 1.15 2009/10/24 22:59:30 jberndt Exp $"
#define ID_THRUSTER "$Id: FGThruster.h,v 1.16 2011/03/10 01:35:25 dpculp Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -74,7 +74,7 @@ CLASS DOCUMENTATION
1.57 (pi/2) results in no thrust at all.
@author Jon Berndt
@version $Id: FGThruster.h,v 1.15 2009/10/24 22:59:30 jberndt Exp $
@version $Id: FGThruster.h,v 1.16 2011/03/10 01:35:25 dpculp Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -105,6 +105,8 @@ public:
string GetName(void) {return Name;}
void SetReverserAngle(double angle) {ReverserAngle = angle;}
double GetReverserAngle(void) const {return ReverserAngle;}
double GetClutchCtrl(void) const { return ClutchCtrlNorm; }
void SetClutchCtrl(double c) { ClutchCtrlNorm = c; }
virtual double GetRPM(void) const { return 0.0; };
double GetGearRatio(void) {return GearRatio; }
virtual string GetThrusterLabels(int id, string delimeter);
@ -119,6 +121,7 @@ protected:
double GearRatio;
double ThrustCoeff;
double ReverserAngle;
double ClutchCtrlNorm;
int EngineNum;
FGPropertyManager* PropertyManager;
virtual void Debug(int from);

View file

@ -51,7 +51,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGTurbine.cpp,v 1.29 2010/08/31 04:01:32 jberndt Exp $";
static const char *IdSrc = "$Id: FGTurbine.cpp,v 1.31 2011/03/03 12:16:26 jberndt Exp $";
static const char *IdHdr = ID_TURBINE;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -74,6 +74,7 @@ FGTurbine::FGTurbine(FGFDMExec* exec, Element *el, int engine_number)
BypassRatio = BleedDemand = 0.0;
IdleThrustLookup = MilThrustLookup = MaxThrustLookup = InjectionLookup = 0;
N1_spinup = 1.0; N2_spinup = 3.0;
EPR = 1.0;
ResetToIC();
@ -96,6 +97,9 @@ FGTurbine::~FGTurbine()
void FGTurbine::ResetToIC(void)
{
FGEngine::ResetToIC();
N1 = N2 = 0.0;
N2norm = 0.0;
correctedTSFC = TSFC;
@ -534,6 +538,8 @@ void FGTurbine::bindmodel()
PropertyManager->Tie( property_name.c_str(), &Seized);
property_name = base_property_name + "/stalled";
PropertyManager->Tie( property_name.c_str(), &Stalled);
property_name = base_property_name + "/bleed-factor";
PropertyManager->Tie( property_name.c_str(), (FGTurbine*)this, &FGTurbine::GetBleedDemand, &FGTurbine::SetBleedDemand);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

125
src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp Normal file → Executable file
View file

@ -34,6 +34,7 @@ based on parameters given in the engine config file for this class
HISTORY
--------------------------------------------------------------------------------
05/14/2004 Created
02/08/2011 T. Kreitler, added rotor support
//JVK (mark)
@ -45,6 +46,7 @@ INCLUDES
#include <sstream>
#include "FGTurboProp.h"
#include "FGPropeller.h"
#include "FGRotor.h"
#include "models/FGPropulsion.h"
#include "models/FGAuxiliary.h"
@ -52,7 +54,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGTurboProp.cpp,v 1.17 2010/08/21 17:13:48 jberndt Exp $";
static const char *IdSrc = "$Id: FGTurboProp.cpp,v 1.19 2011/03/10 01:35:25 dpculp Exp $";
static const char *IdHdr = ID_TURBOPROP;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -64,8 +66,10 @@ FGTurboProp::FGTurboProp(FGFDMExec* exec, Element *el, int engine_number)
ITT_N1(NULL), EnginePowerRPM_N1(NULL), EnginePowerVC(NULL)
{
SetDefaults();
thrusterType = Thruster->GetType();
Load(exec, el);
bindmodel();
Debug(0);
}
@ -101,6 +105,7 @@ bool FGTurboProp::Load(FGFDMExec* exec, Element *el)
MaxN2 = el->FindElementValueAsNumber("maxn2");
if (el->FindElement("betarangeend"))
BetaRangeThrottleEnd = el->FindElementValueAsNumber("betarangeend")/100.0;
BetaRangeThrottleEnd = Constrain(0.0, BetaRangeThrottleEnd, 0.99999);
if (el->FindElement("reversemaxpower"))
ReverseMaxPower = el->FindElementValueAsNumber("reversemaxpower")/100.0;
@ -146,10 +151,10 @@ bool FGTurboProp::Load(FGFDMExec* exec, Element *el)
delay=1;
N1_factor = MaxN1 - IdleN1;
N2_factor = MaxN2 - IdleN2;
OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
OilTemp_degK = Auxiliary->GetTAT_C() + 273.0;
if (IdleFF==-1) IdleFF = pow(MilThrust, 0.2) * 107.0; // just an estimate
cout << "ENG POWER:" << EnginePowerRPM_N1->GetValue(1200,90) << "\n";
// cout << "ENG POWER:" << EnginePowerRPM_N1->GetValue(1200,90) << endl;
return true;
}
@ -162,29 +167,29 @@ void FGTurboProp::Calculate(void)
{
RunPreFunctions();
TAT = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556;
TAT = Auxiliary->GetTAT_C();
dt = FDMExec->GetDeltaT() * Propulsion->GetRate();
ThrottleCmd = FCS->GetThrottleCmd(EngineNumber);
Throttle = FCS->GetThrottlePos(EngineNumber);
Prop_RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
if (Thruster->GetType() == FGThruster::ttPropeller) {
RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
if (thrusterType == FGThruster::ttPropeller) {
((FGPropeller*)Thruster)->SetAdvance(FCS->GetPropAdvance(EngineNumber));
((FGPropeller*)Thruster)->SetFeather(FCS->GetPropFeather(EngineNumber));
((FGPropeller*)Thruster)->SetReverse(Reversed);
if (Reversed) {
((FGPropeller*)Thruster)->SetReverseCoef(ThrottleCmd);
((FGPropeller*)Thruster)->SetReverseCoef(Throttle);
} else {
((FGPropeller*)Thruster)->SetReverseCoef(0.0);
}
}
if (Reversed) {
if (ThrottleCmd < BetaRangeThrottleEnd) {
ThrottleCmd = 0.0; // idle when in Beta-range
} else {
// when reversed:
ThrottleCmd = (ThrottleCmd-BetaRangeThrottleEnd)/(1-BetaRangeThrottleEnd) * ReverseMaxPower;
if (Reversed) {
if (Throttle < BetaRangeThrottleEnd) {
Throttle = 0.0; // idle when in Beta-range
} else {
// when reversed:
Throttle = (Throttle-BetaRangeThrottleEnd)/(1-BetaRangeThrottleEnd) * ReverseMaxPower;
}
}
}
@ -223,36 +228,41 @@ void FGTurboProp::Calculate(void)
StartTime=-1;
}
if (Condition < 1) {
if (Ielu_max_torque > 0
&& -Ielu_max_torque > ((FGPropeller*)(Thruster))->GetTorque()
&& ThrottleCmd >= OldThrottle ) {
ThrottleCmd = OldThrottle - 0.1 * dt; //IELU down
Ielu_intervent = true;
} else if (Ielu_max_torque > 0 && Ielu_intervent && ThrottleCmd >= OldThrottle) {
ThrottleCmd = OldThrottle;
ThrottleCmd = OldThrottle + 0.05 * dt; //IELU up
Ielu_intervent = true;
// limiter intervention wanted?
if (Ielu_max_torque > 0.0) {
double torque = 0.0;
if (thrusterType == FGThruster::ttPropeller) {
torque = ((FGPropeller*)(Thruster))->GetTorque();
} else if (thrusterType == FGThruster::ttRotor) {
torque = ((FGRotor*)(Thruster))->GetTorque();
}
if (Condition < 1) {
if ( abs(torque) > Ielu_max_torque && Throttle >= OldThrottle ) {
Throttle = OldThrottle - 0.1 * dt; //IELU down
Ielu_intervent = true;
} else if ( Ielu_intervent && Throttle >= OldThrottle) {
Throttle = OldThrottle + 0.05 * dt; //IELU up
Ielu_intervent = true;
} else {
Ielu_intervent = false;
}
} else {
Ielu_intervent = false;
}
} else {
Ielu_intervent = false;
OldThrottle = Throttle;
}
OldThrottle = ThrottleCmd;
switch (phase) {
case tpOff: Eng_HP = Off(); break;
case tpRun: Eng_HP = Run(); break;
case tpSpinUp: Eng_HP = SpinUp(); break;
case tpStart: Eng_HP = Start(); break;
default: Eng_HP = 0;
case tpOff: HP = Off(); break;
case tpRun: HP = Run(); break;
case tpSpinUp: HP = SpinUp(); break;
case tpStart: HP = Start(); break;
default: HP = 0;
}
//printf ("EngHP: %lf / Requi: %lf\n",Eng_HP,Prop_Required_Power);
PowerAvailable = (Eng_HP * hptoftlbssec) - Thruster->GetPowerRequired();
Thruster->Calculate(PowerAvailable);
Thruster->Calculate(HP * hptoftlbssec);
RunPostFunctions();
}
@ -280,7 +290,7 @@ double FGTurboProp::Off(void)
ConsumeFuel(); // for possible setting Starved = false when fuel tank
// is refilled (fuel crossfeed etc.)
if (Prop_RPM>5) return -0.012; // friction in engine when propeller spining (estimate)
if (RPM>5) return -0.012; // friction in engine when propeller spining (estimate)
return 0.0;
}
@ -293,9 +303,9 @@ double FGTurboProp::Run(void)
//---
double old_N1 = N1;
N1 = ExpSeek(&N1, IdleN1 + ThrottleCmd * N1_factor, Idle_Max_Delay, Idle_Max_Delay * 2.4);
N1 = ExpSeek(&N1, IdleN1 + Throttle * N1_factor, Idle_Max_Delay, Idle_Max_Delay * 2.4);
EngPower_HP = EnginePowerRPM_N1->GetValue(Prop_RPM,N1);
EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
EngPower_HP *= EnginePowerVC->GetValue();
if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
@ -346,7 +356,7 @@ double FGTurboProp::SpinUp(void)
OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6; //from MPa to psi
NozzlePosition = 1.0;
EngPower_HP = EnginePowerRPM_N1->GetValue(Prop_RPM,N1);
EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
EngPower_HP *= EnginePowerVC->GetValue();
if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
@ -366,13 +376,15 @@ double FGTurboProp::SpinUp(void)
double FGTurboProp::Start(void)
{
double EngPower_HP,eff_coef;
double EngPower_HP = 0.0;
double eff_coef;
EngStarting = false;
if ((N1 > 15.0) && !Starved) { // minimum 15% N2 needed for start
double old_N1 = N1;
Cranking = true; // provided for sound effects signal
if (N1 < IdleN1) {
EngPower_HP = EnginePowerRPM_N1->GetValue(Prop_RPM,N1);
EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
EngPower_HP *= EnginePowerVC->GetValue();
if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
N1 = ExpSeek(&N1, IdleN1*1.1, Idle_Max_Delay*4, Idle_Max_Delay * 2.4);
@ -391,7 +403,6 @@ double FGTurboProp::Start(void)
Starter = false;
Cranking = false;
FuelFlow_pph = 0;
EngPower_HP=0.0;
}
} else { // no start if N2 < 15% or Starved
phase = tpOff;
@ -449,13 +460,14 @@ void FGTurboProp::SetDefaults(void)
{
// Name = "Not defined";
N1 = N2 = 0.0;
HP = 0.0;
Type = etTurboprop;
MilThrust = 10000.0;
IdleN1 = 30.0;
IdleN2 = 60.0;
MaxN1 = 100.0;
MaxN2 = 100.0;
ThrottleCmd = 0.0;
Throttle = 0.0;
InletPosition = 1.0;
NozzlePosition = 1.0;
Reversed = false;
@ -472,6 +484,11 @@ void FGTurboProp::SetDefaults(void)
Ielu_intervent=false;
Idle_Max_Delay = 1.0;
Throttle = OldThrottle = 0.0;
ITT_Delay = 0.05;
ReverseMaxPower = 0.0;
BetaRangeThrottleEnd = 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -495,9 +512,9 @@ string FGTurboProp::GetEngineValues(const string& delimiter)
{
std::ostringstream buf;
buf << PowerAvailable << delimiter
<< N1 << delimiter
buf << N1 << delimiter
<< N2 << delimiter
<< HP << delimiter
<< Thruster->GetThrusterValues(EngineNumber,delimiter);
return buf.str();
@ -524,10 +541,18 @@ void FGTurboProp::bindmodel()
base_property_name = CreateIndexedPropertyName("propulsion/engine", EngineNumber);
property_name = base_property_name + "/n1";
PropertyManager->Tie( property_name.c_str(), &N1);
property_name = base_property_name + "/n2";
PropertyManager->Tie( property_name.c_str(), &N2);
// property_name = base_property_name + "/n2";
// PropertyManager->Tie( property_name.c_str(), &N2);
property_name = base_property_name + "/reverser";
PropertyManager->Tie( property_name.c_str(), &Reversed);
property_name = base_property_name + "/power-hp";
PropertyManager->Tie( property_name.c_str(), &HP);
property_name = base_property_name + "/itt-c";
PropertyManager->Tie( property_name.c_str(), &Eng_ITT_degC);
property_name = base_property_name + "/engtemp-c";
PropertyManager->Tie( property_name.c_str(), &Eng_Temperature);
property_name = base_property_name + "/ielu_intervent";
PropertyManager->Tie( property_name.c_str(), &Ielu_intervent);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

28
src/FDM/JSBSim/models/propulsion/FGTurboProp.h Normal file → Executable file
View file

@ -27,6 +27,7 @@
HISTORY
--------------------------------------------------------------------------------
05/14/2004 Created
02/08/2011 T. Kreitler, added rotor support
//JVK (mark)
@ -46,7 +47,7 @@ INCLUDES
#include "input_output/FGXMLElement.h"
#include "math/FGTable.h"
#define ID_TURBOPROP "$Id: FGTurboProp.h,v 1.12 2010/08/21 18:08:37 jberndt Exp $"
#define ID_TURBOPROP "$Id: FGTurboProp.h,v 1.14 2011/03/10 01:35:25 dpculp Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -107,11 +108,10 @@ public:
void Calculate(void);
double CalcFuelNeed(void);
inline double GetPowerAvailable(void) const {return (Eng_HP * hptoftlbssec);}
inline double GetPowerAvailable_HP(void) const {return (Eng_HP);}
inline double GetPropRPM(void) const {return (Prop_RPM);}
inline double GetThrottleCmd(void) const {return (ThrottleCmd);}
inline bool GetIeluIntervent(void) const { return Ielu_intervent; }
double GetPowerAvailable(void) const { return (HP * hptoftlbssec); }
double GetRPM(void) const { return (RPM); }
double GetIeluThrottle(void) const { return (Throttle); }
bool GetIeluIntervent(void) const { return Ielu_intervent; }
double Seek(double* var, double target, double accel, double decel);
double ExpSeek(double* var, double target, double accel, double decel);
@ -165,9 +165,8 @@ private:
double dt; ///< Simulator time slice
double N1_factor; ///< factor to tie N1 and throttle
double N2_factor; ///< factor to tie N2 and throttle
double ThrottleCmd; ///< FCS-supplied throttle position
double Throttle; ///< FCS-supplied throttle position
double TAT; ///< total air temperature (deg C)
double PowerAvailable;
bool Stalled; ///< true if engine is compressor-stalled
bool Seized; ///< true if inner spool is seized
bool Overtemp; ///< true if EGT exceeds limits
@ -189,26 +188,27 @@ private:
double BetaRangeThrottleEnd; // coef (0-1) where is end of beta-range
double ReverseMaxPower; // coef (0-1) multiplies max throttle on reverse
double Idle_Max_Delay; // time delay for exponencial
double Idle_Max_Delay; // time delay for exponential
double MaxPower; // max engine power [HP]
double StarterN1; // rotates of generator maked by starter [%]
double StarterN1; // rotates of generator maked by starter [%]
double MaxStartingTime; // maximal time for start [s] (-1 means not used)
double Prop_RPM; // propeller RPM
double RPM; // shaft RPM
double Velocity;
double rho;
double PSFC; // Power specific fuel comsumption [lb/(HP*hr)] at best efficiency
double Eng_HP; // current engine power
double HP; // engine power output
double StartTime; // engine strating time [s] (0 when start button pushed)
double StartTime; // engine starting time [s] (0 when start button pushed)
double ITT_Delay; // time delay for exponencial grow of ITT
double ITT_Delay; // time delay for exponential growth of ITT
double Eng_ITT_degC;
double Eng_Temperature; // temperature inside engine
bool EngStarting; // logicaly output - TRUE if engine is starting
bool GeneratorPower;
int Condition;
int thrusterType; // the attached thruster
double Off(void);
double Run(void);

View file

@ -55,10 +55,15 @@ FGJoystickInput::joystick::joystick ()
FGJoystickInput::joystick::~joystick ()
{
// delete js? why not?
// delete js;
// delete js? no, since js == this - and we're in the destructor already.
delete[] axes;
delete[] buttons;
jsnum = 0;
js = NULL;
naxes = 0;
nbuttons = 0;
axes = NULL;
buttons = NULL;
}
@ -68,13 +73,24 @@ FGJoystickInput::FGJoystickInput()
FGJoystickInput::~FGJoystickInput()
{
_remove();
}
void FGJoystickInput::_remove()
{
SGPropertyNode * js_nodes = fgGetNode("/input/joysticks", true);
js_nodes->removeChildren("js", false);
for (int i = 0; i < MAX_JOYSTICKS; i++)
{
if (bindings[i].js)
delete bindings[i].js;
bindings[i].js = NULL;
}
}
void FGJoystickInput::init()
{
jsInit();
// TODO: zero the old bindings first.
SG_LOG(SG_INPUT, SG_DEBUG, "Initializing joystick bindings");
SGPropertyNode * js_nodes = fgGetNode("/input/joysticks", true);
@ -121,8 +137,7 @@ void FGJoystickInput::init()
void FGJoystickInput::reinit() {
SG_LOG(SG_INPUT, SG_DEBUG, "Re-Initializing joystick bindings");
SGPropertyNode * js_nodes = fgGetNode("/input/joysticks", true);
js_nodes->removeChildren("js", false);
_remove();
FGJoystickInput::init();
FGJoystickInput::postinit();
}

View file

@ -52,6 +52,8 @@ public:
static const int MAX_JOYSTICK_BUTTONS = 32;
private:
void _remove();
/**
* Settings for a single joystick axis.
*/

7
utils/fgpanel/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
fgpanel
*.o
*.obj
.deps
*.Po
Makefile
Makefile.in

View file

@ -0,0 +1,31 @@
//
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef __APPLICATION_PROPERTIES
#define __APPLICATION_PROPERTIES
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include "FGFontCache.hxx"
class ApplicationProperties {
public:
static double getDouble( const char * name, double def = 0.0 );
static SGPath GetRootPath( const char * subDir = NULL );
static SGPropertyNode_ptr Properties;
static std::string root;
static FGFontCache fontCache;
};
#endif

View file

@ -0,0 +1,208 @@
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
using namespace std;
#include <map>
#include <algorithm>
#include "ApplicationProperties.hxx"
#include "FGFontCache.hxx"
////////////////////////////////////////////////////////////////////////
// FGFontCache class.
////////////////////////////////////////////////////////////////////////
//extern puFont FONT_HELVETICA_14;
//extern puFont FONT_SANS_12B;
namespace
{
struct GuiFont
{
const char *name;
puFont *font;
struct Predicate
: public std::unary_function<const GuiFont, bool>
{
Predicate(const char* name_) : name(name_) {}
bool operator() (const GuiFont& f1) const
{
return ::strcmp(f1.name, name) == 0;
}
const char* name;
};
};
const GuiFont guifonts[] = {
{ "default", &PUFONT_HELVETICA_12 },
{ "FIXED_8x13", &PUFONT_8_BY_13 },
{ "FIXED_9x15", &PUFONT_9_BY_15 },
{ "TIMES_10", &PUFONT_TIMES_ROMAN_10 },
{ "TIMES_24", &PUFONT_TIMES_ROMAN_24 },
{ "HELVETICA_10", &PUFONT_HELVETICA_10 },
{ "HELVETICA_12", &PUFONT_HELVETICA_12 },
// { "HELVETICA_14", &FONT_HELVETICA_14 },
{ "HELVETICA_18", &PUFONT_HELVETICA_18 }
// { "SANS_12B", &FONT_SANS_12B }
};
const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])];
}
FGFontCache::FGFontCache() :
_initialized(false)
{
}
FGFontCache::~FGFontCache()
{
PuFontMap::iterator it, end = _puFonts.end();
for (it = _puFonts.begin(); it != end; ++it)
delete it->second;
}
inline bool FGFontCache::FntParamsLess::operator()(const FntParams& f1,
const FntParams& f2) const
{
int comp = f1.name.compare(f2.name);
if (comp < 0)
return true;
else if (comp > 0)
return false;
if (f1.size < f2.size)
return true;
else if (f1.size > f2.size)
return false;
return f1.slant < f2.slant;
}
struct FGFontCache::fnt *
FGFontCache::getfnt(const char *name, float size, float slant)
{
string fontName(name);
FntParams fntParams(fontName, size, slant);
PuFontMap::iterator i = _puFonts.find(fntParams);
if (i != _puFonts.end())
return i->second;
// fntTexFont s are all preloaded into the _texFonts map
TexFontMap::iterator texi = _texFonts.find(fontName);
fntTexFont* texfont = 0;
puFont* pufont = 0;
if (texi != _texFonts.end()) {
texfont = texi->second;
} else {
const GuiFont* guifont = std::find_if(&guifonts[0], guifontsEnd,
GuiFont::Predicate(name));
if (guifont != guifontsEnd) {
pufont = guifont->font;
}
}
fnt* f = new fnt;
if (pufont) {
f->pufont = pufont;
} else if (texfont) {
f->texfont = texfont;
f->pufont = new puFont;
f->pufont->initialize(static_cast<fntFont *>(f->texfont), size, slant);
} else {
f->pufont = guifonts[0].font;
}
_puFonts[fntParams] = f;
return f;
}
puFont *
FGFontCache::get(const char *name, float size, float slant)
{
return getfnt(name, size, slant)->pufont;
}
fntTexFont *
FGFontCache::getTexFont(const char *name, float size, float slant)
{
init();
return getfnt(name, size, slant)->texfont;
}
puFont *
FGFontCache::get(SGPropertyNode *node)
{
if (!node)
return get("Helvetica.txf", 15.0, 0.0);
const char *name = node->getStringValue("name", "Helvetica.txf");
float size = node->getFloatValue("size", 15.0);
float slant = node->getFloatValue("slant", 0.0);
return get(name, size, slant);
}
void FGFontCache::init()
{
if (!_initialized) {
char *envp = ::getenv("FG_FONTS");
if (envp != NULL) {
_path.set(envp);
} else {
_path.set(ApplicationProperties::GetRootPath("Fonts").str());
}
_initialized = true;
}
}
SGPath
FGFontCache::getfntpath(const char *name)
{
init();
SGPath path(_path);
if (name && std::string(name) != "") {
path.append(name);
if (path.exists())
return path;
}
path = SGPath(_path);
path.append("Helvetica.txf");
return path;
}
bool FGFontCache::initializeFonts()
{
static string fontext("txf");
init();
ulDir* fontdir = ulOpenDir(_path.c_str());
if (!fontdir)
return false;
const ulDirEnt *dirEntry;
while ((dirEntry = ulReadDir(fontdir)) != 0) {
SGPath path(_path);
path.append(dirEntry->d_name);
if (path.extension() == fontext) {
fntTexFont* f = new fntTexFont;
if (f->load((char *)path.c_str()))
_texFonts[string(dirEntry->d_name)] = f;
else
delete f;
}
}
ulCloseDir(fontdir);
return true;
}
// end of new_gui.cxx

View file

@ -0,0 +1,86 @@
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef __FGFONTCACHE_HXX
#define __FGFONTCACHE_HXX
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <plib/pu.h>
/**
* A class to keep all fonts available for future use.
* This also assures a font isn't resident more than once.
*/
class FGFontCache {
private:
// The parameters of a request to the cache.
struct FntParams
{
const std::string name;
const float size;
const float slant;
FntParams() : size(0.0f), slant(0.0f) {}
FntParams(const FntParams& rhs)
: name(rhs.name), size(rhs.size), slant(rhs.slant)
{
}
FntParams(const std::string& name_, float size_, float slant_)
: name(name_), size(size_), slant(slant_)
{
}
};
struct FntParamsLess
: public std::binary_function<const FntParams, const FntParams, bool>
{
bool operator() (const FntParams& f1, const FntParams& f2) const;
};
struct fnt {
fnt(puFont *pu = 0) : pufont(pu), texfont(0) {}
~fnt() { if (texfont) { delete pufont; delete texfont; } }
// Font used by plib GUI code
puFont *pufont;
// TXF font
fntTexFont *texfont;
};
// Path to the font directory
SGPath _path;
typedef map<const string, fntTexFont*> TexFontMap;
typedef map<const FntParams, fnt*, FntParamsLess> PuFontMap;
TexFontMap _texFonts;
PuFontMap _puFonts;
bool _initialized;
struct fnt *getfnt(const char *name, float size, float slant);
void init();
public:
FGFontCache();
~FGFontCache();
puFont *get(const char *name, float size=15.0, float slant=0.0);
puFont *get(SGPropertyNode *node);
fntTexFont *getTexFont(const char *name, float size=15.0, float slant=0.0);
SGPath getfntpath(const char *name);
/**
* Preload all the fonts in the FlightGear font directory. It is
* important to load the font textures early, with the proper
* graphics context current, so that no plib (or our own) code
* tries to load a font from disk when there's no current graphics
* context.
*/
bool initializeFonts();
};
#endif

View file

@ -0,0 +1,94 @@
//
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "FGGLApplication.hxx"
#include "GL/gl.h"
#include "GL/glut.h"
#include <iostream>
#include <exception>
#include <stdio.h>
FGGLApplication * FGGLApplication::application = NULL;
FGGLApplication::FGGLApplication( const char * aName, int argc, char ** argv ) :
gameMode(false),
name( aName )
{
if( application != NULL ) {
std::cerr << "Only one instance of FGGLApplication allowed!" << std::endl;
throw std::exception();
}
application = this;
glutInit( &argc, argv );
}
FGGLApplication::~FGGLApplication()
{
}
void FGGLApplication::DisplayCallback()
{
if( application ) application->Display();
}
void FGGLApplication::IdleCallback()
{
if( application ) application->Idle();
}
void FGGLApplication::KeyCallback( unsigned char key, int x, int y )
{
if( application ) application->Key( key, x, y );
}
void FGGLApplication::ReshapeCallback( int width, int height )
{
if( application ) application->Reshape( width, height );
}
void FGGLApplication::Run( int glutMode, bool gameMode, int width, int height, int bpp )
{
glutInitDisplayMode(glutMode);
if( gameMode ) {
width = glutGet(GLUT_SCREEN_WIDTH);
height = glutGet(GLUT_SCREEN_HEIGHT);
char game_mode_str[20];
snprintf(game_mode_str, 20, "%dx%d:%d", width, height, bpp );
glutGameModeString( game_mode_str );
glutEnterGameMode();
this->gameMode = gameMode;
} else {
if( width == -1 )
width = glutGet(GLUT_SCREEN_WIDTH);
if( height == -1 )
height = glutGet(GLUT_SCREEN_HEIGHT);
glutInitDisplayMode(glutMode);
// glutInitWindowSize(width, height);
windowId = glutCreateWindow(name);
}
Init();
glutKeyboardFunc(FGGLApplication::KeyCallback);
glutIdleFunc(FGGLApplication::IdleCallback);
glutDisplayFunc(FGGLApplication::DisplayCallback);
glutReshapeFunc(FGGLApplication::ReshapeCallback);
glutMainLoop();
}

View file

@ -0,0 +1,48 @@
//
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef __FGGLAPPLICATION_HXX
#define __FGGLAPPLICATION_HXX
class FGGLApplication {
public:
FGGLApplication( const char * name, int argc, char ** argv );
virtual ~FGGLApplication();
void Run( int glutMode, bool gameMode, int widht=-1, int height=-1, int bpp = 32 );
protected:
virtual void Key( unsigned char key, int x, int y ) {}
virtual void Idle() {}
virtual void Display() {}
virtual void Reshape( int width, int height ) {}
virtual void Init() {}
int windowId;
bool gameMode;
const char * name;
static FGGLApplication * application;
private:
static void KeyCallback( unsigned char key, int x, int y );
static void IdleCallback();
static void DisplayCallback();
static void ReshapeCallback( int width, int height );
};
#endif

View file

@ -0,0 +1,142 @@
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "FGPNGTextureLoader.hxx"
#include <GL/glu.h>
#include <png.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
GLuint FGPNGTextureLoader::loadTexture( const string & filename )
{
//header for testing if it is a png
png_byte header[8];
//open file as binary
FILE *fp = fopen(filename.c_str(), "rb");
if (!fp) {
return NOTEXTURE;
}
//read the header
fread(header, 1, 8, fp);
//test if png
int is_png = !png_sig_cmp(header, 0, 8);
if (!is_png) {
fclose(fp);
return NOTEXTURE;
}
//create png struct
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
NULL, NULL);
if (!png_ptr) {
fclose(fp);
return (NOTEXTURE);
}
//create png info struct
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
fclose(fp);
return (NOTEXTURE);
}
//create png info struct
png_infop end_info = png_create_info_struct(png_ptr);
if (!end_info) {
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
fclose(fp);
return (NOTEXTURE);
}
//png error stuff, not sure libpng man suggests this.
if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
fclose(fp);
return (NOTEXTURE);
}
//init png reading
png_init_io(png_ptr, fp);
//let libpng know you already read the first 8 bytes
png_set_sig_bytes(png_ptr, 8);
// read all the info up to the image data
png_read_info(png_ptr, info_ptr);
//variables to pass to get info
int bit_depth, color_type;
png_uint_32 twidth, theight;
// get info about png
png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type,
NULL, NULL, NULL);
// Update the png info struct.
png_read_update_info(png_ptr, info_ptr);
// Row size in bytes.
int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
// Allocate the image_data as a big block, to be given to opengl
png_byte *image_data = new png_byte[rowbytes * theight];
if (!image_data) {
//clean up memory and close stuff
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
fclose(fp);
return NOTEXTURE;
}
//row_pointers is for pointing to image_data for reading the png with libpng
png_bytep *row_pointers = new png_bytep[theight];
if (!row_pointers) {
//clean up memory and close stuff
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
delete[] image_data;
fclose(fp);
return NOTEXTURE;
}
// set the individual row_pointers to point at the correct offsets of image_data
for (png_uint_32 i = 0; i < theight; ++i)
row_pointers[theight - 1 - i] = image_data + i * rowbytes;
//read the png into image_data through row_pointers
png_read_image(png_ptr, row_pointers);
//Now generate the OpenGL texture object
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
gluBuild2DMipmaps( GL_TEXTURE_2D, 4, twidth, theight, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)image_data );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );
// glTexImage2D(GL_TEXTURE_2D,0, GL_RGBA, twidth, theight, 0,
// GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*) image_data);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//clean up memory and close stuff
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
delete[] image_data;
delete[] row_pointers;
fclose(fp);
return texture;
}

View file

@ -0,0 +1,26 @@
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef __FGPNGTEXTURELOADER_HXX
#define __FGPNGTEXTURELOADER_HXX
#include "FGTextureLoaderInterface.hxx"
class FGPNGTextureLoader : public FGTextureLoaderInterface {
public:
virtual GLuint loadTexture( const std::string & filename );
const static GLuint NOTEXTURE = 0;
};
#endif

View file

@ -0,0 +1,279 @@
//
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "FGPanelApplication.hxx"
#include <GL/gl.h>
#include <GL/glut.h>
#include <simgear/math/SGMisc.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/structure/exception.hxx>
#include <iostream>
#include "panel_io.hxx"
#include "ApplicationProperties.hxx"
using namespace std;
inline static string ParseArgs( int argc, char ** argv, const string & token )
{
for( int i = 0; i < argc; i++ ) {
string arg = argv[i];
if( arg.find( token ) == 0 )
return arg.substr( token.length() );
}
return "";
}
inline static string ParseArgs( int argc, char ** argv, const char * token )
{
string s = token;
return ParseArgs( argc, argv, s );
}
#include "FGPNGTextureLoader.hxx"
#include "FGRGBTextureLoader.hxx"
static FGPNGTextureLoader pngTextureLoader;
static FGRGBTextureLoader rgbTextureLoader;
FGPanelApplication::FGPanelApplication( int argc, char ** argv ) :
FGGLApplication( "FlightGear Panel", argc, argv )
{
sglog().setLogLevels( SG_ALL, SG_WARN );
FGCroppedTexture::registerTextureLoader( "png", &pngTextureLoader );
FGCroppedTexture::registerTextureLoader( "rgb", &rgbTextureLoader );
string panelFilename;
string fgRoot;
for( int i = 1; i < argc; i++ ) {
panelFilename = ParseArgs( argc, argv, "--panel=" );
fgRoot = ParseArgs( argc, argv, "--fg-root=" );
}
if( fgRoot.length() > 0 )
ApplicationProperties::root = fgRoot;
if( panelFilename.length() == 0 ) {
cerr << "Need a panel filename. Use --panel=path_to_filename" << endl;
throw exception();
}
try {
SGPath tpath = ApplicationProperties::GetRootPath( panelFilename.c_str() );
readProperties( tpath.str(), ApplicationProperties::Properties );
}
catch( sg_io_exception & e ) {
cerr << e.getFormattedMessage() << endl;
throw;
}
for( int i = 1; i < argc; i++ ) {
string arg = argv[i];
if( arg.find( "--prop:" ) == 0 ) {
string s2 = arg.substr( 7 );
unsigned p = s2.find( "=" );
if( p != string::npos ) {
string propertyName = s2.substr( 0, p );
string propertyValue = s2.substr( p+1 );
ApplicationProperties::Properties->getNode( propertyName.c_str(), true )->setValue( propertyValue.c_str() );
}
}
}
SGPropertyNode_ptr n;
if( (n = ApplicationProperties::Properties->getNode( "panel" )) != NULL )
panel = FGReadablePanel::read( n );
protocol = new FGPanelProtocol( ApplicationProperties::Properties->getNode( "communication", true ) );
protocol->init();
}
FGPanelApplication::~FGPanelApplication()
{
}
void FGPanelApplication::Run()
{
int mode = GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE;
int w = panel == NULL ? 0 : panel->getWidth();
int h = panel == NULL ? 0 : panel->getHeight();
if( w == 0 && h == 0 ) {
w = 1024;
h = 768;
} else if( w == 0 ) {
w = h / 0.75;
} else if( h == 0 ) {
h = w * 0.75;
}
bool gameMode = ApplicationProperties::Properties->getNode( "game-mode", true )->getBoolValue();
FGGLApplication::Run( mode, gameMode, w, h );
}
void FGPanelApplication::Init()
{
glAlphaFunc(GL_GREATER, 0.1);
glutSetCursor( GLUT_CURSOR_NONE );
ApplicationProperties::fontCache.initializeFonts();
}
void FGPanelApplication::Reshape( int width, int height )
{
this->width = width;
this->height = height;
glViewport(0, 0, (GLsizei) width, (GLsizei) height);
}
void FGPanelApplication::Idle()
{
double d = glutGet(GLUT_ELAPSED_TIME);
double dt = Sleep();
if( dt == 0 )
return;
if( panel != NULL )
panel->update( dt );
glutSwapBuffers();
if( protocol != NULL )
protocol->update( dt );
static double dsum = 0.0;
static unsigned cnt = 0;
dsum += glutGet(GLUT_ELAPSED_TIME)-d;
cnt++;
if( dsum > 1000.0 ) {
ApplicationProperties::Properties->getNode( "/sim/frame-rate", true )->setDoubleValue(cnt*1000.0/dsum );
dsum = 0.0;
cnt = 0;
}
}
void FGPanelApplication::Key( unsigned char key, int x, int y )
{
switch( key ) {
case 0x1b:
if( gameMode ) glutLeaveGameMode();
else glutDestroyWindow( windowId );
break;
}
}
double FGPanelApplication::Sleep()
{
SGTimeStamp current_time_stamp;
static SGTimeStamp last_time_stamp;
if ( last_time_stamp.get_seconds() == 0 )
last_time_stamp.stamp();
double model_hz = 60;
double throttle_hz = ApplicationProperties::getDouble("/sim/frame-rate-throttle-hz", 0.0);
if ( throttle_hz > 0.0 ) {
// optionally throttle the frame rate (to get consistent frame
// rates or reduce cpu usage.
double frame_us = 1.0e6 / throttle_hz;
// sleep based timing loop.
//
// Calling sleep, even usleep() on linux is less accurate than
// we like, but it does free up the cpu for other tasks during
// the sleep so it is desirable. Because of the way sleep()
// is implemented in consumer operating systems like windows
// and linux, you almost always sleep a little longer than the
// requested amount.
//
// To combat the problem of sleeping too long, we calculate the
// desired wait time and shorten it by 2000us (2ms) to avoid
// [hopefully] over-sleep'ing. The 2ms value was arrived at
// via experimentation. We follow this up at the end with a
// simple busy-wait loop to get the final pause timing exactly
// right.
//
// Assuming we don't oversleep by more than 2000us, this
// should be a reasonable compromise between sleep based
// waiting, and busy waiting.
// sleep() will always overshoot by a bit so undersleep by
// 2000us in the hopes of never oversleeping.
frame_us -= 2000.0;
if ( frame_us < 0.0 ) {
frame_us = 0.0;
}
current_time_stamp.stamp();
/* Convert to ms */
double elapsed_us = (current_time_stamp - last_time_stamp).toUSecs();
if ( elapsed_us < frame_us ) {
double requested_us = frame_us - elapsed_us;
usleep ( (useconds_t)(requested_us ) ) ;
}
// busy wait timing loop.
//
// This yields the most accurate timing. If the previous
// usleep() call is omitted this will peg the cpu
// (which is just fine if FG is the only app you care about.)
current_time_stamp.stamp();
SGTimeStamp next_time_stamp = last_time_stamp;
next_time_stamp += SGTimeStamp::fromSec(1e-6*frame_us);
while ( current_time_stamp < next_time_stamp ) {
current_time_stamp.stamp();
}
} else {
current_time_stamp.stamp();
}
double real_delta_time_sec = double(current_time_stamp.toUSecs() - last_time_stamp.toUSecs()) / 1000000.0;
last_time_stamp = current_time_stamp;
//fprintf(stdout,"\r%4.1lf ", 1/real_delta_time_sec );
//fflush(stdout);
// round the real time down to a multiple of 1/model-hz.
// this way all systems are updated the _same_ amount of dt.
static double reminder = 0.0;
static long global_multi_loop = 0;
real_delta_time_sec += reminder;
global_multi_loop = long(floor(real_delta_time_sec*model_hz));
global_multi_loop = SGMisc<long>::max(0, global_multi_loop);
reminder = real_delta_time_sec - double(global_multi_loop)/double(model_hz);
return double(global_multi_loop)/double(model_hz);
}
double ApplicationProperties::getDouble( const char * name, double def )
{
SGPropertyNode_ptr n = ApplicationProperties::Properties->getNode( name, false );
if( n == NULL ) return def;
return n->getDoubleValue();
}
SGPath ApplicationProperties::GetRootPath( const char * sub )
{
SGPath path( ApplicationProperties::root );
if( sub != NULL )
path.append( sub );
return path;
}
std::string ApplicationProperties::root = ".";
SGPropertyNode_ptr ApplicationProperties::Properties = new SGPropertyNode;
FGFontCache ApplicationProperties::fontCache;

View file

@ -0,0 +1,55 @@
//
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef __FGPANELAPPLICATION_HXX
#define __FGPANELAPPLICATION_HXX
#include "FGGLApplication.hxx"
#include "FGPanelProtocol.hxx"
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/props/props.hxx>
#include <string>
#include "panel.hxx"
class FGPanelApplication : public FGGLApplication {
public:
FGPanelApplication( int argc, char ** argv );
~FGPanelApplication();
void Run();
protected:
virtual void Key( unsigned char key, int x, int y );
virtual void Idle();
// virtual void Display();
virtual void Reshape( int width, int height );
virtual void Init();
double Sleep();
SGSharedPtr<FGPanel> panel;
SGSharedPtr<FGPanelProtocol> protocol;
int width;
int height;
};
#endif

View file

@ -0,0 +1,154 @@
//
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "FGPanelProtocol.hxx"
#include "ApplicationProperties.hxx"
#include <simgear/io/sg_socket.hxx>
#include <simgear/misc/strutils.hxx>
class PropertySetter {
public:
PropertySetter( SGPropertyNode_ptr node ) : _node(node) {}
virtual void setValue( const char * value ) = 0;
protected:
SGPropertyNode_ptr _node;
};
class BoolPropertySetter : public PropertySetter {
public:
BoolPropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {}
virtual void setValue( const char * value ) {
_node->setBoolValue( atoi( value ) != 0 );
}
};
class IntPropertySetter : public PropertySetter {
public:
IntPropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {}
virtual void setValue( const char * value ) {
_node->setIntValue( atol( value ) );
}
};
class FloatPropertySetter : public PropertySetter {
public:
FloatPropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {}
virtual void setValue( const char * value ) {
_node->setFloatValue( strtof( value, NULL ) );
}
};
class DoublePropertySetter : public PropertySetter {
public:
DoublePropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {}
virtual void setValue( const char * value ) {
_node->setDoubleValue( strtod( value, NULL ) );
}
};
class StringPropertySetter : public PropertySetter {
public:
StringPropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {}
virtual void setValue( const char * value ) {
_node->setStringValue( value );
}
};
FGPanelProtocol::FGPanelProtocol( SGPropertyNode_ptr aRoot )
: SGSubsystem(),
root(aRoot),
io(NULL)
{
SGPropertyNode_ptr outputNode = root->getNode( "protocol/generic/output" );
if( outputNode ) {
vector<SGPropertyNode_ptr> chunks = outputNode->getChildren( "chunk" );
for( vector<SGPropertyNode_ptr>::size_type i = 0; i < chunks.size(); i++ ) {
SGPropertyNode_ptr chunk = chunks[i];
SGPropertyNode_ptr nodeNode = chunk->getNode("node", false );
if( nodeNode == NULL )
continue;
SGPropertyNode_ptr node = ApplicationProperties::Properties->getNode( nodeNode->getStringValue(), true );
string type = "";
SGPropertyNode_ptr typeNode = chunk->getNode( "type", false );
if( typeNode != NULL ) type = typeNode->getStringValue();
if( type == "float" ) {
propertySetterVector.push_back( new FloatPropertySetter( node ) );
} else if( type == "double" || type == "fixed" ) {
propertySetterVector.push_back( new DoublePropertySetter( node ) );
} else if( type == "bool" || type == "boolean" ) {
propertySetterVector.push_back( new BoolPropertySetter( node ) );
} else if( type == "string" ) {
propertySetterVector.push_back( new StringPropertySetter( node ) );
} else {
propertySetterVector.push_back( new IntPropertySetter( node ) );
}
}
}
}
FGPanelProtocol::~FGPanelProtocol()
{
for( PropertySetterVector::size_type i = 0; i < propertySetterVector.size(); i++ )
delete propertySetterVector[i];
}
void FGPanelProtocol::update( double dt )
{
char buf[8192];
if( io == NULL )
return;
int length = io->readline( buf, sizeof(buf)-1 );
buf[sizeof(buf)-1] = 0;
if ( length > 0 ) {
vector<string> tokens = simgear::strutils::split( buf, "," );
for( vector<string>::size_type i = 0; i < tokens.size(); i++ ) {
if( i < propertySetterVector.size() )
propertySetterVector[i]->setValue( tokens[i].c_str() );
}
}
}
void FGPanelProtocol::init()
{
SGPropertyNode_ptr listenNode = root->getNode( "listen" );
if( listenNode == NULL ) {
return;
}
string hostname = listenNode->getNode( "host", true )->getStringValue();
string port = listenNode->getNode( "port", true )->getStringValue();
string style = listenNode->getNode( "style", true )->getStringValue();
if( io != NULL )
delete io;
io = new SGSocket( hostname, port, style );
if( !io->open( SG_IO_IN ) ) {
cerr << "can't open socket " << style << ":" << hostname << ":" << port << endl;
}
}
void FGPanelProtocol::reinit()
{
init();
}

View file

@ -0,0 +1,41 @@
//
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef __FGPANELPROTOCOL_HXX
#define __FGPANELPROTOCOL_HXX
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/props/props.hxx>
#include <simgear/io/iochannel.hxx>
class PropertySetter;
typedef vector<PropertySetter*> PropertySetterVector;
class FGPanelProtocol : public SGSubsystem {
public:
FGPanelProtocol( SGPropertyNode_ptr root );
virtual ~FGPanelProtocol();
virtual void init();
virtual void reinit();
virtual void update( double dt );
protected:
private:
SGPropertyNode_ptr root;
SGIOChannel * io;
PropertySetterVector propertySetterVector;
};
#endif

View file

@ -0,0 +1,504 @@
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// From the OpenSceneGraph distribution ReaderWriterRGB.cpp
// Reader for sgi's .rgb format.
// specification can be found at http://local.wasp.uwa.edu.au/~pbourke/dataformats/sgirgb/sgiversion.html
#include "FGRGBTextureLoader.hxx"
#include <GL/gl.h>
#include <GL/glu.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <fstream>
typedef struct _rawImageRec
{
unsigned short imagic;
unsigned short type;
unsigned short dim;
unsigned short sizeX, sizeY, sizeZ;
unsigned long min, max;
unsigned long wasteBytes;
char name[80];
unsigned long colorMap;
std::istream *file;
unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA;
unsigned long rleEnd;
GLuint *rowStart;
GLint *rowSize;
GLenum swapFlag;
short bpc;
typedef unsigned char * BytePtr;
bool needsBytesSwapped()
{
union {
int testWord;
char testByte[sizeof(int)];
}endianTest;
endianTest.testWord = 1;
if( endianTest.testByte[0] == 1 )
return true;
else
return false;
}
template <class T>
inline void swapBytes( T &s )
{
if( sizeof( T ) == 1 )
return;
T d = s;
BytePtr sptr = (BytePtr)&s;
BytePtr dptr = &(((BytePtr)&d)[sizeof(T)-1]);
for( unsigned int i = 0; i < sizeof(T); i++ )
*(sptr++) = *(dptr--);
}
void swapBytes()
{
swapBytes( imagic );
swapBytes( type );
swapBytes( dim );
swapBytes( sizeX );
swapBytes( sizeY );
swapBytes( sizeZ );
swapBytes( wasteBytes );
swapBytes( min );
swapBytes( max );
swapBytes( colorMap );
}
} rawImageRec;
static void ConvertShort(unsigned short *array, long length)
{
unsigned long b1, b2;
unsigned char *ptr;
ptr = (unsigned char *)array;
while (length--)
{
b1 = *ptr++;
b2 = *ptr++;
*array++ = (unsigned short) ((b1 << 8) | (b2));
}
}
static void ConvertLong(GLuint *array, long length)
{
unsigned long b1, b2, b3, b4;
unsigned char *ptr;
ptr = (unsigned char *)array;
while (length--)
{
b1 = *ptr++;
b2 = *ptr++;
b3 = *ptr++;
b4 = *ptr++;
*array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
}
}
static void RawImageClose(rawImageRec *raw)
{
if (raw)
{
if (raw->tmp) delete [] raw->tmp;
if (raw->tmpR) delete [] raw->tmpR;
if (raw->tmpG) delete [] raw->tmpG;
if (raw->tmpB) delete [] raw->tmpB;
if (raw->tmpA) delete [] raw->tmpA;
if (raw->rowStart) delete [] raw->rowStart;
if (raw->rowSize) delete [] raw->rowSize;
delete raw;
}
}
static rawImageRec *RawImageOpen(std::istream& fin)
{
union
{
int testWord;
char testByte[4];
} endianTest;
rawImageRec *raw;
int x;
raw = new rawImageRec;
if (raw == NULL)
{
// notify(WARN)<< "Out of memory!"<< std::endl;
return NULL;
}
//Set istream pointer
raw->file = &fin;
endianTest.testWord = 1;
if (endianTest.testByte[0] == 1)
{
raw->swapFlag = GL_TRUE;
}
else
{
raw->swapFlag = GL_FALSE;
}
fin.read((char*)raw,12);
if (!fin.good())
return NULL;
if (raw->swapFlag)
{
ConvertShort(&raw->imagic, 6);
}
raw->tmp = raw->tmpR = raw->tmpG = raw->tmpB = raw->tmpA = 0L;
raw->rowStart = 0;
raw->rowSize = 0;
raw->bpc = (raw->type & 0x00FF);
raw->tmp = new unsigned char [raw->sizeX*256*raw->bpc];
if (raw->tmp == NULL )
{
// notify(FATAL)<< "Out of memory!"<< std::endl;
RawImageClose(raw);
return NULL;
}
if( raw->sizeZ >= 1 )
{
if( (raw->tmpR = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
{
// notify(FATAL)<< "Out of memory!"<< std::endl;
RawImageClose(raw);
return NULL;
}
}
if( raw->sizeZ >= 2 )
{
if( (raw->tmpG = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
{
// notify(FATAL)<< "Out of memory!"<< std::endl;
RawImageClose(raw);
return NULL;
}
}
if( raw->sizeZ >= 3 )
{
if( (raw->tmpB = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
{
// notify(FATAL)<< "Out of memory!"<< std::endl;
RawImageClose(raw);
return NULL;
}
}
if (raw->sizeZ >= 4)
{
if( (raw->tmpA = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
{
// notify(FATAL)<< "Out of memory!"<< std::endl;
RawImageClose(raw);
return NULL;
}
}
if ((raw->type & 0xFF00) == 0x0100)
{
unsigned int ybyz = raw->sizeY * raw->sizeZ;
if ( (raw->rowStart = new GLuint [ybyz]) == NULL )
{
// notify(FATAL)<< "Out of memory!"<< std::endl;
RawImageClose(raw);
return NULL;
}
if ( (raw->rowSize = new GLint [ybyz]) == NULL )
{
// notify(FATAL)<< "Out of memory!"<< std::endl;
RawImageClose(raw);
return NULL;
}
x = ybyz * sizeof(GLuint);
raw->rleEnd = 512 + (2 * x);
fin.seekg(512,std::ios::beg);
fin.read((char*)raw->rowStart,x);
fin.read((char*)raw->rowSize,x);
if (raw->swapFlag)
{
ConvertLong(raw->rowStart, (long) (x/sizeof(GLuint)));
ConvertLong((GLuint *)raw->rowSize, (long) (x/sizeof(GLint)));
}
}
return raw;
}
static void RawImageGetRow(rawImageRec *raw, unsigned char *buf, int y, int z)
{
unsigned char *iPtr, *oPtr;
unsigned short pixel;
int count, done = 0;
unsigned short *tempShort;
if ((raw->type & 0xFF00) == 0x0100)
{
raw->file->seekg((long) raw->rowStart[y+z*raw->sizeY], std::ios::beg);
raw->file->read((char*)raw->tmp, (unsigned int)raw->rowSize[y+z*raw->sizeY]);
iPtr = raw->tmp;
oPtr = buf;
while (!done)
{
if (raw->bpc == 1)
pixel = *iPtr++;
else
{
tempShort = reinterpret_cast<unsigned short*>(iPtr);
pixel = *tempShort;
tempShort++;
iPtr = reinterpret_cast<unsigned char *>(tempShort);
}
if(raw->bpc != 1)
ConvertShort(&pixel, 1);
count = (int)(pixel & 0x7F);
// limit the count value to the remiaing row size
if (oPtr + count*raw->bpc > buf + raw->sizeX*raw->bpc)
{
count = ( (buf + raw->sizeX*raw->bpc) - oPtr ) / raw->bpc;
}
if (count<=0)
{
done = 1;
return;
}
if (pixel & 0x80)
{
while (count--)
{
if(raw->bpc == 1)
*oPtr++ = *iPtr++;
else{
tempShort = reinterpret_cast<unsigned short*>(iPtr);
pixel = *tempShort;
tempShort++;
iPtr = reinterpret_cast<unsigned char *>(tempShort);
ConvertShort(&pixel, 1);
tempShort = reinterpret_cast<unsigned short*>(oPtr);
*tempShort = pixel;
tempShort++;
oPtr = reinterpret_cast<unsigned char *>(tempShort);
}
}
}
else
{
if (raw->bpc == 1)
{
pixel = *iPtr++;
}
else
{
tempShort = reinterpret_cast<unsigned short*>(iPtr);
pixel = *tempShort;
tempShort++;
iPtr = reinterpret_cast<unsigned char *>(tempShort);
}
if(raw->bpc != 1)
ConvertShort(&pixel, 1);
while (count--)
{
if(raw->bpc == 1)
*oPtr++ = pixel;
else
{
tempShort = reinterpret_cast<unsigned short*>(oPtr);
*tempShort = pixel;
tempShort++;
oPtr = reinterpret_cast<unsigned char *>(tempShort);
}
}
}
}
}
else
{
raw->file->seekg(512+(y*raw->sizeX*raw->bpc)+(z*raw->sizeX*raw->sizeY*raw->bpc),std::ios::beg);
raw->file->read((char*)buf, raw->sizeX*raw->bpc);
if(raw->swapFlag && raw->bpc != 1){
ConvertShort(reinterpret_cast<unsigned short*>(buf), raw->sizeX);
}
}
}
static void RawImageGetData(rawImageRec *raw, unsigned char **data )
{
unsigned char *ptr;
int i, j;
unsigned short *tempShort;
// // round the width to a factor 4
// int width = (int)(floorf((float)raw->sizeX/4.0f)*4.0f);
// if (width!=raw->sizeX) width += 4;
// byte aligned.
// osg::notify(osg::INFO)<<"raw->sizeX = "<<raw->sizeX<<std::endl;
// osg::notify(osg::INFO)<<"raw->sizeY = "<<raw->sizeY<<std::endl;
// osg::notify(osg::INFO)<<"raw->sizeZ = "<<raw->sizeZ<<std::endl;
// osg::notify(osg::INFO)<<"raw->bpc = "<<raw->bpc<<std::endl;
*data = new unsigned char [(raw->sizeX)*(raw->sizeY)*(raw->sizeZ)*(raw->bpc)];
ptr = *data;
for (i = 0; i < (int)(raw->sizeY); i++)
{
if( raw->sizeZ >= 1 )
RawImageGetRow(raw, raw->tmpR, i, 0);
if( raw->sizeZ >= 2 )
RawImageGetRow(raw, raw->tmpG, i, 1);
if( raw->sizeZ >= 3 )
RawImageGetRow(raw, raw->tmpB, i, 2);
if( raw->sizeZ >= 4 )
RawImageGetRow(raw, raw->tmpA, i, 3);
for (j = 0; j < (int)(raw->sizeX); j++)
{
if(raw->bpc == 1){
if( raw->sizeZ >= 1 )
*ptr++ = *(raw->tmpR + j);
if( raw->sizeZ >= 2 )
*ptr++ = *(raw->tmpG + j);
if( raw->sizeZ >= 3 )
*ptr++ = *(raw->tmpB + j);
if( raw->sizeZ >= 4 )
*ptr++ = *(raw->tmpA + j);
}else{
if( raw->sizeZ >= 1 )
{
tempShort = reinterpret_cast<unsigned short*>(ptr);
*tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpR) + j);
tempShort++;
ptr = reinterpret_cast<unsigned char *>(tempShort);
}
if( raw->sizeZ >= 2 )
{
tempShort = reinterpret_cast<unsigned short*>(ptr);
*tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpG) + j);
tempShort++;
ptr = reinterpret_cast<unsigned char *>(tempShort);
}
if( raw->sizeZ >= 3 )
{
tempShort = reinterpret_cast<unsigned short*>(ptr);
*tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpB) + j);
tempShort++;
ptr = reinterpret_cast<unsigned char *>(tempShort);
}
if( raw->sizeZ >= 4 )
{
tempShort = reinterpret_cast<unsigned short*>(ptr);
*tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpA) + j);
tempShort++;
ptr = reinterpret_cast<unsigned char *>(tempShort);
}
}
}
// // pad the image width with blanks to bring it up to the rounded width.
// for(;j<width;++j) *ptr++ = 0;
}
}
// supportsExtension("rgb","rgb image format");
// supportsExtension("rgba","rgba image format");
// supportsExtension("sgi","sgi image format");
// supportsExtension("int","int image format");
// supportsExtension("inta","inta image format");
// supportsExtension("bw","bw image format");
GLuint readRGBStream(std::istream& fin)
{
rawImageRec *raw;
if( (raw = RawImageOpen(fin)) == NULL )
{
return 0;
}
int s = raw->sizeX;
int t = raw->sizeY;
// int r = 1;
#if 0
int internalFormat = raw->sizeZ == 3 ? GL_RGB5 :
raw->sizeZ == 4 ? GL_RGB5_A1 : GL_RGB;
#else
// int internalFormat = raw->sizeZ;
#endif
unsigned int pixelFormat =
raw->sizeZ == 1 ? GL_LUMINANCE :
raw->sizeZ == 2 ? GL_LUMINANCE_ALPHA :
raw->sizeZ == 3 ? GL_RGB :
raw->sizeZ == 4 ? GL_RGBA : (GLenum)-1;
GLint component = raw->sizeZ;
unsigned int dataType = raw->bpc == 1 ? GL_UNSIGNED_BYTE :
GL_UNSIGNED_SHORT;
unsigned char *data;
RawImageGetData(raw, &data);
RawImageClose(raw);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
gluBuild2DMipmaps( GL_TEXTURE_2D, component, s, t, pixelFormat, dataType, (GLvoid*)data );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );
delete []data;
return texture;
}
GLuint FGRGBTextureLoader::loadTexture( const std::string & filename )
{
GLuint texture = NOTEXTURE;
std::ifstream istream(filename.c_str(), std::ios::in | std::ios::binary );
texture = readRGBStream(istream);
istream.close();
return texture;
}

View file

@ -0,0 +1,26 @@
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef __FGRGBTEXTURELOADER_HXX
#define __FGRGBTEXTURELOADER_HXX
#include "FGTextureLoaderInterface.hxx"
class FGRGBTextureLoader : public FGTextureLoaderInterface {
public:
virtual GLuint loadTexture( const std::string & filename );
const static GLuint NOTEXTURE = 0;
};
#endif

View file

@ -0,0 +1,27 @@
//
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef __FGTEXTURELOADERINTERFACE_HXX
#define __FGTEXTURELOADERINTERFACE_HXX
#include <GL/gl.h>
#include <string>
class FGTextureLoaderInterface {
public:
virtual GLuint loadTexture( const std::string & filename ) = 0;
};
#endif

20
utils/fgpanel/Makefile.am Normal file
View file

@ -0,0 +1,20 @@
AM_CXXFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\"
bin_PROGRAMS = fgpanel
fgpanel_SOURCES = main.cxx \
FGGLApplication.cxx FGGLApplication.hxx \
FGPanelApplication.cxx FGPanelApplication.hxx \
FGPNGTextureLoader.cxx FGPNGTextureLoader.hxx FGTextureLoaderInterface.hxx \
FGRGBTextureLoader.cxx FGRGBTextureLoader.hxx \
FGPanelProtocol.cxx \
FGFontCache.cxx \
panel.cxx panel.hxx \
panel_io.cxx panel_io.hxx
LIBS =
fgpanel_LDADD = \
-lGLU -lglut -lsgmath -lsgprops -lsgio -lsgdebug -lsgmisc -lsgstructure -lsgxml -lsgtiming \
-lplibpu -lplibfnt -lplibul \
-lrt -lpng

148
utils/fgpanel/README Normal file
View file

@ -0,0 +1,148 @@
=====================================================================
This is fgpanel - basically the stripped down 2D-Panel code from
FlightGear. It is designed as a standalone lightweight panel
rendering engine to draw 2d panels on a lowcost computer/graphic card
without 3d acceleration at reasonablel framerates.
=====================================================================
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
=====================================================================
Usage
start fgpanel with
fgpanel --fg-root=/path/to/fg/data --panel=Aircraft/MyAircraft/Panels/MyPanel.xml
with the command args set to
--fg-root shall point to the directory where your FGDATA lives
NOTE: you don't need a full copy of FGDATA, just the panel definition files for
your aircraft, e.g.
- Aircraft/MyAircraft/Panels/*
- Aircraft/Instruments/* (if referenced)
-panel shall point to a panel-configuration file, relative to FGDATA
start flightgear with
fgfs --generic=socket,out,10,239.24.10.64,5432,udp,../Aircraft/MyAircraft/Panels/SampleProtocol
=====================================================================
Sample:
Create the sample files within your aicraft directory, preferrable under Panels
MyPanel.xml
sample-2d-panel.xml
SampleProtocol.xml
=====================================================================
Sample panel configuration file (MyPanel.xml)
<PropertyList>
<!-- true: run full-screen, false; run in window -->
<game-mode type="bool">false</game-mode>
<!-- include the panel definitions (2d-panel syntax)-->
<panel include="sample-2d-panel.xml"/>
<!-- compose your property-tree here -->
<sim>
<panel>
<flip-x type="bool">false</flip-x>
</panel>
<instrument-options>
<omit-knobs type="bool">true</omit-knobs>
</instrument-options>
</sim>
<!-- network communication settings -->
<communication>
<listen>
<!-- interface to bind to,
leave empty for all interfaces -->
<host>239.24.10.64</host> <!-- multicast address! -->
<port>5432</port> <!-- tcp port to listen to -->
<style>udp</style> <!-- udp or tcp (forget about tcp!) -->
</listen>
<!-- the generic protocol definition
same as used for fgfs --generic=foobar option
-->
<protocol include="SampleProtocol.xml"/>
</communication>
</PropertyList>
=====================================================================
Sampe 2d-panel configuration file sample-2d-panel.xml
To be included from the panel configuration file
<?xml version="1.0"?>
<PropertyList>
<name>Sample Instrument Panel</name>
<w>375</w> <!-- screen width: 375mm -->
<h>305</h> <!-- screen height: 305mm -->
<instruments>
<!-- use FlightGear's c172 attitude indicator -->
<instrument include="../../Instruments/ati-c172s.xml">
<name>Attitude Gyro</name>
<x alias="../../../params/col-2"/>
<y alias="../../../params/row-1"/>
<w>80</w>
<h>80</h>
</instrument>
</instruments>
</PropertyList>
=====================================================================
Sample protocol configuration file to drive the AI (SampleProtocol.xml)
<?xml version="1.0"?>
<PropertyList>
<generic>
<output>
<line_separator>newline</line_separator>
<var_separator>,</var_separator>
<chunk>
<type>float</type>
<format>%.2f</format>
<node>/position/altitude-agl-ft</node>
</chunk>
<chunk>
<type>float</type>
<format>%.2f</format>
<node>/instrumentation/attitude-indicator/indicated-roll-deg</node>
</chunk>
<chunk>
<type>float</type>
<format>%.2f</format>
<node>/instrumentation/attitude-indicator/indicated-pitch-deg</node>
</chunk>
<chunk>
<type>float</type>
<format>%.2f</format>
<node>/instrumentation/attitude-indicator/horizon-offset-deg</node>
</chunk>
<chunk>
<type>float</type>
<format>%.4e</format>
<node>/instrumentation/attitude-indicator/spin</node>
</chunk>
</output>
</generic>
</PropertyList>
=====================================================================

30
utils/fgpanel/main.cxx Normal file
View file

@ -0,0 +1,30 @@
//
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "FGPanelApplication.hxx"
int main( int argc, char ** argv )
{
try {
FGPanelApplication app(argc,argv);
app.Run();
return 0;
}
catch( ... ) {
cerr << "Sorry, your program terminated." << endl;
}
}

962
utils/fgpanel/panel.cxx Normal file
View file

@ -0,0 +1,962 @@
// panel.cxx - default, 2D single-engine prop instrument panel
//
// Written by David Megginson, started January 2000.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id: panel.cxx,v 1.44 2006/09/05 20:28:48 curt Exp $
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_WINDOWS_H
# include <windows.h>
#endif
#include <stdio.h> // sprintf
#include <string.h>
#include <simgear/compiler.h>
#include <GL/glut.h>
#include <plib/fnt.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include "panel.hxx"
#include "ApplicationProperties.hxx"
////////////////////////////////////////////////////////////////////////
// Local functions.
////////////////////////////////////////////////////////////////////////
class FGDummyTextureLoader : public FGTextureLoaderInterface {
public:
virtual GLuint loadTexture( const string & filename );
};
GLuint FGDummyTextureLoader::loadTexture( const string & filename )
{
GLuint _texture = 0;
glGenTextures( 1, &_texture );
glBindTexture( GL_TEXTURE_2D, _texture );
// glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) ;
// glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) ;
// glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ) ;
// glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ) ;
// glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ) ;
GLubyte image[ 2 * 2 * 3 ] ;
/* Red and white chequerboard */
image [ 0 ] = 255 ; image [ 1 ] = 0 ; image [ 2 ] = 0 ;
image [ 3 ] = 255 ; image [ 4 ] = 255 ; image [ 5 ] = 255 ;
image [ 6 ] = 255 ; image [ 7 ] = 255 ; image [ 8 ] = 255 ;
image [ 9 ] = 255 ; image [ 10] = 0 ; image [ 11] = 0 ;
glTexImage2D(GL_TEXTURE_2D,0, GL_RGB, 2, 2, 0,
GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) image);
return _texture;
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGCropped Texture.
////////////////////////////////////////////////////////////////////////
GLuint FGCroppedTexture::current_bound_texture = 0;
map<string,GLuint> FGCroppedTexture::cache;
map<string,FGTextureLoaderInterface*> FGCroppedTexture::textureLoader;
static FGDummyTextureLoader dummyTextureLoader;
FGCroppedTexture::FGCroppedTexture (const string &path,
float minX, float minY,
float maxX, float maxY)
: _path(path),
_minX(minX), _minY(minY), _maxX(maxX), _maxY(maxY), _texture(0)
{
}
FGCroppedTexture::~FGCroppedTexture ()
{
}
void FGCroppedTexture::bind( bool doGLBind )
{
if( _texture == 0 ) {
SG_LOG( SG_COCKPIT, SG_DEBUG, "First bind of texture " << _path );
if( cache.count(_path) > 0 ) {
_texture = cache[_path];
SG_LOG( SG_COCKPIT, SG_DEBUG, "Using texture " << _path << " from cache (#" << _texture << ")" );
} else {
SGPath tpath = ApplicationProperties::GetRootPath(_path.c_str());
string extension = tpath.extension();
FGTextureLoaderInterface * loader = &dummyTextureLoader;
if( textureLoader.count( extension ) == 0 ) {
SG_LOG( SG_COCKPIT, SG_ALERT, "Can't handle textures of type " << extension );
} else {
loader = textureLoader[extension];
}
_texture = loader->loadTexture( tpath.c_str() );
SG_LOG( SG_COCKPIT, SG_DEBUG, "Texture " << tpath.c_str() << " loaded from file as #" << _texture );
cache[_path] = _texture;
}
}
if( !doGLBind || current_bound_texture == _texture )
return;
glBindTexture( GL_TEXTURE_2D, _texture );
current_bound_texture = _texture;
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGPanel.
////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
FGPanel::FGPanel ( SGPropertyNode_ptr root)
: _root(root),
_flipx(root->getNode("/sim/panel/flip-x", true)),
_rotate(root->getNode("/sim/panel/rotate-deg", true)),
_bg_width(1.0), _bg_height(1.0),
initDisplayList(0)
{
}
/**
* Destructor.
*/
FGPanel::~FGPanel ()
{
for (instrument_list_type::iterator it = _instruments.begin();
it != _instruments.end();
it++) {
delete *it;
*it = 0;
}
}
/**
* Add an instrument to the panel.
*/
void
FGPanel::addInstrument (FGPanelInstrument * instrument)
{
_instruments.push_back(instrument);
}
/**
* Initialize the panel.
*/
void
FGPanel::init ()
{
}
/**
* Bind panel properties.
*/
void
FGPanel::bind ()
{
}
/**
* Unbind panel properties.
*/
void
FGPanel::unbind ()
{
}
GLuint FGPanel::getInitDisplayList()
{
if( initDisplayList != 0 ) return initDisplayList;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if ( _flipx->getBoolValue() ) {
gluOrtho2D( _width, 0, _height, 0 ); /* up side down */
} else {
gluOrtho2D( 0, _width, 0, _height ); /* right side up */
}
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear( GL_COLOR_BUFFER_BIT);
// save some state
glPushAttrib( GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT
| GL_TEXTURE_BIT | GL_PIXEL_MODE_BIT | GL_CULL_FACE
| GL_DEPTH_BUFFER_BIT );
// Draw the background
glEnable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_ALPHA_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glDisable(GL_DEPTH_TEST);
if (_bg != NULL) {
_bg->bind();
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2f(0, 0);
glTexCoord2f(_bg_width, 0.0); glVertex2f(_width, 0);
glTexCoord2f(_bg_width, _bg_height); glVertex2f(_width, _height);
glTexCoord2f(0.0, _bg_height); glVertex2f(0, _height);
glEnd();
} else if( _mbg[0] != NULL ) {
for (int i = 0; i < 4; i ++) {
// top row of textures...(1,3,5,7)
_mbg[i*2]->bind();
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2f(i*_width/4, _height/2);
glTexCoord2f(1.0, 0.0); glVertex2f((i+1)*_width/4, _height/2);
glTexCoord2f(1.0, 1.0); glVertex2f((i+1)*_width/4, _height);
glTexCoord2f(0.0, 1.0); glVertex2f(i*_width/4, _height);
glEnd();
// bottom row of textures...(2,4,6,8)
_mbg[i*2+1]->bind();
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2f( i*_width/4, 0);
glTexCoord2f(1.0, 0.0); glVertex2f( (i+1)*_width/4, 0);
glTexCoord2f(1.0, 1.0); glVertex2f( (i+1)*_width/4, _height/2);
glTexCoord2f(0.0, 1.0); glVertex2f( i*_width/4, _height/2);
glEnd();
}
} else {
float c[4];
glGetFloatv( GL_CURRENT_COLOR, c );
glColor4f( 0.0, 0.0, 0.0, 1.0 );
glBegin(GL_QUADS);
glVertex2f(0, 0);
glVertex2f(_width, 0);
glVertex2f(_width, _height);
glVertex2f(0, _height);
glEnd();
glColor4fv( c );
}
return initDisplayList;
}
void
FGPanel::update (double dt)
{
glCallList(getInitDisplayList());
// Draw the instruments.
// Syd Adams: added instrument clipping
instrument_list_type::const_iterator current = _instruments.begin();
instrument_list_type::const_iterator end = _instruments.end();
GLdouble blx[4]={1.0,0.0,0.0,0.0};
GLdouble bly[4]={0.0,1.0,0.0,0.0};
GLdouble urx[4]={-1.0,0.0,0.0,0.0};
GLdouble ury[4]={0.0,-1.0,0.0,0.0};
for ( ; current != end; current++) {
FGPanelInstrument * instr = *current;
glPushMatrix();
glTranslated(instr->getXPos(), instr->getYPos(), 0);
int ix= instr->getWidth();
int iy= instr->getHeight();
glPushMatrix();
glTranslated(-ix/2,-iy/2,0);
glClipPlane(GL_CLIP_PLANE0,blx);
glClipPlane(GL_CLIP_PLANE1,bly);
glEnable(GL_CLIP_PLANE0);
glEnable(GL_CLIP_PLANE1);
glTranslated(ix,iy,0);
glClipPlane(GL_CLIP_PLANE2,urx);
glClipPlane(GL_CLIP_PLANE3,ury);
glEnable(GL_CLIP_PLANE2);
glEnable(GL_CLIP_PLANE3);
glPopMatrix();
instr->draw();
glPopMatrix();
}
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);
glDisable(GL_CLIP_PLANE2);
glDisable(GL_CLIP_PLANE3);
// restore some original state
glPopAttrib();
}
#if 0
/**
* Update the panel.
*/
void
FGPanel::update (double dt)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if ( _flipx->getBoolValue() ) {
gluOrtho2D( _width, 0, _height, 0 ); /* up side down */
} else {
gluOrtho2D( 0, _width, 0, _height ); /* right side up */
}
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
draw();
}
void FGPanel::draw()
{
glClear( GL_COLOR_BUFFER_BIT);
// save some state
glPushAttrib( GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT
| GL_TEXTURE_BIT | GL_PIXEL_MODE_BIT | GL_CULL_FACE
| GL_DEPTH_BUFFER_BIT );
// Draw the background
glEnable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_ALPHA_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glDisable(GL_DEPTH_TEST);
if (_bg != NULL) {
_bg->bind();
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2f(0, 0);
glTexCoord2f(_bg_width, 0.0); glVertex2f(_width, 0);
glTexCoord2f(_bg_width, _bg_height); glVertex2f(_width, _height);
glTexCoord2f(0.0, _bg_height); glVertex2f(0, _height);
glEnd();
} else if( _mbg[0] != NULL ) {
for (int i = 0; i < 4; i ++) {
// top row of textures...(1,3,5,7)
_mbg[i*2]->bind();
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2f(i*_width/4, _height/2);
glTexCoord2f(1.0, 0.0); glVertex2f((i+1)*_width/4, _height/2);
glTexCoord2f(1.0, 1.0); glVertex2f((i+1)*_width/4, _height);
glTexCoord2f(0.0, 1.0); glVertex2f(i*_width/4, _height);
glEnd();
// bottom row of textures...(2,4,6,8)
_mbg[i*2+1]->bind();
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2f( i*_width/4, 0);
glTexCoord2f(1.0, 0.0); glVertex2f( (i+1)*_width/4, 0);
glTexCoord2f(1.0, 1.0); glVertex2f( (i+1)*_width/4, _height/2);
glTexCoord2f(0.0, 1.0); glVertex2f( i*_width/4, _height/2);
glEnd();
}
} else {
float c[4];
glGetFloatv( GL_CURRENT_COLOR, c );
glColor4f( 0.0, 0.0, 0.0, 1.0 );
glBegin(GL_QUADS);
glVertex2f(0, 0);
glVertex2f(_width, 0);
glVertex2f(_width, _height);
glVertex2f(0, _height);
glEnd();
glColor4fv( c );
}
// Draw the instruments.
// Syd Adams: added instrument clipping
instrument_list_type::const_iterator current = _instruments.begin();
instrument_list_type::const_iterator end = _instruments.end();
GLdouble blx[4]={1.0,0.0,0.0,0.0};
GLdouble bly[4]={0.0,1.0,0.0,0.0};
GLdouble urx[4]={-1.0,0.0,0.0,0.0};
GLdouble ury[4]={0.0,-1.0,0.0,0.0};
for ( ; current != end; current++) {
FGPanelInstrument * instr = *current;
glPushMatrix();
glTranslated(instr->getXPos(), instr->getYPos(), 0);
int ix= instr->getWidth();
int iy= instr->getHeight();
glPushMatrix();
glTranslated(-ix/2,-iy/2,0);
glClipPlane(GL_CLIP_PLANE0,blx);
glClipPlane(GL_CLIP_PLANE1,bly);
glEnable(GL_CLIP_PLANE0);
glEnable(GL_CLIP_PLANE1);
glTranslated(ix,iy,0);
glClipPlane(GL_CLIP_PLANE2,urx);
glClipPlane(GL_CLIP_PLANE3,ury);
glEnable(GL_CLIP_PLANE2);
glEnable(GL_CLIP_PLANE3);
glPopMatrix();
instr->draw();
glPopMatrix();
}
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);
glDisable(GL_CLIP_PLANE2);
glDisable(GL_CLIP_PLANE3);
// restore some original state
glPopAttrib();
}
#endif
/**
* Set the panel's background texture.
*/
void
FGPanel::setBackground (FGCroppedTexture_ptr texture)
{
_bg = texture;
}
/**
* Set the panel's multiple background textures.
*/
void
FGPanel::setMultiBackground (FGCroppedTexture_ptr texture, int idx)
{
_bg = 0;
_mbg[idx] = texture;
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGPanelTransformation.
////////////////////////////////////////////////////////////////////////
FGPanelTransformation::FGPanelTransformation ()
: table(0)
{
}
FGPanelTransformation::~FGPanelTransformation ()
{
delete table;
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGPanelInstrument.
////////////////////////////////////////////////////////////////////////
FGPanelInstrument::FGPanelInstrument ()
{
setPosition(0, 0);
setSize(0, 0);
}
FGPanelInstrument::FGPanelInstrument (int x, int y, int w, int h)
{
setPosition(x, y);
setSize(w, h);
}
FGPanelInstrument::~FGPanelInstrument ()
{
}
void
FGPanelInstrument::setPosition (int x, int y)
{
_x = x;
_y = y;
}
void
FGPanelInstrument::setSize (int w, int h)
{
_w = w;
_h = h;
}
int
FGPanelInstrument::getXPos () const
{
return _x;
}
int
FGPanelInstrument::getYPos () const
{
return _y;
}
int
FGPanelInstrument::getWidth () const
{
return _w;
}
int
FGPanelInstrument::getHeight () const
{
return _h;
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGLayeredInstrument.
////////////////////////////////////////////////////////////////////////
FGLayeredInstrument::FGLayeredInstrument (int x, int y, int w, int h)
: FGPanelInstrument(x, y, w, h)
{
}
FGLayeredInstrument::~FGLayeredInstrument ()
{
for (layer_list::iterator it = _layers.begin(); it != _layers.end(); it++) {
delete *it;
*it = 0;
}
}
void
FGLayeredInstrument::draw ()
{
if (!test())
return;
for (int i = 0; i < (int)_layers.size(); i++) {
glPushMatrix();
_layers[i]->draw();
glPopMatrix();
}
}
int
FGLayeredInstrument::addLayer (FGInstrumentLayer *layer)
{
int n = _layers.size();
if (layer->getWidth() == -1) {
layer->setWidth(getWidth());
}
if (layer->getHeight() == -1) {
layer->setHeight(getHeight());
}
_layers.push_back(layer);
return n;
}
int
FGLayeredInstrument::addLayer (FGCroppedTexture_ptr texture, int w, int h)
{
return addLayer(new FGTexturedLayer(texture, w, h));
}
void
FGLayeredInstrument::addTransformation (FGPanelTransformation * transformation)
{
int layer = _layers.size() - 1;
_layers[layer]->addTransformation(transformation);
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGInstrumentLayer.
////////////////////////////////////////////////////////////////////////
FGInstrumentLayer::FGInstrumentLayer (int w, int h)
: _w(w),
_h(h)
{
}
FGInstrumentLayer::~FGInstrumentLayer ()
{
for (transformation_list::iterator it = _transformations.begin();
it != _transformations.end();
it++) {
delete *it;
*it = 0;
}
}
void
FGInstrumentLayer::transform () const
{
transformation_list::const_iterator it = _transformations.begin();
transformation_list::const_iterator last = _transformations.end();
while (it != last) {
FGPanelTransformation *t = *it;
if (t->test()) {
float val = (t->node == 0 ? 0.0 : t->node->getFloatValue());
if (t->has_mod)
val = fmod(val, t->mod);
if (val < t->min) {
val = t->min;
} else if (val > t->max) {
val = t->max;
}
if (t->table==0) {
val = val * t->factor + t->offset;
} else {
val = t->table->interpolate(val) * t->factor + t->offset;
}
switch (t->type) {
case FGPanelTransformation::XSHIFT:
glTranslatef(val, 0.0, 0.0);
break;
case FGPanelTransformation::YSHIFT:
glTranslatef(0.0, val, 0.0);
break;
case FGPanelTransformation::ROTATION:
glRotatef(-val, 0.0, 0.0, 1.0);
break;
}
}
it++;
}
}
void
FGInstrumentLayer::addTransformation (FGPanelTransformation * transformation)
{
_transformations.push_back(transformation);
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGGroupLayer.
////////////////////////////////////////////////////////////////////////
FGGroupLayer::FGGroupLayer ()
{
}
FGGroupLayer::~FGGroupLayer ()
{
for (unsigned int i = 0; i < _layers.size(); i++)
delete _layers[i];
}
void
FGGroupLayer::draw ()
{
if (test()) {
transform();
int nLayers = _layers.size();
for (int i = 0; i < nLayers; i++)
_layers[i]->draw( );
}
}
void
FGGroupLayer::addLayer (FGInstrumentLayer * layer)
{
_layers.push_back(layer);
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGTexturedLayer.
////////////////////////////////////////////////////////////////////////
FGTexturedLayer::FGTexturedLayer (FGCroppedTexture_ptr texture, int w, int h)
: FGInstrumentLayer(w, h),
_emissive(false),
displayList(0)
{
setTexture(texture);
}
FGTexturedLayer::~FGTexturedLayer ()
{
}
GLuint
FGTexturedLayer::getDisplayList()
{
if( displayList != 0 )
return displayList;
int w2 = _w / 2;
int h2 = _h / 2;
_texture->bind( false );
displayList = glGenLists(1);
glNewList(displayList,GL_COMPILE_AND_EXECUTE);
glBindTexture( GL_TEXTURE_2D, _texture->getTexture() );
glBegin(GL_QUADS);
glTexCoord2f(_texture->getMinX(), _texture->getMinY()); glVertex2f(-w2, -h2);
glTexCoord2f(_texture->getMaxX(), _texture->getMinY()); glVertex2f(w2, -h2);
glTexCoord2f(_texture->getMaxX(), _texture->getMaxY()); glVertex2f(w2, h2);
glTexCoord2f(_texture->getMinX(), _texture->getMaxY()); glVertex2f(-w2, h2);
glEnd();
glEndList();
return displayList;
}
void
FGTexturedLayer::draw ( )
{
if (test()) {
transform();
glCallList(getDisplayList());
}
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGTextLayer.
////////////////////////////////////////////////////////////////////////
fntRenderer FGTextLayer::text_renderer;
FGTextLayer::FGTextLayer (int w, int h)
: FGInstrumentLayer(w, h), _pointSize(14.0), _font_name("Helvetica.txf")
{
_then.stamp();
_color[0] = _color[1] = _color[2] = 0.0;
_color[3] = 1.0;
}
FGTextLayer::~FGTextLayer ()
{
chunk_list::iterator it = _chunks.begin();
chunk_list::iterator last = _chunks.end();
for ( ; it != last; it++) {
delete *it;
}
}
void
FGTextLayer::draw ()
{
if (test()) {
float c[4];
glGetFloatv( GL_CURRENT_COLOR, c );
glColor4fv(_color);
transform();
text_renderer.setFont(ApplicationProperties::fontCache.getTexFont(_font_name.c_str()));
text_renderer.setPointSize(_pointSize);
text_renderer.begin();
text_renderer.start3f(0, 0, 0);
_now.stamp();
long diff = (_now - _then).toUSecs();
if (diff > 100000 || diff < 0 ) {
// ( diff < 0 ) is a sanity check and indicates our time stamp
// difference math probably overflowed. We can handle a max
// difference of 35.8 minutes since the returned value is in
// usec. So if the panel is left off longer than that we can
// over flow the math with it is turned back on. This (diff <
// 0) catches that situation, get's us out of trouble, and
// back on track.
recalc_value();
_then = _now;
}
// Something is goofy. The code in this file renders only CCW
// polygons, and I have verified that the font code in plib
// renders only CCW trianbles. Yet they come out backwards.
// Something around here or in plib is either changing the winding
// order or (more likely) pushing a left-handed matrix onto the
// stack. But I can't find it; get out the chainsaw...
glFrontFace(GL_CW);
text_renderer.puts((char *)(_value.c_str()));
glFrontFace(GL_CCW);
text_renderer.end();
glColor4fv( c );
}
}
void
FGTextLayer::addChunk (FGTextLayer::Chunk * chunk)
{
_chunks.push_back(chunk);
}
void
FGTextLayer::setColor (float r, float g, float b)
{
_color[0] = r;
_color[1] = g;
_color[2] = b;
_color[3] = 1.0;
}
void
FGTextLayer::setPointSize (float size)
{
_pointSize = size;
}
void
FGTextLayer::setFontName(const string &name)
{
_font_name = name + ".txf";
}
void
FGTextLayer::setFont(fntFont * font)
{
FGTextLayer::text_renderer.setFont(font);
}
void
FGTextLayer::recalc_value () const
{
_value = "";
chunk_list::const_iterator it = _chunks.begin();
chunk_list::const_iterator last = _chunks.end();
for ( ; it != last; it++) {
_value += (*it)->getValue();
}
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGTextLayer::Chunk.
////////////////////////////////////////////////////////////////////////
FGTextLayer::Chunk::Chunk (const string &text, const string &fmt)
: _type(FGTextLayer::TEXT), _fmt(fmt)
{
_text = text;
if (_fmt.empty())
_fmt = "%s";
}
FGTextLayer::Chunk::Chunk (ChunkType type, const SGPropertyNode * node,
const string &fmt, float mult, float offs,
bool truncation)
: _type(type), _fmt(fmt), _mult(mult), _offs(offs), _trunc(truncation)
{
if (_fmt.empty()) {
if (type == TEXT_VALUE)
_fmt = "%s";
else
_fmt = "%.2f";
}
_node = node;
}
const char *
FGTextLayer::Chunk::getValue () const
{
if (test()) {
_buf[0] = '\0';
switch (_type) {
case TEXT:
sprintf(_buf, _fmt.c_str(), _text.c_str());
return _buf;
case TEXT_VALUE:
sprintf(_buf, _fmt.c_str(), _node->getStringValue());
break;
case DOUBLE_VALUE:
double d = _offs + _node->getFloatValue() * _mult;
if (_trunc) d = (d < 0) ? -floor(-d) : floor(d);
sprintf(_buf, _fmt.c_str(), d);
break;
}
return _buf;
} else {
return "";
}
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGSwitchLayer.
////////////////////////////////////////////////////////////////////////
FGSwitchLayer::FGSwitchLayer ()
: FGGroupLayer()
{
}
void
FGSwitchLayer::draw ()
{
if (test()) {
transform();
int nLayers = _layers.size();
for (int i = 0; i < nLayers; i++) {
if (_layers[i]->test()) {
_layers[i]->draw();
return;
}
}
}
}
// end of panel.cxx

451
utils/fgpanel/panel.hxx Normal file
View file

@ -0,0 +1,451 @@
// panel.hxx - generic support classes for a 2D panel.
//
// Written by David Megginson, started January 2000.
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef __PANEL_HXX
#define __PANEL_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <plib/fnt.h>
#include <simgear/props/condition.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/math/interpolater.hxx>
#include <simgear/sg_inlines.h>
#include "FGTextureLoaderInterface.hxx"
class FGPanelInstrument;
////////////////////////////////////////////////////////////////////////
// Texture management.
////////////////////////////////////////////////////////////////////////
class FGCroppedTexture;
typedef SGSharedPtr<FGCroppedTexture> FGCroppedTexture_ptr;
/**
* Cropped texture (should migrate out into FGFS).
*
* This structure wraps an SSG texture with cropping information.
*/
class FGCroppedTexture : public SGReferenced
{
public:
FGCroppedTexture (const string &path,
float _minX = 0.0, float _minY = 0.0,
float _maxX = 1.0, float _maxY = 1.0);
virtual ~FGCroppedTexture ();
virtual void setPath (const string &path) { _path = path; }
virtual const string &getPath () const { return _path; }
virtual void setCrop (float minX, float minY, float maxX, float maxY) {
_minX = minX; _minY = minY; _maxX = maxX; _maxY = maxY;
}
static void registerTextureLoader( const string & extension, FGTextureLoaderInterface * loader ) {
if( textureLoader.count( extension ) == 0 )
textureLoader[extension] = loader;
}
virtual float getMinX () const { return _minX; }
virtual float getMinY () const { return _minY; }
virtual float getMaxX () const { return _maxX; }
virtual float getMaxY () const { return _maxY; }
GLuint getTexture() const { return _texture; }
virtual void bind( bool doGLBind = true );
private:
string _path;
float _minX, _minY, _maxX, _maxY;
GLuint _texture;
static GLuint current_bound_texture;
static map<string,GLuint> cache;
static map<string,FGTextureLoaderInterface*> textureLoader;
};
////////////////////////////////////////////////////////////////////////
// Top-level panel.
////////////////////////////////////////////////////////////////////////
/**
* Instrument panel class.
*
* The panel is a container that has a background texture and holds
* zero or more instruments. The panel will order the instruments to
* redraw themselves when necessary, and will pass mouse clicks on to
* the appropriate instruments for processing.
*/
class FGPanel : public SGSubsystem
{
public:
FGPanel ( SGPropertyNode_ptr root );
virtual ~FGPanel ();
// Update the panel (every frame).
virtual void init ();
virtual void bind ();
virtual void unbind ();
// virtual void draw ();
virtual void update (double dt);
// transfer pointer ownership!!!
virtual void addInstrument (FGPanelInstrument * instrument);
// Background texture.
virtual void setBackground (FGCroppedTexture_ptr texture);
inline void setBackgroundWidth( double d ) {
_bg_width = d;
}
inline void setBackgroundHeight( double d ) {
_bg_height = d;
}
// Background multiple textures.
virtual void setMultiBackground (FGCroppedTexture_ptr texture , int idx);
// Full width of panel.
virtual void setWidth (int width) { _width = width; }
virtual int getWidth () const { return _width; }
// Full height of panel.
virtual void setHeight (int height) { _height = height; }
virtual int getHeight () const { return _height; }
private:
typedef vector<FGPanelInstrument *> instrument_list_type;
int _width;
int _height;
SGPropertyNode_ptr _root;
SGPropertyNode_ptr _flipx;
SGPropertyNode_ptr _rotate;
FGCroppedTexture_ptr _bg;
double _bg_width;
double _bg_height;
FGCroppedTexture_ptr _mbg[8];
// List of instruments in panel.
instrument_list_type _instruments;
GLuint initDisplayList;
GLuint getInitDisplayList();
};
////////////////////////////////////////////////////////////////////////
// Transformations.
////////////////////////////////////////////////////////////////////////
/**
* A transformation for a layer.
*/
class FGPanelTransformation : public SGConditional
{
public:
enum Type {
XSHIFT,
YSHIFT,
ROTATION
};
FGPanelTransformation ();
virtual ~FGPanelTransformation ();
Type type;
SGConstPropertyNode_ptr node;
float min;
float max;
bool has_mod;
float mod;
float factor;
float offset;
SGInterpTable * table;
};
////////////////////////////////////////////////////////////////////////
// Layers
////////////////////////////////////////////////////////////////////////
/**
* A single layer of a multi-layered instrument.
*
* Each layer can be subject to a series of transformations based
* on current FGFS instrument readings: for example, a texture
* representing a needle can rotate to show the airspeed.
*/
class FGInstrumentLayer : public SGConditional
{
public:
FGInstrumentLayer (int w = -1, int h = -1);
virtual ~FGInstrumentLayer ();
virtual void draw () = 0;
virtual void transform () const;
virtual int getWidth () const { return _w; }
virtual int getHeight () const { return _h; }
virtual void setWidth (int w) { _w = w; }
virtual void setHeight (int h) { _h = h; }
// Transfer pointer ownership!!
// DEPRECATED
virtual void addTransformation (FGPanelTransformation * transformation);
protected:
int _w, _h;
typedef vector<FGPanelTransformation *> transformation_list;
transformation_list _transformations;
};
////////////////////////////////////////////////////////////////////////
// Instruments.
////////////////////////////////////////////////////////////////////////
/**
* Abstract base class for a panel instrument.
*
* A panel instrument consists of zero or more actions, associated
* with mouse clicks in rectangular areas. Currently, the only
* concrete class derived from this is FGLayeredInstrument, but others
* may show up in the future (some complex instruments could be
* entirely hand-coded, for example).
*/
class FGPanelInstrument : public SGConditional
{
public:
FGPanelInstrument ();
FGPanelInstrument (int x, int y, int w, int h);
virtual ~FGPanelInstrument ();
virtual void draw () = 0;
virtual void setPosition(int x, int y);
virtual void setSize(int w, int h);
virtual int getXPos () const;
virtual int getYPos () const;
virtual int getWidth () const;
virtual int getHeight () const;
protected:
int _x, _y, _w, _h;
};
/**
* An instrument constructed of multiple layers.
*
* Each individual layer can be rotated or shifted to correspond
* to internal FGFS instrument readings.
*/
class FGLayeredInstrument : public FGPanelInstrument
{
public:
FGLayeredInstrument (int x, int y, int w, int h);
virtual ~FGLayeredInstrument ();
virtual void draw ();
// Transfer pointer ownership!!
virtual int addLayer (FGInstrumentLayer *layer);
virtual int addLayer (FGCroppedTexture_ptr texture, int w = -1, int h = -1);
// Transfer pointer ownership!!
virtual void addTransformation (FGPanelTransformation * transformation);
protected:
typedef vector<FGInstrumentLayer *> layer_list;
layer_list _layers;
};
/**
* An instrument layer containing a group of sublayers.
*
* This class is useful for gathering together a group of related
* layers, either to hold in an external file or to work under
* the same condition.
*/
class FGGroupLayer : public FGInstrumentLayer
{
public:
FGGroupLayer ();
virtual ~FGGroupLayer ();
virtual void draw ();
// transfer pointer ownership
virtual void addLayer (FGInstrumentLayer * layer);
protected:
vector<FGInstrumentLayer *> _layers;
};
/**
* A textured layer of an instrument.
*
* This is a layer holding a single texture. Normally, the texture's
* backgound should be transparent so that lower layers and the panel
* background can show through.
*/
class FGTexturedLayer : public FGInstrumentLayer
{
public:
FGTexturedLayer (int w = -1, int h = -1) : FGInstrumentLayer(w, h) {}
FGTexturedLayer (FGCroppedTexture_ptr texture, int w = -1, int h = -1);
virtual ~FGTexturedLayer ();
virtual void draw ();
virtual void setTexture (FGCroppedTexture_ptr texture) {
_texture = texture;
}
FGCroppedTexture_ptr getTexture() { return _texture; }
void setEmissive(bool e) { _emissive = e; }
private:
GLuint getDisplayList();
FGCroppedTexture_ptr _texture;
bool _emissive;
GLuint displayList;
};
/**
* A text layer of an instrument.
*
* This is a layer holding a string of static and/or generated text.
* It is useful for instruments that have text displays, such as
* a chronometer, GPS, or NavCom radio.
*/
class FGTextLayer : public FGInstrumentLayer
{
public:
enum ChunkType {
TEXT,
TEXT_VALUE,
DOUBLE_VALUE
};
class Chunk : public SGConditional
{
public:
Chunk (const string &text, const string &fmt = "%s");
Chunk (ChunkType type, const SGPropertyNode * node,
const string &fmt = "", float mult = 1.0, float offs = 0.0,
bool truncation = false);
const char * getValue () const;
private:
ChunkType _type;
string _text;
SGConstPropertyNode_ptr _node;
string _fmt;
float _mult;
float _offs;
bool _trunc;
mutable char _buf[1024];
};
FGTextLayer (int w = -1, int h = -1);
virtual ~FGTextLayer ();
virtual void draw ();
// Transfer pointer!!
virtual void addChunk (Chunk * chunk);
virtual void setColor (float r, float g, float b);
virtual void setPointSize (float size);
virtual void setFontName ( const string &name );
virtual void setFont (fntFont * font);
private:
void recalc_value () const;
typedef vector<Chunk *> chunk_list;
chunk_list _chunks;
float _color[4];
float _pointSize;
mutable string _font_name;
mutable string _value;
mutable SGTimeStamp _then;
mutable SGTimeStamp _now;
static fntRenderer text_renderer;
};
/**
* A group layer that switches among its children.
*
* The first layer that passes its condition will be drawn, and
* any following layers will be ignored.
*/
class FGSwitchLayer : public FGGroupLayer
{
public:
// Transfer pointers!!
FGSwitchLayer ();
virtual void draw ();
};
#endif // __PANEL_HXX
// end of panel.hxx

591
utils/fgpanel/panel_io.cxx Normal file
View file

@ -0,0 +1,591 @@
// panel_io.cxx - I/O for 2D panel.
//
// Written by David Megginson, started January 2000.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id: panel_io.cxx,v 1.26 2006/08/10 11:12:39 mfranz Exp $
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_WINDOWS_H
# include <windows.h>
#endif
#include <string.h> // for strcmp()
#include <simgear/compiler.h>
#include <simgear/structure/exception.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/condition.hxx>
#include "panel.hxx"
#include "panel_io.hxx"
#include "ApplicationProperties.hxx"
////////////////////////////////////////////////////////////////////////
// Read and construct a panel.
//
// The panel is specified as a regular property list, and each of the
// instruments is its own, separate property list (and thus, a separate
// XML document). The functions in this section read in the files
// as property lists, then extract properties to set up the panel
// itself.
//
// A panel contains zero or more instruments.
//
// An instrument contains one or more layers and zero or more actions.
//
// A layer contains zero or more transformations.
//
// Some special types of layers also contain other objects, such as
// chunks of text or other layers.
//
// There are currently four types of layers:
//
// 1. Textured Layer (type="texture"), the default
// 2. Text Layer (type="text")
// 3. Switch Layer (type="switch")
// 4. Built-in Layer (type="built-in", must also specify class)
//
// The only built-in layer so far is the ribbon for the magnetic compass
// (class="compass-ribbon").
//
// There are three types of actions:
//
// 1. Adjust (type="adjust"), the default
// 2. Swap (type="swap")
// 3. Toggle (type="toggle")
//
// There are three types of transformations:
//
// 1. X shift (type="x-shift"), the default
// 2. Y shift (type="y-shift")
// 3. Rotation (type="rotation")
//
// Each of these may be associated with a property, so that a needle
// will rotate with the airspeed, for example, or may have a fixed
// floating-point value.
////////////////////////////////////////////////////////////////////////
/**
* Read a cropped texture from the instrument's property list.
*
* The x1 and y1 properties give the starting position of the texture
* (between 0.0 and 1.0), and the the x2 and y2 properties give the
* ending position. For example, to use the bottom-left quarter of a
* texture, x1=0.0, y1=0.0, x2=0.5, y2=0.5.
*/
static FGCroppedTexture_ptr
readTexture (const SGPropertyNode * node)
{
return new FGCroppedTexture(node->getStringValue("path"),
node->getFloatValue("x1"),
node->getFloatValue("y1"),
node->getFloatValue("x2", 1.0),
node->getFloatValue("y2", 1.0));
SG_LOG(SG_COCKPIT, SG_DEBUG, "Read texture " << node->getName());
}
/**
* Test for a condition in the current node.
*/
////////////////////////////////////////////////////////////////////////
// Read a condition and use it if necessary.
////////////////////////////////////////////////////////////////////////
static void
readConditions (SGConditional *component, const SGPropertyNode *node)
{
const SGPropertyNode * conditionNode = node->getChild("condition");
if (conditionNode != 0)
// The top level is implicitly AND
component->setCondition(sgReadCondition(ApplicationProperties::Properties,
conditionNode) );
;
}
/**
* Read a transformation from the instrument's property list.
*
* The panel module uses the transformations to slide or spin needles,
* knobs, and other indicators, and to place layers in the correct
* positions. Every layer starts centered exactly on the x,y co-ordinate,
* and many layers need to be moved or rotated simply to display the
* instrument correctly.
*
* There are three types of transformations:
*
* "x-shift" - move the layer horizontally.
*
* "y-shift" - move the layer vertically.
*
* "rotation" - rotate the layer.
*
* Each transformation may have a fixed offset, and may also have
* a floating-point property value to add to the offset. The
* floating-point property may be clamped to a minimum and/or
* maximum range and scaled (after clamping).
*
* Note that because of the way OpenGL works, transformations will
* appear to be applied backwards.
*/
static FGPanelTransformation *
readTransformation (const SGPropertyNode * node, float w_scale, float h_scale)
{
FGPanelTransformation * t = new FGPanelTransformation;
string name = node->getName();
string type = node->getStringValue("type");
string propName = node->getStringValue("property", "");
const SGPropertyNode * target = 0;
if (type.empty()) {
SG_LOG( SG_COCKPIT, SG_INFO,
"No type supplied for transformation " << name
<< " assuming \"rotation\"" );
type = "rotation";
}
if (!propName.empty())
target = ApplicationProperties::Properties->getNode(propName.c_str(), true);
t->node = target;
t->min = node->getFloatValue("min", -9999999);
t->max = node->getFloatValue("max", 99999999);
t->has_mod = node->hasChild("modulator");
if (t->has_mod)
t->mod = node->getFloatValue("modulator");
t->factor = node->getFloatValue("scale", 1.0);
t->offset = node->getFloatValue("offset", 0.0);
// Check for an interpolation table
const SGPropertyNode * trans_table = node->getNode("interpolation");
if (trans_table != 0) {
SG_LOG( SG_COCKPIT, SG_INFO, "Found interpolation table with "
<< trans_table->nChildren() << " children" );
t->table = new SGInterpTable();
for (int i = 0; i < trans_table->nChildren(); i++) {
const SGPropertyNode * node = trans_table->getChild(i);
if (!strcmp(node->getName(), "entry")) {
double ind = node->getDoubleValue("ind", 0.0);
double dep = node->getDoubleValue("dep", 0.0);
SG_LOG( SG_COCKPIT, SG_INFO, "Adding interpolation entry "
<< ind << "==>" << dep );
t->table->addEntry(ind, dep);
} else {
SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
<< " in interpolation" );
}
}
} else {
t->table = 0;
}
// Move the layer horizontally.
if (type == "x-shift") {
t->type = FGPanelTransformation::XSHIFT;
// t->min *= w_scale; //removed by Martin Dressler
// t->max *= w_scale; //removed by Martin Dressler
t->offset *= w_scale;
t->factor *= w_scale; //Added by Martin Dressler
}
// Move the layer vertically.
else if (type == "y-shift") {
t->type = FGPanelTransformation::YSHIFT;
//t->min *= h_scale; //removed
//t->max *= h_scale; //removed
t->offset *= h_scale;
t->factor *= h_scale; //Added
}
// Rotate the layer. The rotation
// is in degrees, and does not need
// to scale with the instrument size.
else if (type == "rotation") {
t->type = FGPanelTransformation::ROTATION;
}
else {
SG_LOG( SG_COCKPIT, SG_ALERT, "Unrecognized transformation type " << type );
delete t;
return 0;
}
readConditions(t, node);
SG_LOG( SG_COCKPIT, SG_DEBUG, "Read transformation " << name );
return t;
}
/**
* Read a chunk of text from the instrument's property list.
*
* A text layer consists of one or more chunks of text. All chunks
* share the same font size and color (and eventually, font), but
* each can come from a different source. There are three types of
* text chunks:
*
* "literal" - a literal text string (the default)
*
* "text-value" - the current value of a string property
*
* "number-value" - the current value of a floating-point property.
*
* All three may also include a printf-style format string.
*/
FGTextLayer::Chunk *
readTextChunk (const SGPropertyNode * node)
{
FGTextLayer::Chunk * chunk;
string name = node->getStringValue("name");
string type = node->getStringValue("type");
string format = node->getStringValue("format");
// Default to literal text.
if (type.empty()) {
SG_LOG( SG_COCKPIT, SG_INFO, "No type provided for text chunk " << name
<< " assuming \"literal\"");
type = "literal";
}
// A literal text string.
if (type == "literal") {
string text = node->getStringValue("text");
chunk = new FGTextLayer::Chunk(text, format);
}
// The value of a string property.
else if (type == "text-value") {
SGPropertyNode * target =
ApplicationProperties::Properties->getNode( node->getStringValue("property"), true);
chunk = new FGTextLayer::Chunk(FGTextLayer::TEXT_VALUE, target, format);
}
// The value of a float property.
else if (type == "number-value") {
string propName = node->getStringValue("property");
float scale = node->getFloatValue("scale", 1.0);
float offset = node->getFloatValue("offset", 0.0);
bool truncation = node->getBoolValue("truncate", false);
SGPropertyNode * target = ApplicationProperties::Properties->getNode(propName.c_str(), true);
chunk = new FGTextLayer::Chunk(FGTextLayer::DOUBLE_VALUE, target,
format, scale, offset, truncation);
}
// Unknown type.
else {
SG_LOG( SG_COCKPIT, SG_ALERT, "Unrecognized type " << type
<< " for text chunk " << name );
return 0;
}
readConditions(chunk, node);
return chunk;
}
/**
* Read a single layer from an instrument's property list.
*
* Each instrument consists of one or more layers stacked on top
* of each other; the lower layers show through only where the upper
* layers contain an alpha component. Each layer can be moved
* horizontally and vertically and rotated using transformations.
*
* This module currently recognizes four kinds of layers:
*
* "texture" - a layer containing a texture (the default)
*
* "text" - a layer containing text
*
* "switch" - a layer that switches between two other layers
* based on the current value of a boolean property.
*
* "built-in" - a hard-coded layer supported by C++ code in FlightGear.
*
* Currently, the only built-in layer class is "compass-ribbon".
*/
static FGInstrumentLayer *
readLayer (const SGPropertyNode * node, float w_scale, float h_scale)
{
FGInstrumentLayer * layer = NULL;
string name = node->getStringValue("name");
string type = node->getStringValue("type");
int w = node->getIntValue("w", -1);
int h = node->getIntValue("h", -1);
bool emissive = node->getBoolValue("emissive", false);
if (w != -1)
w = int(w * w_scale);
if (h != -1)
h = int(h * h_scale);
if (type.empty()) {
SG_LOG( SG_COCKPIT, SG_INFO,
"No type supplied for layer " << name
<< " assuming \"texture\"" );
type = "texture";
}
// A textured instrument layer.
if (type == "texture") {
FGCroppedTexture_ptr texture = readTexture(node->getNode("texture"));
layer = new FGTexturedLayer(texture, w, h);
if (emissive) {
FGTexturedLayer *tl=(FGTexturedLayer*)layer;
tl->setEmissive(true);
}
}
// A group of sublayers.
else if (type == "group") {
layer = new FGGroupLayer();
for (int i = 0; i < node->nChildren(); i++) {
const SGPropertyNode * child = node->getChild(i);
if (!strcmp(child->getName(), "layer"))
((FGGroupLayer *)layer)->addLayer(readLayer(child, w_scale, h_scale));
}
}
// A textual instrument layer.
else if (type == "text") {
FGTextLayer * tlayer = new FGTextLayer(w, h); // FIXME
// Set the text color.
float red = node->getFloatValue("color/red", 0.0);
float green = node->getFloatValue("color/green", 0.0);
float blue = node->getFloatValue("color/blue", 0.0);
tlayer->setColor(red, green, blue);
// Set the point size.
float pointSize = node->getFloatValue("point-size", 10.0) * w_scale;
tlayer->setPointSize(pointSize);
// Set the font.
string fontName = node->getStringValue("font", "Helvetica");
tlayer->setFontName(fontName);
const SGPropertyNode * chunk_group = node->getNode("chunks");
if (chunk_group != 0) {
int nChunks = chunk_group->nChildren();
for (int i = 0; i < nChunks; i++) {
const SGPropertyNode * node = chunk_group->getChild(i);
if (!strcmp(node->getName(), "chunk")) {
FGTextLayer::Chunk * chunk = readTextChunk(node);
if (chunk != 0)
tlayer->addChunk(chunk);
} else {
SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
<< " in chunks" );
}
}
layer = tlayer;
}
}
// A switch instrument layer.
else if (type == "switch") {
layer = new FGSwitchLayer();
for (int i = 0; i < node->nChildren(); i++) {
const SGPropertyNode * child = node->getChild(i);
if (!strcmp(child->getName(), "layer"))
((FGGroupLayer *)layer)->addLayer(readLayer(child, w_scale, h_scale));
}
}
// An unknown type.
else {
SG_LOG( SG_COCKPIT, SG_ALERT, "Unrecognized layer type " << type );
delete layer;
return 0;
}
//
// Get the transformations for each layer.
//
const SGPropertyNode * trans_group = node->getNode("transformations");
if (trans_group != 0) {
int nTransformations = trans_group->nChildren();
for (int i = 0; i < nTransformations; i++) {
const SGPropertyNode * node = trans_group->getChild(i);
if (!strcmp(node->getName(), "transformation")) {
FGPanelTransformation * t = readTransformation(node, w_scale, h_scale);
if (t != 0)
layer->addTransformation(t);
} else {
SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
<< " in transformations" );
}
}
}
readConditions(layer, node);
SG_LOG( SG_COCKPIT, SG_DEBUG, "Read layer " << name );
return layer;
}
/**
* Read an instrument from a property list.
*
* The instrument consists of a preferred width and height
* (the panel may override these), together with a list of layers
* and a list of actions to be performed when the user clicks
* the mouse over the instrument. All co-ordinates are relative
* to the instrument's position, so instruments are fully relocatable;
* likewise, co-ordinates for actions and transformations will be
* scaled automatically if the instrument is not at its preferred size.
*/
static FGPanelInstrument *
readInstrument (const SGPropertyNode * node)
{
const string name = node->getStringValue("name");
int x = node->getIntValue("x", -1);
int y = node->getIntValue("y", -1);
int real_w = node->getIntValue("w", -1);
int real_h = node->getIntValue("h", -1);
int w = node->getIntValue("w-base", -1);
int h = node->getIntValue("h-base", -1);
if (x == -1 || y == -1) {
SG_LOG( SG_COCKPIT, SG_ALERT,
"x and y positions must be specified and > 0" );
return 0;
}
float w_scale = 1.0;
float h_scale = 1.0;
if (real_w != -1) {
w_scale = float(real_w) / float(w);
w = real_w;
}
if (real_h != -1) {
h_scale = float(real_h) / float(h);
h = real_h;
}
SG_LOG( SG_COCKPIT, SG_DEBUG, "Reading instrument " << name );
FGLayeredInstrument * instrument =
new FGLayeredInstrument(x, y, w, h);
//
// Get the layers for the instrument.
//
const SGPropertyNode * layer_group = node->getNode("layers");
if (layer_group != 0) {
int nLayers = layer_group->nChildren();
for (int i = 0; i < nLayers; i++) {
const SGPropertyNode * node = layer_group->getChild(i);
if (!strcmp(node->getName(), "layer")) {
FGInstrumentLayer * layer = readLayer(node, w_scale, h_scale);
if (layer != 0)
instrument->addLayer(layer);
} else {
SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
<< " in layers" );
}
}
}
readConditions(instrument, node);
SG_LOG( SG_COCKPIT, SG_DEBUG, "Done reading instrument " << name );
return instrument;
}
/**
* Construct the panel from a property tree.
*/
SGSharedPtr<FGPanel>
FGReadablePanel::read(SGPropertyNode_ptr root)
{
SG_LOG( SG_COCKPIT, SG_INFO, "Reading properties for panel " <<
root->getStringValue("name", "[Unnamed Panel]") );
FGPanel * panel = new FGPanel(root);
panel->setWidth(root->getIntValue("w", 1024));
panel->setHeight(root->getIntValue("h", 443));
SG_LOG( SG_COCKPIT, SG_INFO, "Size=" << panel->getWidth() << "x" << panel->getHeight() );
// Assign the background texture, if any, or a bogus chequerboard.
//
string bgTexture = root->getStringValue("background");
if( !bgTexture.empty() )
panel->setBackground( new FGCroppedTexture( bgTexture ) );
panel->setBackgroundWidth( root->getDoubleValue( "background-width", 1.0 ) );
panel->setBackgroundHeight( root->getDoubleValue( "background-height", 1.0 ) );
SG_LOG( SG_COCKPIT, SG_INFO, "Set background texture to " << bgTexture );
//
// Get multibackground if any...
//
for( int i = 0; i < 8; i++ ) {
SGPropertyNode * mbgNode = root->getChild( "multibackground", i );
string mbgTexture;
if( mbgNode != NULL ) mbgTexture = mbgNode->getStringValue();
if( mbgTexture.empty() ) {
if( i == 0 ) break; // if first texture is missing, ignore the rest
else mbgTexture = "FOO"; // if others are missing - set default texture
}
panel->setMultiBackground( new FGCroppedTexture(mbgTexture), i );
SG_LOG( SG_COCKPIT, SG_INFO, "Set multi-background texture" << i << " to " << mbgTexture );
}
//
// Create each instrument.
//
SG_LOG( SG_COCKPIT, SG_INFO, "Reading panel instruments" );
const SGPropertyNode * instrument_group = root->getChild("instruments");
if (instrument_group != 0) {
int nInstruments = instrument_group->nChildren();
for (int i = 0; i < nInstruments; i++) {
const SGPropertyNode * node = instrument_group->getChild(i);
if (!strcmp(node->getName(), "instrument")) {
FGPanelInstrument * instrument = readInstrument(node);
if (instrument != 0)
panel->addInstrument(instrument);
} else {
SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
<< " in instruments section" );
}
}
}
SG_LOG( SG_COCKPIT, SG_INFO, "Done reading panel instruments" );
//
// Return the new panel.
//
return panel;
}
// end of panel_io.cxx

View file

@ -0,0 +1,40 @@
// panel_io.cxx - I/O for 2D panel.
//
// Written by David Megginson, started January 2000.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id: panel_io.hxx,v 1.6 2006/04/17 13:03:43 mfranz Exp $
#ifndef __PANEL_IO_HXX
#define __PANEL_IO_HXX
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_WINDOWS_H
# include <windows.h>
#endif
#include "panel.hxx"
class FGReadablePanel : public FGPanel {
public:
static SGSharedPtr<FGPanel> read(SGPropertyNode_ptr root);
};
#endif // __PANEL_IO_HXX