Merge branch 'next' of http://git.gitorious.org/fg/flightgear into next
This commit is contained in:
commit
06bd56a8e8
85 changed files with 4793 additions and 531 deletions
|
@ -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;
|
||||
|
|
|
@ -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;}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
71
src/FDM/JSBSim/input_output/FGPropertyManager.cpp
Normal file → Executable 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
40
src/FDM/JSBSim/input_output/FGScript.cpp
Normal file → Executable 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;
|
||||
|
|
|
@ -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 "run" section, where the conditions are
|
||||
described in "event" 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
8
src/FDM/JSBSim/input_output/FGXMLElement.cpp
Normal file → Executable 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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
20
src/FDM/JSBSim/math/FGFunction.cpp
Normal file → Executable 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
6
src/FDM/JSBSim/math/FGParameter.h
Normal file → Executable 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
38
src/FDM/JSBSim/math/FGPropertyValue.cpp
Normal file → Executable 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
16
src/FDM/JSBSim/math/FGPropertyValue.h
Normal file → Executable 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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
26
src/FDM/JSBSim/models/FGAuxiliary.cpp
Normal file → Executable 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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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="-";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
125
src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp
Normal file → Executable 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
28
src/FDM/JSBSim/models/propulsion/FGTurboProp.h
Normal file → Executable 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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
7
utils/fgpanel/.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
fgpanel
|
||||
*.o
|
||||
*.obj
|
||||
.deps
|
||||
*.Po
|
||||
Makefile
|
||||
Makefile.in
|
31
utils/fgpanel/ApplicationProperties.hxx
Normal file
31
utils/fgpanel/ApplicationProperties.hxx
Normal 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
|
208
utils/fgpanel/FGFontCache.cxx
Normal file
208
utils/fgpanel/FGFontCache.cxx
Normal 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
|
||||
|
86
utils/fgpanel/FGFontCache.hxx
Normal file
86
utils/fgpanel/FGFontCache.hxx
Normal 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
|
94
utils/fgpanel/FGGLApplication.cxx
Normal file
94
utils/fgpanel/FGGLApplication.cxx
Normal 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();
|
||||
}
|
48
utils/fgpanel/FGGLApplication.hxx
Normal file
48
utils/fgpanel/FGGLApplication.hxx
Normal 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
|
142
utils/fgpanel/FGPNGTextureLoader.cxx
Normal file
142
utils/fgpanel/FGPNGTextureLoader.cxx
Normal 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;
|
||||
}
|
26
utils/fgpanel/FGPNGTextureLoader.hxx
Normal file
26
utils/fgpanel/FGPNGTextureLoader.hxx
Normal 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
|
279
utils/fgpanel/FGPanelApplication.cxx
Normal file
279
utils/fgpanel/FGPanelApplication.cxx
Normal 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;
|
55
utils/fgpanel/FGPanelApplication.hxx
Normal file
55
utils/fgpanel/FGPanelApplication.hxx
Normal 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
|
154
utils/fgpanel/FGPanelProtocol.cxx
Normal file
154
utils/fgpanel/FGPanelProtocol.cxx
Normal 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();
|
||||
}
|
41
utils/fgpanel/FGPanelProtocol.hxx
Normal file
41
utils/fgpanel/FGPanelProtocol.hxx
Normal 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
|
504
utils/fgpanel/FGRGBTextureLoader.cxx
Normal file
504
utils/fgpanel/FGRGBTextureLoader.cxx
Normal 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;
|
||||
}
|
||||
|
26
utils/fgpanel/FGRGBTextureLoader.hxx
Normal file
26
utils/fgpanel/FGRGBTextureLoader.hxx
Normal 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
|
27
utils/fgpanel/FGTextureLoaderInterface.hxx
Normal file
27
utils/fgpanel/FGTextureLoaderInterface.hxx
Normal 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
20
utils/fgpanel/Makefile.am
Normal 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
148
utils/fgpanel/README
Normal 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
30
utils/fgpanel/main.cxx
Normal 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
962
utils/fgpanel/panel.cxx
Normal 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
451
utils/fgpanel/panel.hxx
Normal 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
591
utils/fgpanel/panel_io.cxx
Normal 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
|
||||
|
||||
|
||||
|
40
utils/fgpanel/panel_io.hxx
Normal file
40
utils/fgpanel/panel_io.hxx
Normal 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
|
Loading…
Add table
Reference in a new issue