1
0
Fork 0

Merge branch 'next-2' into multiplayer-dev

This commit is contained in:
Richard Harrison 2017-02-23 22:35:27 +01:00
commit c5cc666288
188 changed files with 9190 additions and 4157 deletions

View file

@ -2,4 +2,4 @@
add_definitions(-DSQLITE_OMIT_LOAD_EXTENSION)
add_definitions(-DNDEBUG)
add_library(fgsqlite3 sqlite3.c)
set_target_properties(fgsqlite3 PROPERTIES COMPILE_FLAGS "-fno-fast-math")
set_target_properties(fgsqlite3 PROPERTIES COMPILE_FLAGS "-fpic -fno-fast-math")

View file

@ -25,6 +25,13 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
"MinSizeRel" "RelWithDebInfo")
endif()
if(NOT FG_BUILD_TYPE)
message(STATUS "Setting build type to 'Dev' as none was specified.")
set(FG_BUILD_TYPE Dev CACHE STRING "Choose the FlightGear build type" FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE FG_BUILD_TYPE PROPERTY STRINGS "Dev" "Nightly" "Release")
endif()
if(APPLE)
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks")
# when building, don't use the install RPATH already
@ -176,8 +183,6 @@ option(SYSTEM_SPEEX "Set to ON to build IAXClient with the system's speex a
option(SYSTEM_GSM "Set to ON to build IAXClient with the system's GSM library" ${SYSTEM_GSM_DEFAULT})
option(SYSTEM_FLITE "Set to ON to build Flightgear with the system's Flite library" ${SYSTEM_FLITE_DEFAULT})
option(SYSTEM_HTS_ENGINE "Set to ON to build Flightgear with the system's HTS Engine library" ${SYSTEM_HTS_ENGINE_DEFAULT})
option(FG_NIGHTLY "Set to ON to mark this as a nightly build" OFF)
option(ENABLE_DEV_WARNINGS "Set to ON to include developer-warnings" OFF)
# additional utilities
option(ENABLE_FGELEV "Set to ON to build the fgelev application (default)" ON)
@ -194,6 +199,7 @@ option(ENABLE_FLITE "Set to ON to build the Flite text-to-speech module" ON
option(ENABLE_QT "Set to ON to build the internal Qt launcher" ON)
option(ENABLE_TRAFFIC "Set to ON to build the external traffic generator modules" ON)
option(ENABLE_FGQCANVAS "Set to ON to build the Qt-based remote canvas application" OFF)
option(ENABLE_DEMCONVERT "Set to ON to build the dem conversion tool (default)" ON)
include (DetectArch)
@ -305,7 +311,7 @@ endif (USE_DBUS)
## Qt5 setup setup
if (ENABLE_QT)
message(STATUS "Qt launcher enabled, checking for Qt 5.1 / qmake")
find_package(Qt5 5.1 COMPONENTS Widgets)
find_package(Qt5 5.1 COMPONENTS Widgets Network)
if (Qt5Widgets_FOUND)
message(STATUS "Will enable Qt launcher GUI")
message(STATUS " Qt5Widgets version: ${Qt5Widgets_VERSION_STRING}")
@ -357,6 +363,24 @@ else()
message(STATUS "RTI: DISABLED")
endif(ENABLE_RTI)
if(ENABLE_GDAL)
find_package(GDAL 2.0.0 REQUIRED)
endif(ENABLE_GDAL)
include_directories(${GDAL_INCLUDE_DIR})
if (ENABLE_OPENMP)
find_package(OpenMP)
if(OPENMP_FOUND)
message(STATUS "OpenMP: ENABLED")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
else()
message(STATUS "OpenMP: NOT FOUND")
endif()
else()
message(STATUS "OpenMP: DISABLED")
endif()
if (ENABLE_SIMD)
message(STATUS "SSE/SSE2 support: ENABLED")
else()
@ -485,6 +509,23 @@ configure_file (
add_subdirectory(3rdparty)
add_subdirectory(utils)
if(ENABLE_TESTS)
# enable CTest / make test target
message(STATUS "Tests: ENABLED")
include (Dart)
enable_testing()
if(WIN32)
# tests disabled until shared library export is fixed on Windows
message(STATUS "Tests disabled on Windows for the moment")
else()
add_subdirectory(tests)
endif()
else()
message(STATUS "Tests: DISABLED")
endif(ENABLE_TESTS)
add_subdirectory(src)
add_subdirectory(man)

View file

@ -25,7 +25,6 @@
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
#include <Airports/dynamics.hxx>
#include <Airports/airport.hxx>
#include <Main/util.hxx>
@ -551,7 +550,7 @@ void FGAIAircraft::getGroundElev(double dt) {
}
double range = 500.0;
if (globals->get_tile_mgr()->schedule_scenery(pos, range, 5.0))
if (globals->get_scenery()->schedule_scenery(pos, range, 5.0))
{
double alt;
if (getGroundElevationM(SGGeod::fromGeodM(pos, 20000), alt, 0))

View file

@ -576,11 +576,9 @@ void FGSubmodelMgr::setData(int id, const string& path, bool serviceable, const
sm->pitch_offset = new FGXMLAutopilot::InputValue(*prop_root, b ? *b : n);
if (b) old = true;
#if defined(ENABLE_DEV_WARNINGS)
if (old) {
SG_LOG(SG_AI, SG_WARN, "Submodels: <*-offset> is deprecated. Use <offsets> instead");
SG_LOG(SG_AI, SG_DEV_WARN, "Submodels: <*-offset> is deprecated. Use <offsets> instead");
}
#endif
}
// Randomness

View file

@ -36,7 +36,7 @@ static string NO_ATIS("nil");
static string EMPTY("");
#define SPACE append(1,' ')
const char * ATCSpeech::getSpokenDigit( int i )
std::string ATCSpeech::getSpokenDigit( int i )
{
string key = "n" + boost::lexical_cast<std::string>( i );
return globals->get_locale()->getLocalizedString(key.c_str(), "atc", "" );
@ -55,7 +55,7 @@ string ATCSpeech::getSpokenNumber( string number )
string ATCSpeech::getSpokenNumber( int number, bool leadingZero, int digits )
{
vector<const char *> spokenDigits;
string_list spokenDigits;
bool negative = false;
if( number < 0 ) {
negative = true;

View file

@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class ATCSpeech {
public:
static const char * getSpokenDigit( int i );
static std::string getSpokenDigit( int i );
static std::string getSpokenNumber( std::string number );
static std::string getSpokenNumber( int number, bool leadingZero = false, int digits = 1 );
static std::string getSpokenAltitude( int altitude );

View file

@ -1,3 +1,5 @@
#include "config.h"
#include "CommStation.hxx"
#include <Airports/airport.hxx>
#include <Navaids/NavDataCache.hxx>

View file

@ -724,7 +724,7 @@ void FGAirport::validateILSData()
SGPath path;
if (!XMLLoader::findAirportData(ident(), "ils", path)) {
return; // no XML tower data
return; // no XML ILS data
}
try {

View file

@ -99,7 +99,6 @@ void APTLoader::readAptDatFile(const SGPath &aptdb_file,
sg_location(aptdb_file));
}
SG_LOG( SG_GENERAL, SG_INFO, "Opened apt.dat file: '" << apt_dat << "'" );
string line;
unsigned int rowCode = 0; // terminology used in the apt.dat format spec

View file

@ -69,7 +69,7 @@ void FGGroundNetXMLLoader::endXML ()
for (it = _parkingPushbacks.begin(); it != _parkingPushbacks.end(); ++it) {
NodeIndexMap::const_iterator j = _indexMap.find(it->second);
if (j == _indexMap.end()) {
SG_LOG(SG_NAVAID, SG_WARN, "bad groundnet, no node for index:" << it->first);
SG_LOG(SG_NAVAID, SG_DEV_WARN, "bad groundnet, no node for index:" << it->first);
continue;
}
@ -78,7 +78,7 @@ void FGGroundNetXMLLoader::endXML ()
}
BOOST_FOREACH(FGTaxiNodeRef node, _unreferencedNodes) {
SG_LOG(SG_NAVAID, SG_WARN, "unreferenced groundnet node:" << node->ident());
SG_LOG(SG_NAVAID, SG_DEV_WARN, "unreferenced groundnet node:" << node->ident());
}
}
@ -173,7 +173,7 @@ void FGGroundNetXMLLoader::startNode(const XMLAttributes &atts)
}
if (_indexMap.find(index) != _indexMap.end()) {
SG_LOG(SG_NAVAID, SG_WARN, "duplicate ground-net index:" << index);
SG_LOG(SG_NAVAID, SG_DEV_WARN, "duplicate ground-net index:" << index);
}
SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
@ -200,7 +200,7 @@ void FGGroundNetXMLLoader::startArc(const XMLAttributes &atts)
IntPair e(begin, end);
if (_arcSet.find(e) != _arcSet.end()) {
SG_LOG(SG_NAVAID, SG_WARN, _groundNetwork->airport()->ident() << " ground-net: skipping duplicate edge:" << begin << "->" << end);
SG_LOG(SG_NAVAID, SG_DEV_WARN, _groundNetwork->airport()->ident() << " ground-net: skipping duplicate edge:" << begin << "->" << end);
return;
}
@ -208,7 +208,7 @@ void FGGroundNetXMLLoader::startArc(const XMLAttributes &atts)
FGTaxiNodeRef fromNode, toNode;
it = _indexMap.find(begin);
if (it == _indexMap.end()) {
SG_LOG(SG_NAVAID, SG_WARN, "ground-net: bad edge:" << begin << "->" << end << ", begin index unknown");
SG_LOG(SG_NAVAID, SG_DEV_WARN, "ground-net: bad edge:" << begin << "->" << end << ", begin index unknown");
return;
} else {
_unreferencedNodes.erase(it->second);
@ -217,7 +217,7 @@ void FGGroundNetXMLLoader::startArc(const XMLAttributes &atts)
it = _indexMap.find(end);
if (it == _indexMap.end()) {
SG_LOG(SG_NAVAID, SG_WARN, "ground-net: bad edge:" << begin << "->" << end << ", end index unknown");
SG_LOG(SG_NAVAID, SG_DEV_WARN, "ground-net: bad edge:" << begin << "->" << end << ", end index unknown");
return;
} else {
_unreferencedNodes.erase(it->second);

View file

@ -1,3 +1,5 @@
#include "config.h"
#include "gnnode.hxx"
#include <boost/foreach.hpp>

View file

@ -259,16 +259,16 @@ void FGRouteMgr::init() {
magvar = fgGetNode("/environment/magnetic-variation-deg", true);
departure = fgGetNode(RM "departure", true);
departure->tie("airport", SGRawValueMethods<FGRouteMgr, const char*>(*this,
departure->tie("airport", SGStringValueMethods<FGRouteMgr>(*this,
&FGRouteMgr::getDepartureICAO, &FGRouteMgr::setDepartureICAO));
departure->tie("runway", SGRawValueMethods<FGRouteMgr, const char*>(*this,
departure->tie("runway", SGStringValueMethods<FGRouteMgr>(*this,
&FGRouteMgr::getDepartureRunway,
&FGRouteMgr::setDepartureRunway));
departure->tie("sid", SGRawValueMethods<FGRouteMgr, const char*>(*this,
departure->tie("sid", SGStringValueMethods<FGRouteMgr>(*this,
&FGRouteMgr::getSID,
&FGRouteMgr::setSID));
departure->tie("name", SGRawValueMethods<FGRouteMgr, const char*>(*this,
departure->tie("name", SGStringValueMethods<FGRouteMgr>(*this,
&FGRouteMgr::getDepartureName, NULL));
departure->tie("field-elevation-ft", SGRawValueMethods<FGRouteMgr, double>(*this,
&FGRouteMgr::getDepartureFieldElevation, NULL));
@ -278,19 +278,19 @@ void FGRouteMgr::init() {
destination = fgGetNode(RM "destination", true);
destination->getChild("airport", 0, true);
destination->tie("airport", SGRawValueMethods<FGRouteMgr, const char*>(*this,
destination->tie("airport", SGStringValueMethods<FGRouteMgr>(*this,
&FGRouteMgr::getDestinationICAO, &FGRouteMgr::setDestinationICAO));
destination->tie("runway", SGRawValueMethods<FGRouteMgr, const char*>(*this,
destination->tie("runway", SGStringValueMethods<FGRouteMgr>(*this,
&FGRouteMgr::getDestinationRunway,
&FGRouteMgr::setDestinationRunway));
destination->tie("star", SGRawValueMethods<FGRouteMgr, const char*>(*this,
destination->tie("star", SGStringValueMethods<FGRouteMgr>(*this,
&FGRouteMgr::getSTAR,
&FGRouteMgr::setSTAR));
destination->tie("approach", SGRawValueMethods<FGRouteMgr, const char*>(*this,
destination->tie("approach", SGStringValueMethods<FGRouteMgr>(*this,
&FGRouteMgr::getApproach,
&FGRouteMgr::setApproach));
destination->tie("name", SGRawValueMethods<FGRouteMgr, const char*>(*this,
destination->tie("name", SGStringValueMethods<FGRouteMgr>(*this,
&FGRouteMgr::getDestinationName, NULL));
destination->tie("field-elevation-ft", SGRawValueMethods<FGRouteMgr, double>(*this,
&FGRouteMgr::getDestinationFieldElevation, NULL));
@ -637,7 +637,7 @@ void FGRouteMgr::update_mirror()
SGPropertyNode *prop = mirror->getChild("wp", i, 1);
const SGGeod& pos(wp->position());
prop->setStringValue("id", wp->ident().c_str());
prop->setStringValue("id", wp->ident());
prop->setDoubleValue("longitude-deg", pos.getLongitudeDeg());
prop->setDoubleValue("latitude-deg",pos.getLatitudeDeg());
@ -797,64 +797,64 @@ void FGRouteMgr::currentWaypointChanged()
SG_LOG(SG_AUTOPILOT, SG_INFO, "route manager, current-wp is now " << currentIndex());
}
const char* FGRouteMgr::getDepartureICAO() const
std::string FGRouteMgr::getDepartureICAO() const
{
if (!_plan || !_plan->departureAirport()) {
return "";
}
return _plan->departureAirport()->ident().c_str();
return _plan->departureAirport()->ident();
}
const char* FGRouteMgr::getDepartureName() const
std::string FGRouteMgr::getDepartureName() const
{
if (!_plan || !_plan->departureAirport()) {
return "";
}
return _plan->departureAirport()->name().c_str();
return _plan->departureAirport()->name();
}
const char* FGRouteMgr::getDepartureRunway() const
std::string FGRouteMgr::getDepartureRunway() const
{
if (_plan && _plan->departureRunway()) {
return _plan->departureRunway()->ident().c_str();
return _plan->departureRunway()->ident();
}
return "";
}
void FGRouteMgr::setDepartureRunway(const char* aIdent)
void FGRouteMgr::setDepartureRunway(const std::string& aIdent)
{
if (!_plan) {
return;
}
FGAirport* apt = _plan->departureAirport();
if (!apt || (aIdent == NULL)) {
if (!apt || aIdent.empty()) {
_plan->setDeparture(apt);
} else if (apt->hasRunwayWithIdent(aIdent)) {
_plan->setDeparture(apt->getRunwayByIdent(aIdent));
}
}
void FGRouteMgr::setDepartureICAO(const char* aIdent)
void FGRouteMgr::setDepartureICAO(const std::string& aIdent)
{
if (!_plan) {
return;
}
if ((aIdent == NULL) || (strlen(aIdent) < 4)) {
if (aIdent.length() < 4) {
_plan->setDeparture((FGAirport*) NULL);
} else {
_plan->setDeparture(FGAirport::findByIdent(aIdent));
}
}
const char* FGRouteMgr::getSID() const
std::string FGRouteMgr::getSID() const
{
if (_plan && _plan->sid()) {
return _plan->sid()->ident().c_str();
return _plan->sid()->ident();
}
return "";
@ -923,19 +923,19 @@ flightgear::SID* createDefaultSID(FGRunway* aRunway, double enrouteCourse)
return flightgear::SID::createTempSID("DEFAULT", aRunway, wpts);
}
void FGRouteMgr::setSID(const char* aIdent)
void FGRouteMgr::setSID(const std::string& aIdent)
{
if (!_plan) {
return;
}
FGAirport* apt = _plan->departureAirport();
if (!apt || (aIdent == NULL)) {
if (!apt || aIdent.empty()) {
_plan->setSID((flightgear::SID*) NULL);
return;
}
if (!strcmp(aIdent, "DEFAULT")) {
if (aIdent == "DEFAULT") {
double enrouteCourse = -1.0;
if (_plan->destinationAirport()) {
enrouteCourse = SGGeodesy::courseDeg(apt->geod(), _plan->destinationAirport()->geod());
@ -945,11 +945,10 @@ void FGRouteMgr::setSID(const char* aIdent)
return;
}
string ident(aIdent);
size_t hyphenPos = ident.find('-');
size_t hyphenPos = aIdent.find('-');
if (hyphenPos != string::npos) {
string sidIdent = ident.substr(0, hyphenPos);
string transIdent = ident.substr(hyphenPos + 1);
string sidIdent = aIdent.substr(0, hyphenPos);
string transIdent = aIdent.substr(hyphenPos + 1);
flightgear::SID* sid = apt->findSIDWithIdent(sidIdent);
Transition* trans = sid ? sid->findTransitionByName(transIdent) : NULL;
@ -959,64 +958,64 @@ void FGRouteMgr::setSID(const char* aIdent)
}
}
const char* FGRouteMgr::getDestinationICAO() const
std::string FGRouteMgr::getDestinationICAO() const
{
if (!_plan || !_plan->destinationAirport()) {
return "";
}
return _plan->destinationAirport()->ident().c_str();
return _plan->destinationAirport()->ident();
}
const char* FGRouteMgr::getDestinationName() const
std::string FGRouteMgr::getDestinationName() const
{
if (!_plan || !_plan->destinationAirport()) {
return "";
}
return _plan->destinationAirport()->name().c_str();
return _plan->destinationAirport()->name();
}
void FGRouteMgr::setDestinationICAO(const char* aIdent)
void FGRouteMgr::setDestinationICAO(const std::string& aIdent)
{
if (!_plan) {
return;
}
if ((aIdent == NULL) || (strlen(aIdent) < 4)) {
if (aIdent.length() < 4) {
_plan->setDestination((FGAirport*) NULL);
} else {
_plan->setDestination(FGAirport::findByIdent(aIdent));
}
}
const char* FGRouteMgr::getDestinationRunway() const
std::string FGRouteMgr::getDestinationRunway() const
{
if (_plan && _plan->destinationRunway()) {
return _plan->destinationRunway()->ident().c_str();
return _plan->destinationRunway()->ident();
}
return "";
}
void FGRouteMgr::setDestinationRunway(const char* aIdent)
void FGRouteMgr::setDestinationRunway(const std::string& aIdent)
{
if (!_plan) {
return;
}
FGAirport* apt = _plan->destinationAirport();
if (!apt || (aIdent == NULL)) {
if (!apt || aIdent.empty()) {
_plan->setDestination(apt);
} else if (apt->hasRunwayWithIdent(aIdent)) {
_plan->setDestination(apt->getRunwayByIdent(aIdent));
}
}
const char* FGRouteMgr::getApproach() const
std::string FGRouteMgr::getApproach() const
{
if (_plan && _plan->approach()) {
return _plan->approach()->ident().c_str();
return _plan->approach()->ident();
}
return "";
@ -1082,14 +1081,14 @@ flightgear::Approach* createDefaultApproach(FGRunway* aRunway, double aEnrouteCo
return Approach::createTempApproach("DEFAULT", aRunway, wpts);
}
void FGRouteMgr::setApproach(const char* aIdent)
void FGRouteMgr::setApproach(const std::string& aIdent)
{
if (!_plan) {
return;
}
FGAirport* apt = _plan->destinationAirport();
if (!strcmp(aIdent, "DEFAULT")) {
if (aIdent == "DEFAULT") {
double enrouteCourse = -1.0;
if (_plan->departureAirport()) {
enrouteCourse = SGGeodesy::courseDeg(_plan->departureAirport()->geod(), apt->geod());
@ -1099,30 +1098,30 @@ void FGRouteMgr::setApproach(const char* aIdent)
return;
}
if (!apt || (aIdent == NULL)) {
if (!apt || aIdent.empty()) {
_plan->setApproach(NULL);
} else {
_plan->setApproach(apt->findApproachWithIdent(aIdent));
}
}
const char* FGRouteMgr::getSTAR() const
std::string FGRouteMgr::getSTAR() const
{
if (_plan && _plan->star()) {
return _plan->star()->ident().c_str();
return _plan->star()->ident();
}
return "";
}
void FGRouteMgr::setSTAR(const char* aIdent)
void FGRouteMgr::setSTAR(const std::string& aIdent)
{
if (!_plan) {
return;
}
FGAirport* apt = _plan->destinationAirport();
if (!apt || (aIdent == NULL)) {
if (!apt || aIdent.empty()) {
_plan->setSTAR((STAR*) NULL);
return;
}

View file

@ -183,28 +183,28 @@ private:
virtual void currentWaypointChanged();
// tied getters and setters
const char* getDepartureICAO() const;
const char* getDepartureName() const;
void setDepartureICAO(const char* aIdent);
std::string getDepartureICAO() const;
std::string getDepartureName() const;
void setDepartureICAO(const std::string& aIdent);
const char* getDepartureRunway() const;
void setDepartureRunway(const char* aIdent);
std::string getDepartureRunway() const;
void setDepartureRunway(const std::string& aIdent);
const char* getSID() const;
void setSID(const char* aIdent);
std::string getSID() const;
void setSID(const std::string& aIdent);
const char* getDestinationICAO() const;
const char* getDestinationName() const;
void setDestinationICAO(const char* aIdent);
std::string getDestinationICAO() const;
std::string getDestinationName() const;
void setDestinationICAO(const std::string& aIdent);
const char* getDestinationRunway() const;
void setDestinationRunway(const char* aIdent);
std::string getDestinationRunway() const;
void setDestinationRunway(const std::string& aIdent);
const char* getApproach() const;
void setApproach(const char* aIdent);
std::string getApproach() const;
void setApproach(const std::string& aIdent);
const char* getSTAR() const;
void setSTAR(const char* aIdent);
std::string getSTAR() const;
void setSTAR(const std::string& aIdent);
double getDepartureFieldElevation() const;
double getDestinationFieldElevation() const;

View file

@ -183,7 +183,7 @@ private:
class SymbolRule
{
public:
SymbolRule()
SymbolRule() : enabled(false)
{
}

View file

@ -26,8 +26,13 @@
#include <simgear/constants.h>
#include <simgear/debug/logstream.hxx>
#ifdef FG_TESTLIB
#include <tests/fake_sgSky.hxx>
#else
#include <simgear/scene/sky/sky.hxx>
#include <simgear/scene/model/particles.hxx>
#endif
#include <simgear/structure/event_mgr.hxx>
#include <Main/main.hxx>
@ -47,6 +52,7 @@
#include "gravity.hxx"
#include "magvarmanager.hxx"
#ifndef FG_TESTLIB
class FG3DCloudsListener : public SGPropertyChangeListener {
public:
FG3DCloudsListener( FGClouds * fgClouds );
@ -77,19 +83,26 @@ void FG3DCloudsListener::valueChanged( SGPropertyNode * node )
{
_fgClouds->set_3dClouds( _enableNode->getBoolValue() );
}
#endif
FGEnvironmentMgr::FGEnvironmentMgr () :
_environment(new FGEnvironment()),
fgClouds(new FGClouds()),
fgClouds(nullptr),
_cloudLayersDirty(true),
_3dCloudsEnableListener(new FG3DCloudsListener(fgClouds) ),
_3dCloudsEnableListener(nullptr),
_sky(globals->get_renderer()->getSky())
{
#ifndef FG_TESTLIB
fgClouds = new FGClouds;
_3dCloudsEnableListener = new FG3DCloudsListener(fgClouds);
#endif
set_subsystem("controller", Environment::LayerInterpolateController::createInstance( fgGetNode("/environment/config", true ) ));
set_subsystem("realwx", Environment::RealWxController::createInstance( fgGetNode("/environment/realwx", true ) ), 1.0 );
set_subsystem("precipitation", new FGPrecipitationMgr);
#ifndef FG_TESTLIB
set_subsystem("realwx", Environment::RealWxController::createInstance( fgGetNode("/environment/realwx", true ) ), 1.0 );
set_subsystem("terrainsampler", Environment::TerrainSampler::createInstance( fgGetNode("/environment/terrain", true ) ));
#endif
set_subsystem("ridgelift", new FGRidgeLift);
set_subsystem("magvar", new FGMagVarManager);
@ -104,10 +117,11 @@ FGEnvironmentMgr::~FGEnvironmentMgr ()
remove_subsystem("controller");
remove_subsystem("magvar");
#ifndef FG_TESTLIB
delete fgClouds;
delete _environment;
delete _3dCloudsEnableListener;
#endif
delete _environment;
}
SGSubsystem::InitStatus FGEnvironmentMgr::incrementalInit()
@ -115,7 +129,9 @@ SGSubsystem::InitStatus FGEnvironmentMgr::incrementalInit()
InitStatus r = SGSubsystemGroup::incrementalInit();
if (r == INIT_DONE) {
#ifndef FG_TESTLIB
fgClouds->Init();
#endif
globals->get_event_mgr()->addTask("updateClosestAirport", this,
&FGEnvironmentMgr::updateClosestAirport, 30 );
}
@ -148,10 +164,11 @@ FGEnvironmentMgr::bind ()
_tiedProperties.Tie( "effective-visibility-m", _sky,
&SGSky::get_visibility );
#ifndef FG_TESTLIB
_tiedProperties.Tie("rebuild-layers", fgClouds,
&FGClouds::get_update_event,
&FGClouds::set_update_event);
#endif
// _tiedProperties.Tie("turbulence/use-cloud-turbulence", &sgEnviro,
// &SGEnviro::get_turbulence_enable_state,
// &SGEnviro::set_turbulence_enable_state);
@ -221,7 +238,6 @@ FGEnvironmentMgr::bind ()
_tiedProperties.Tie("clouds3d-use-impostors", _sky,
&SGSky::get_3dCloudUseImpostors,
&SGSky::set_3dCloudUseImpostors);
}
void
@ -240,13 +256,14 @@ FGEnvironmentMgr::update (double dt)
SGGeod aircraftPos(globals->get_aircraft_position());
_environment->set_elevation_ft( aircraftPos.getElevationFt() );
#ifndef FG_TESTLIB
simgear::Particles::setWindFrom( _environment->get_wind_from_heading_deg(),
_environment->get_wind_speed_kt() );
if( _cloudLayersDirty ) {
_cloudLayersDirty = false;
fgClouds->set_update_event( fgClouds->get_update_event()+1 );
}
#endif
fgSetDouble( "/environment/gravitational-acceleration-mps2",
Environment::Gravity::instance()->getGravity(aircraftPos));

View file

@ -160,7 +160,7 @@ FGMetar::FGMetar(const string& icao) :
long FGMetar::getAge_min() const
{
time_t now = _x_proxy ? _rq_time : sgGMTime();
time_t now = _x_proxy ? _rq_time : time(nullptr);
return (now - _time) / 60;
}

View file

@ -36,8 +36,10 @@
class FGPrecipitationMgr : public SGSubsystem
{
private:
#ifndef FG_TESTLIB
osg::ref_ptr<osg::MatrixTransform> transform;
osg::ref_ptr<SGPrecipitation> precipitation;
#endif
float getPrecipitationAtAltitudeMax(void);
simgear::TiedPropertyList _tiedProperties;
@ -56,4 +58,3 @@ public:
};
#endif

View file

@ -72,7 +72,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGFDMExec.cpp,v 1.191 2016/05/16 18:19:57 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGFDMExec.cpp,v 1.194 2017/03/03 23:00:39 bcoconni Exp $");
IDENT(IdHdr,ID_FDMEXEC);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -428,7 +428,7 @@ void FGFDMExec::LoadInputs(unsigned int idx)
Propulsion->in.PropAdvance = FCS->GetPropAdvance();
Propulsion->in.PropFeather = FCS->GetPropFeather();
Propulsion->in.H_agl = Propagate->GetDistanceAGL();
Propulsion->in.PQR = Propagate->GetPQR();
Propulsion->in.PQRi = Propagate->GetPQRi();
break;
case eAerodynamics:
@ -650,24 +650,26 @@ vector <string> FGFDMExec::EnumerateFDMs(void)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGFDMExec::LoadScript(const string& script, double deltaT, const string& initfile)
bool FGFDMExec::LoadScript(const SGPath& script, double deltaT,
const SGPath& initfile)
{
bool result;
Script = new FGScript(this);
result = Script->LoadScript(RootDir + script, deltaT, initfile);
result = Script->LoadScript(GetFullPath(script), deltaT, initfile);
return result;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGFDMExec::LoadModel(const string& AircraftPath, const string& EnginePath, const string& SystemsPath,
const string& model, bool addModelToPath)
bool FGFDMExec::LoadModel(const SGPath& AircraftPath, const SGPath& EnginePath,
const SGPath& SystemsPath, const string& model,
bool addModelToPath)
{
FGFDMExec::AircraftPath = RootDir + AircraftPath;
FGFDMExec::EnginePath = RootDir + EnginePath;
FGFDMExec::SystemsPath = RootDir + SystemsPath;
FGFDMExec::AircraftPath = GetFullPath(AircraftPath);
FGFDMExec::EnginePath = GetFullPath(EnginePath);
FGFDMExec::SystemsPath = GetFullPath(SystemsPath);
return LoadModel(model, addModelToPath);
}
@ -676,20 +678,20 @@ bool FGFDMExec::LoadModel(const string& AircraftPath, const string& EnginePath,
bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
{
string aircraftCfgFileName;
SGPath aircraftCfgFileName;
bool result = false; // initialize result to false, indicating input file not yet read
modelName = model; // Set the class modelName attribute
if( AircraftPath.empty() || EnginePath.empty() || SystemsPath.empty()) {
if( AircraftPath.isNull() || EnginePath.isNull() || SystemsPath.isNull()) {
cerr << "Error: attempted to load aircraft with undefined ";
cerr << "aircraft, engine, and system paths" << endl;
return false;
}
FullAircraftPath = AircraftPath;
if (addModelToPath) FullAircraftPath += "/" + model;
aircraftCfgFileName = FullAircraftPath + "/" + model + ".xml";
if (addModelToPath) FullAircraftPath.append(model);
aircraftCfgFileName = FullAircraftPath/(model + ".xml");
if (modelLoaded) {
DeAllocate();

View file

@ -49,12 +49,13 @@ INCLUDES
#include "models/FGPropagate.h"
#include "math/FGColumnVector3.h"
#include "models/FGOutput.h"
#include "simgear/misc/sg_path.hxx"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_FDMEXEC "$Id: FGFDMExec.h,v 1.105 2016/04/16 12:24:39 bcoconni Exp $"
#define ID_FDMEXEC "$Id: FGFDMExec.h,v 1.106 2017/02/25 14:23:18 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -178,7 +179,7 @@ CLASS DOCUMENTATION
property actually maps toa function call of DoTrim().
@author Jon S. Berndt
@version $Revision: 1.105 $
@version $Revision: 1.106 $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -284,8 +285,8 @@ public:
@param addModelToPath set to true to add the model name to the
AircraftPath, defaults to true
@return true if successful */
bool LoadModel(const std::string& AircraftPath, const std::string& EnginePath,
const std::string& SystemsPath, const std::string& model,
bool LoadModel(const SGPath& AircraftPath, const SGPath& EnginePath,
const SGPath& SystemsPath, const std::string& model,
bool addModelToPath = true);
/** Loads an aircraft model. The paths to the aircraft and engine
@ -310,24 +311,33 @@ public:
the file specified in the script will be used. If an initialization file
is not given in either place, an error will result.
@return true if successfully loads; false otherwise. */
bool LoadScript(const std::string& Script, double deltaT=0.0,
const std::string& initfile="");
bool LoadScript(const SGPath& Script, double deltaT=0.0,
const SGPath& initfile=SGPath());
/** Sets the path to the engine config file directories.
@param path path to the directory under which engine config
files are kept, for instance "engine" */
bool SetEnginePath(const std::string& path) { EnginePath = RootDir + path; return true; }
bool SetEnginePath(const SGPath& path) {
EnginePath = GetFullPath(path);
return true;
}
/** Sets the path to the aircraft config file directories.
@param path path to the aircraft directory. For instance:
"aircraft". Under aircraft, then, would be directories for various
modeled aircraft such as C172/, x15/, etc. */
bool SetAircraftPath(const std::string& path) { AircraftPath = RootDir + path; return true; }
bool SetAircraftPath(const SGPath& path) {
AircraftPath = GetFullPath(path);
return true;
}
/** Sets the path to the systems config file directories.
@param path path to the directory under which systems config
files are kept, for instance "systems" */
bool SetSystemsPath(const std::string& path) { SystemsPath = RootDir + path; return true; }
bool SetSystemsPath(const SGPath& path) {
SystemsPath = GetFullPath(path);
return true;
}
/// @name Top-level executive State and Model retrieval mechanism
///@{
@ -378,13 +388,13 @@ public:
///@}
/// Retrieves the engine path.
const std::string& GetEnginePath(void) {return EnginePath;}
const SGPath& GetEnginePath(void) {return EnginePath;}
/// Retrieves the aircraft path.
const std::string& GetAircraftPath(void) {return AircraftPath;}
const SGPath& GetAircraftPath(void) {return AircraftPath;}
/// Retrieves the systems path.
const std::string& GetSystemsPath(void) {return SystemsPath;}
const SGPath& GetSystemsPath(void) {return SystemsPath;}
/// Retrieves the full aircraft path name.
const std::string& GetFullAircraftPath(void) {return FullAircraftPath;}
const SGPath& GetFullAircraftPath(void) {return FullAircraftPath;}
/** Retrieves the value of a property.
@param property the name of the property
@ -428,8 +438,8 @@ public:
be logged.
@param fname the filename of an output directives file.
*/
bool SetOutputDirectives(const std::string& fname)
{return Output->SetDirectivesFile(RootDir + fname);}
bool SetOutputDirectives(const SGPath& fname)
{ return Output->SetDirectivesFile(GetFullPath(fname)); }
/** Forces the specified output object to print its items once */
void ForceOutput(int idx=0) { Output->ForceOutput(idx); }
@ -550,11 +560,11 @@ public:
/** Sets the root directory where JSBSim starts looking for its system directories.
@param rootDir the string containing the root directory. */
void SetRootDir(const std::string& rootDir) {RootDir = rootDir;}
void SetRootDir(const SGPath& rootDir) {RootDir = rootDir;}
/** Retrieves the Root Directory.
@return the string representing the root (base) JSBSim directory. */
const std::string& GetRootDir(void) const {return RootDir;}
const SGPath& GetRootDir(void) const {return RootDir;}
/** Increments the simulation time if not in Holding mode. The Frame counter
is also incremented.
@ -606,13 +616,13 @@ private:
bool modelLoaded;
bool IsChild;
std::string modelName;
std::string AircraftPath;
std::string FullAircraftPath;
std::string EnginePath;
std::string SystemsPath;
SGPath AircraftPath;
SGPath FullAircraftPath;
SGPath EnginePath;
SGPath SystemsPath;
std::string CFGVersion;
std::string Release;
std::string RootDir;
SGPath RootDir;
// Standard Model pointers - shortcuts for internal executive use only.
FGPropagate* Propagate;
@ -664,6 +674,12 @@ private:
bool Allocate(void);
bool DeAllocate(void);
int GetDisperse(void) const {return disperse;}
SGPath GetFullPath(const SGPath& name) {
if (name.isRelative())
return RootDir/name.utf8Str();
else
return name;
}
void Debug(int from);
};

View file

@ -77,18 +77,18 @@ using JSBSim::Element;
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
IDENT(IdSrc,"$Id: JSBSim.cpp,v 1.89 2016/05/20 14:14:05 ehofman Exp $");
IDENT(IdSrc,"$Id: JSBSim.cpp,v 1.90 2017/02/25 14:23:18 bcoconni Exp $");
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
GLOBAL DATA
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
string RootDir = "";
string ScriptName;
SGPath RootDir;
SGPath ScriptName;
string AircraftName;
string ResetName;
SGPath ResetName;
vector <string> LogOutputName;
vector <string> LogDirectiveName;
vector <SGPath> LogDirectiveName;
vector <string> CommandLineProperties;
vector <double> CommandLinePropertyValues;
JSBSim::FGFDMExec* FDMExec;
@ -151,28 +151,28 @@ void PrintHelp(void);
of file is given on the command line */
class XMLFile : public FGXMLFileRead {
public:
bool IsScriptFile(std::string filename) {
bool IsScriptFile(const SGPath& filename) {
bool result=false;
Element *document = LoadXMLDocument(filename, false);
if (document && document->GetName() == "runscript") result = true;
ResetParser();
return result;
}
bool IsLogDirectiveFile(std::string filename) {
bool IsLogDirectiveFile(const SGPath& filename) {
bool result=false;
Element *document = LoadXMLDocument(filename, false);
if (document && document->GetName() == "output") result = true;
ResetParser();
return result;
}
bool IsAircraftFile(std::string filename) {
bool IsAircraftFile(const SGPath& filename) {
bool result=false;
Element* document = LoadXMLDocument(filename, false);
if (document && document->GetName() == "fdm_config") result = true;
ResetParser();
return result;
}
bool IsInitFile(std::string filename) {
bool IsInitFile(const SGPath& filename) {
bool result=false;
Element *document = LoadXMLDocument(filename, false);
if (document && document->GetName() == "initialize") result = true;
@ -345,9 +345,9 @@ int real_main(int argc, char* argv[])
// *** SET UP JSBSIM *** //
FDMExec = new JSBSim::FGFDMExec();
FDMExec->SetRootDir(RootDir);
FDMExec->SetAircraftPath("aircraft");
FDMExec->SetEnginePath("engine");
FDMExec->SetSystemsPath("systems");
FDMExec->SetAircraftPath(SGPath("aircraft"));
FDMExec->SetEnginePath(SGPath("engine"));
FDMExec->SetSystemsPath(SGPath("systems"));
FDMExec->GetPropertyManager()->Tie("simulation/frame_start_time", &actual_elapsed_time);
FDMExec->GetPropertyManager()->Tie("simulation/cycle_duration", &cycle_duration);
@ -372,7 +372,7 @@ int real_main(int argc, char* argv[])
}
// *** OPTION A: LOAD A SCRIPT, WHICH LOADS EVERYTHING ELSE *** //
if (!ScriptName.empty()) {
if (!ScriptName.isNull()) {
result = FDMExec->LoadScript(ScriptName, override_sim_rate_value, ResetName);
@ -383,13 +383,13 @@ int real_main(int argc, char* argv[])
}
// *** OPTION B: LOAD AN AIRCRAFT AND A SET OF INITIAL CONDITIONS *** //
} else if (!AircraftName.empty() || !ResetName.empty()) {
} else if (!AircraftName.empty() || !ResetName.isNull()) {
if (catalog) FDMExec->SetDebugLevel(0);
if ( ! FDMExec->LoadModel( "aircraft",
"engine",
"systems",
if ( ! FDMExec->LoadModel(SGPath("aircraft"),
SGPath("engine"),
SGPath("systems"),
AircraftName)) {
cerr << " JSBSim could not be started" << endl << endl;
delete FDMExec;
@ -417,7 +417,7 @@ int real_main(int argc, char* argv[])
// Load output directives file[s], if given
for (unsigned int i=0; i<LogDirectiveName.size(); i++) {
if (!LogDirectiveName[i].empty()) {
if (!LogDirectiveName[i].isNull()) {
if (!FDMExec->SetOutputDirectives(LogDirectiveName[i])) {
cout << "Output directives not properly set in file " << LogDirectiveName[i] << endl;
delete FDMExec;
@ -621,17 +621,14 @@ bool options(int count, char **arg)
}
} else if (keyword == "--logdirectivefile") {
if (n != string::npos) {
LogDirectiveName.push_back(value);
LogDirectiveName.push_back(SGPath::fromLocal8Bit(value.c_str()));
} else {
gripe;
exit(1);
}
} else if (keyword == "--root") {
if (n != string::npos) {
RootDir = value;
if (RootDir[RootDir.length()-1] != '/') {
RootDir += '/';
}
RootDir = SGPath::fromLocal8Bit(value.c_str());
} else {
gripe;
exit(1);
@ -645,14 +642,14 @@ bool options(int count, char **arg)
}
} else if (keyword == "--script") {
if (n != string::npos) {
ScriptName = value;
ScriptName = SGPath::fromLocal8Bit(value.c_str());
} else {
gripe;
exit(1);
}
} else if (keyword == "--initfile") {
if (n != string::npos) {
ResetName = value;
ResetName = SGPath::fromLocal8Bit(value.c_str());
} else {
gripe;
exit(1);
@ -704,12 +701,13 @@ bool options(int count, char **arg)
// See what kind of files we are specifying on the command line
XMLFile xmlFile;
SGPath path = SGPath::fromLocal8Bit(keyword.c_str());
if (xmlFile.IsScriptFile(keyword)) ScriptName = keyword;
else if (xmlFile.IsLogDirectiveFile(keyword)) LogDirectiveName.push_back(keyword);
else if (xmlFile.IsAircraftFile("aircraft/" + keyword + "/" + keyword)) AircraftName = keyword;
else if (xmlFile.IsInitFile(keyword)) ResetName = keyword;
else if (xmlFile.IsInitFile("aircraft/" + AircraftName + "/" + keyword)) ResetName = keyword;
if (xmlFile.IsScriptFile(path)) ScriptName = path;
else if (xmlFile.IsLogDirectiveFile(path)) LogDirectiveName.push_back(path);
else if (xmlFile.IsAircraftFile(SGPath("aircraft")/keyword/keyword)) AircraftName = keyword;
else if (xmlFile.IsInitFile(path)) ResetName = path;
else if (xmlFile.IsInitFile(SGPath("aircraft")/AircraftName/keyword)) ResetName = SGPath("aircraft")/AircraftName/keyword;
else {
cerr << "The argument \"" << keyword << "\" cannot be interpreted as a file name or option." << endl;
exit(1);
@ -727,15 +725,15 @@ bool options(int count, char **arg)
// Post-processing for script options. check for incompatible options.
if (catalog && !ScriptName.empty()) {
if (catalog && !ScriptName.isNull()) {
cerr << "Cannot specify catalog with script option" << endl << endl;
result = false;
}
if (AircraftName.size() > 0 && ResetName.size() == 0 && !catalog) {
if (!AircraftName.empty() && ResetName.isNull() && !catalog) {
cerr << "You must specify an initialization file with the aircraft name." << endl << endl;
result = false;
}
if (ScriptName.size() > 0 && AircraftName.size() > 0) {
if (!ScriptName.isNull() && !AircraftName.empty()) {
cerr << "You cannot specify an aircraft file with a script." << endl;
result = false;
}

View file

@ -188,6 +188,11 @@ FGJSBsim::FGJSBsim( double dt )
case SG_POPUP:
FGJSBBase::debug_lvl = 0x00;
break;
default:
// silence warning about unhandled cases
FGJSBBase::debug_lvl = 0x00;
break;
}
} else {
// if flight is excluded, don't bother
@ -234,9 +239,7 @@ FGJSBsim::FGJSBsim( double dt )
fdmex->Setdt( dt );
result = fdmex->LoadModel( aircraft_path.local8BitStr(),
engine_path.local8BitStr(),
systems_path.local8BitStr(),
result = fdmex->LoadModel( aircraft_path, engine_path, systems_path,
fgGetString("/sim/aero"), false );
if (result) {

View file

@ -58,7 +58,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGInitialCondition.cpp,v 1.111 2016/07/03 17:20:55 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGInitialCondition.cpp,v 1.114 2017/02/25 14:23:18 bcoconni Exp $");
IDENT(IdHdr,ID_INITIALCONDITION);
//******************************************************************************
@ -709,10 +709,10 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt)
altitudeASL=alt;
position.SetAltitudeASL(alt);
if (lastLatitudeSet == setgeod) {
double h = ComputeGeodAltitude(geodLatitude);
position.SetPositionGeodetic(position.GetLongitude(), geodLatitude, h);
}
// The call to SetAltitudeASL has most likely modified the geodetic latitude
// so we need to restore it to its initial value.
if (lastLatitudeSet == setgeod)
SetGeodLatitudeRadIC(geodLatitude);
soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
rho = Atmosphere->GetDensity(altitudeASL);
@ -880,11 +880,11 @@ double FGInitialCondition::GetBodyVelFpsIC(int idx) const
//******************************************************************************
bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
bool FGInitialCondition::Load(const SGPath& rstfile, bool useStoredPath)
{
string init_file_name;
if( useStoredPath ) {
init_file_name = fdmex->GetFullAircraftPath() + "/" + rstfile + ".xml";
SGPath init_file_name;
if(useStoredPath && rstfile.isRelative()) {
init_file_name = fdmex->GetFullAircraftPath()/rstfile.utf8Str();
} else {
init_file_name = rstfile;
}
@ -931,16 +931,11 @@ bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
}
//******************************************************************************
// Given an altitude above the sea level (or a position radius which is the
// same) and a geodetic latitude, compute the geodetic altitude. It is assumed
// that the terrain is a sphere and that the elevation is uniform all over the
// Earth. Would that assumption fail, the computation below would need to be
// adapted since the position radius would depend on the terrain elevation which
// depends itself on the latitude.
// Given an altitude above the mean sea level (or a position radius which is the
// same) and a geodetic latitude, compute the geodetic altitude.
//
// This is an acceptable trade off because this routine is only used by
// standalone JSBSim which uses FGDefaultGroundCallback which assumes that the
// Earth is a sphere.
// TODO: extend the routine to the case where lastAltitudeSet is equal to
// setagl.
double FGInitialCondition::ComputeGeodAltitude(double geodLatitude)
{
@ -978,11 +973,8 @@ bool FGInitialCondition::LoadLatitude(Element* position_el)
string lat_type = latitude_el->GetAttributeValue("type");
if (lat_type == "geod" || lat_type == "geodetic") {
double h = ComputeGeodAltitude(latitude);
position.SetPositionGeodetic(position.GetLongitude(), latitude, h);
lastLatitudeSet = setgeod;
}
if (lat_type == "geod" || lat_type == "geodetic")
SetGeodLatitudeRadIC(latitude);
else {
position.SetLatitude(latitude);
lastLatitudeSet = setgeoc;
@ -1491,10 +1483,14 @@ void FGInitialCondition::bind(FGPropertyManager* PropertyManager)
&FGInitialCondition::GetRRadpsIC,
&FGInitialCondition::SetRRadpsIC,
true);
PropertyManager->Tie("ic/lat-geod-rad", &position,
&FGLocation::GetGeodLatitudeRad);
PropertyManager->Tie("ic/lat-geod-deg", &position,
&FGLocation::GetGeodLatitudeDeg);
PropertyManager->Tie("ic/lat-geod-rad", this,
&FGInitialCondition::GetGeodLatitudeRadIC,
&FGInitialCondition::SetGeodLatitudeRadIC,
true);
PropertyManager->Tie("ic/lat-geod-deg", this,
&FGInitialCondition::GetGeodLatitudeDegIC,
&FGInitialCondition::SetGeodLatitudeDegIC,
true);
PropertyManager->Tie("ic/geod-alt-ft", &position,
&FGLocation::GetGeodAltitude);
}

View file

@ -49,12 +49,13 @@ INCLUDES
#include "math/FGLocation.h"
#include "math/FGQuaternion.h"
#include "simgear/misc/sg_path.hxx"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.46 2016/07/03 17:20:55 bcoconni Exp $"
#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.48 2017/02/25 14:23:18 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -220,7 +221,7 @@ CLASS DOCUMENTATION
@property ic/r-rad_sec (read/write) Yaw rate initial condition in radians/second
@author Tony Peden
@version "$Id: FGInitialCondition.h,v 1.46 2016/07/03 17:20:55 bcoconni Exp $"
@version "$Id: FGInitialCondition.h,v 1.48 2017/02/25 14:23:18 bcoconni Exp $"
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -311,6 +312,13 @@ public:
@param lat Initial latitude in degrees */
void SetLatitudeDegIC(double lat) { SetLatitudeRadIC(lat*degtorad); }
/** Sets the initial geodetic latitude.
This method modifies the geodetic altitude in order to keep the altitude
above sea level unchanged.
@param glat Initial geodetic latitude in degrees */
void SetGeodLatitudeDegIC(double glat)
{ SetGeodLatitudeRadIC(glat*degtorad); }
/** Sets the initial longitude.
@param lon Initial longitude in degrees */
void SetLongitudeDegIC(double lon) { SetLongitudeRadIC(lon*degtorad); }
@ -369,6 +377,11 @@ public:
@return Initial geocentric latitude in degrees */
double GetLatitudeDegIC(void) const { return position.GetLatitudeDeg(); }
/** Gets the initial geodetic latitude.
@return Initial geodetic latitude in degrees */
double GetGeodLatitudeDegIC(void) const
{ return position.GetGeodLatitudeDeg(); }
/** Gets the initial longitude.
@return Initial longitude in degrees */
double GetLongitudeDegIC(void) const { return position.GetLongitudeDeg(); }
@ -628,6 +641,11 @@ public:
@return Initial latitude in radians */
double GetLatitudeRadIC(void) const { return position.GetLatitude(); }
/** Gets the initial geodetic latitude.
@return Initial geodetic latitude in radians */
double GetGeodLatitudeRadIC(void) const
{ return position.GetGeodLatitudeRad(); }
/** Gets the initial longitude.
@return Initial longitude in radians */
double GetLongitudeRadIC(void) const { return position.GetLongitude(); }
@ -660,7 +678,7 @@ public:
@param rstname The name of an initial conditions file
@param useStoredPath true if the stored path to the IC file should be used
@return true if successful */
bool Load(std::string rstname, bool useStoredPath = true );
bool Load(const SGPath& rstname, bool useStoredPath = true );
/** Is an engine running ?
@param index of the engine to be checked

View file

@ -46,7 +46,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc, "$Id: FGModelLoader.cpp,v 1.3 2015/07/12 12:41:55 bcoconni Exp $");
IDENT(IdSrc, "$Id: FGModelLoader.cpp,v 1.4 2017/02/25 14:23:18 bcoconni Exp $");
IDENT(IdHdr, ID_MODELLOADER);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -60,28 +60,21 @@ Element_ptr FGModelLoader::Open(Element *el)
if (!fname.empty()) {
FGXMLFileRead XMLFileRead;
string file;
SGPath path(SGPath::fromLocal8Bit(fname.c_str()));
try {
file = model->FindFullPathName(fname);
if (file.empty()) throw string("File does not exist.");
}
catch(string& e) {
cerr << endl << el->ReadFrom()
<< "Could not open file: " << fname << endl << e << endl;
return NULL;
}
if (path.isRelative())
path = model->FindFullPathName(path);
if (CachedFiles.find(file) != CachedFiles.end())
document = CachedFiles[file];
if (CachedFiles.find(path.utf8Str()) != CachedFiles.end())
document = CachedFiles[path.utf8Str()];
else {
document = XMLFileRead.LoadXMLDocument(file);
document = XMLFileRead.LoadXMLDocument(path);
if (document == 0L) {
cerr << endl << el->ReadFrom()
<< "Could not open file: " << file << endl;
<< "Could not open file: " << path << endl;
return NULL;
}
CachedFiles[file] = document;
CachedFiles[path.utf8Str()] = document;
}
if (document->GetName() != el->GetName()) {
@ -93,19 +86,12 @@ Element_ptr FGModelLoader::Open(Element *el)
return document;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SGPath CheckPathName(const SGPath& path, const SGPath& filename) {
SGPath fullName = path/filename.utf8Str();
string CheckFullPathName(const string& path, const string& fname)
{
string name = path + "/" + fname;
if (fullName.extension() != "xml")
fullName.concat(".xml");
if (name.length() <=4 || name.substr(name.length()-4, 4) != ".xml")
name.append(".xml");
ifstream file(name.c_str());
if (!file.is_open())
return string();
return name;
return fullName.exists() ? fullName : SGPath();
}
}

View file

@ -41,12 +41,13 @@ INCLUDES
#include <string>
#include "FGXMLElement.h"
#include "simgear/misc/sg_path.hxx"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_MODELLOADER "$Id: FGModelLoader.h,v 1.1 2014/06/09 11:52:06 bcoconni Exp $"
#define ID_MODELLOADER "$Id: FGModelLoader.h,v 1.2 2017/02/25 14:23:18 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -75,7 +76,7 @@ private:
std::map<std::string, Element_ptr> CachedFiles;
};
std::string CheckFullPathName(const std::string& path, const std::string& fname);
SGPath CheckPathName(const SGPath& path, const SGPath& filename);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif

View file

@ -47,7 +47,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGOutputFile.cpp,v 1.9 2014/05/04 17:00:27 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGOutputFile.cpp,v 1.10 2017/02/25 14:23:18 bcoconni Exp $");
IDENT(IdHdr,ID_OUTPUTFILE);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -65,8 +65,8 @@ FGOutputFile::FGOutputFile(FGFDMExec* fdmex) :
bool FGOutputFile::InitModel(void)
{
if (FGOutputType::InitModel()) {
if (Filename.empty()) {
Filename = Name;
if (Filename.isNull()) {
Filename = SGPath(Name);
runID_postfix = 0;
}
return OpenFile();
@ -87,7 +87,7 @@ void FGOutputFile::SetStartNewOutput(void)
} else {
buf << Name << '_' << runID_postfix++;
}
Filename = buf.str();
Filename = SGPath(buf.str());
}
CloseFile();

View file

@ -45,7 +45,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_OUTPUTFILE "$Id: FGOutputFile.h,v 1.6 2014/05/04 17:00:27 bcoconni Exp $"
#define ID_OUTPUTFILE "$Id: FGOutputFile.h,v 1.8 2017/02/25 14:23:18 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -106,9 +106,9 @@ public:
the next call to SetStartNewOutput().
@param name new name */
void SetOutputName(const std::string& fname) {
Name = FDMExec->GetRootDir() + fname;
Name = (FDMExec->GetRootDir()/fname).utf8Str();
runID_postfix = -1;
Filename = std::string();
Filename = SGPath();
}
/** Generate the output. This is a pure method so it must be implemented by
the classes that inherits from FGOutputFile.
@ -116,7 +116,7 @@ public:
void Print(void) = 0;
protected:
std::string Filename;
SGPath Filename;
/// Opens the file
virtual bool OpenFile(void) = 0;

View file

@ -64,7 +64,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGOutputTextFile.cpp,v 1.12 2016/05/22 10:28:23 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGOutputTextFile.cpp,v 1.13 2017/02/25 14:23:18 bcoconni Exp $");
IDENT(IdHdr,ID_OUTPUTTEXTFILE);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -96,7 +96,7 @@ bool FGOutputTextFile::Load(Element* el)
bool FGOutputTextFile::OpenFile(void)
{
datafile.clear();
datafile.open(Filename.c_str());
datafile.open(Filename);
if (!datafile) {
cerr << endl << fgred << highint << "ERROR: unable to open the file "
<< reset << Filename.c_str() << endl
@ -261,9 +261,9 @@ bool FGOutputTextFile::OpenFile(void)
void FGOutputTextFile::Print(void)
{
streambuf* buffer;
string scratch = "";
string scratch = Filename.utf8Str();
if (Filename == "COUT" || Filename == "cout") {
if (to_upper(scratch) == "COUT") {
buffer = cout.rdbuf();
} else {
buffer = datafile.rdbuf();

View file

@ -41,12 +41,13 @@ INCLUDES
#include <fstream>
#include "FGOutputFile.h"
#include "simgear/io/iostreams/sgstream.hxx"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_OUTPUTTEXTFILE "$Id: FGOutputTextFile.h,v 1.4 2012/12/15 16:13:58 bcoconni Exp $"
#define ID_OUTPUTTEXTFILE "$Id: FGOutputTextFile.h,v 1.5 2017/02/25 14:23:18 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -89,7 +90,7 @@ public:
protected:
std::string delimeter;
std::ofstream datafile;
sg_ofstream datafile;
virtual bool OpenFile(void);
virtual void CloseFile(void) { if (datafile.is_open()) datafile.close(); }

View file

@ -58,7 +58,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGScript.cpp,v 1.64 2016/04/03 17:10:46 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGScript.cpp,v 1.65 2017/02/25 14:23:18 bcoconni Exp $");
IDENT(IdHdr,ID_FGSCRIPT);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -96,10 +96,11 @@ FGScript::~FGScript()
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGScript::LoadScript(const string& script, double default_dT,
const string& initfile)
bool FGScript::LoadScript(const SGPath& script, double default_dT,
const SGPath& initfile)
{
string aircraft="", initialize="", prop_name="";
SGPath initialize;
string aircraft="", prop_name="";
string notifyPropertyName="";
Element *element=0, *run_element=0, *event_element=0;
Element *set_element=0;
@ -171,9 +172,9 @@ bool FGScript::LoadScript(const string& script, double default_dT,
return false;
}
if (initfile.empty()) {
initialize = element->GetAttributeValue("initialize");
if (initialize.empty()) {
initialize = SGPath::fromLocal8Bit(element->GetAttributeValue("initialize").c_str());
if (initfile.isNull()) {
if (initialize.isNull()) {
cerr << "Initialization file must be specified in use element." << endl;
return false;
}

View file

@ -43,12 +43,13 @@ INCLUDES
#include "FGJSBBase.h"
#include "FGPropertyReader.h"
#include "input_output/FGPropertyManager.h"
#include "simgear/misc/sg_path.hxx"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_FGSCRIPT "$Id: FGScript.h,v 1.30 2015/09/20 16:32:11 bcoconni Exp $"
#define ID_FGSCRIPT "$Id: FGScript.h,v 1.31 2017/02/25 14:23:18 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -161,7 +162,7 @@ CLASS DOCUMENTATION
comes the &quot;run&quot; section, where the conditions are
described in &quot;event&quot; clauses.</p>
@author Jon S. Berndt
@version "$Id: FGScript.h,v 1.30 2015/09/20 16:32:11 bcoconni Exp $"
@version "$Id: FGScript.h,v 1.31 2017/02/25 14:23:18 bcoconni Exp $"
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -188,8 +189,8 @@ public:
default. If a file name is passed in, it will override the
one present in the script.
@return true if successful */
bool LoadScript(const std::string& script, double default_dT,
const std::string& initfile);
bool LoadScript(const SGPath& script, double default_dT,
const SGPath& initfile);
/** This function is called each pass through the executive Run() method IF
scripting is enabled.

View file

@ -45,7 +45,7 @@ FORWARD DECLARATIONS
namespace JSBSim {
IDENT(IdSrc,"$Id: FGXMLElement.cpp,v 1.55 2016/01/02 15:23:50 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGXMLElement.cpp,v 1.56 2016/09/11 11:26:04 bcoconni Exp $");
IDENT(IdHdr,ID_XMLELEMENT);
bool Element::converterIsInitialized = false;
@ -467,12 +467,14 @@ double Element::FindElementValueAsNumberConvertTo(const string& el, const string
// Sanity check for angular values
if ((supplied_units == "RAD") && (fabs(value) > 2 * M_PI)) {
cerr << element->ReadFrom() << "The value " << value
<< " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]" << endl;
cerr << element->ReadFrom() << element->GetName() << " value "
<< value << " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]"
<< endl;
}
if ((supplied_units == "DEG") && (fabs(value) > 360.0)) {
cerr << element->ReadFrom() << "The value " << value
<< " DEG is outside the range [ -360 DEG ; +360 DEG ]" << endl;
cerr << element->ReadFrom() << element->GetName() << " value "
<< value << " DEG is outside the range [ -360 DEG ; +360 DEG ]"
<< endl;
}
@ -481,12 +483,14 @@ double Element::FindElementValueAsNumberConvertTo(const string& el, const string
}
if ((target_units == "RAD") && (fabs(value) > 2 * M_PI)) {
cerr << element->ReadFrom() << "The value " << value
<< " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]" << endl;
cerr << element->ReadFrom() << element->GetName() << " value "
<< value << " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]"
<< endl;
}
if ((target_units == "DEG") && (fabs(value) > 360.0)) {
cerr << element->ReadFrom() << "The value " << value
<< " DEG is outside the range [ -360 DEG ; +360 DEG ]" << endl;
cerr << element->ReadFrom() << element->GetName() << " value "
<< value << " DEG is outside the range [ -360 DEG ; +360 DEG ]"
<< endl;
}
value = DisperseValue(element, value, supplied_units, target_units);

View file

@ -35,15 +35,18 @@ SENTRY
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "input_output/FGXMLParse.h"
#include <iostream>
#include <fstream>
#include "input_output/FGXMLParse.h"
#include "simgear/misc/sg_path.hxx"
#include "simgear/io/iostreams/sgstream.hxx"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_XMLFILEREAD "$Id: FGXMLFileRead.h,v 1.9 2013/12/01 14:33:51 bcoconni Exp $"
#define ID_XMLFILEREAD "$Id: FGXMLFileRead.h,v 1.10 2017/02/25 14:23:18 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -56,20 +59,23 @@ public:
FGXMLFileRead(void) {}
~FGXMLFileRead(void) {}
Element* LoadXMLDocument(std::string XML_filename, bool verbose=true)
Element* LoadXMLDocument(const SGPath& XML_filename, bool verbose=true)
{
return LoadXMLDocument(XML_filename, file_parser, verbose);
}
Element* LoadXMLDocument(std::string XML_filename, FGXMLParse& fparse, bool verbose=true)
Element* LoadXMLDocument(const SGPath& XML_filename, FGXMLParse& fparse, bool verbose=true)
{
std::ifstream infile;
sg_ifstream infile;
SGPath filename(XML_filename);
if ( !XML_filename.empty() ) {
if (XML_filename.find(".xml") == std::string::npos) XML_filename += ".xml";
infile.open(XML_filename.c_str());
if (!filename.isNull()) {
if (filename.extension().empty())
filename.concat(".xml");
infile.open(filename);
if ( !infile.is_open()) {
if (verbose) std::cerr << "Could not open file: " << XML_filename << std::endl;
if (verbose) std::cerr << "Could not open file: " << filename << std::endl;
return 0L;
}
} else {
@ -77,7 +83,7 @@ public:
return 0L;
}
readXML(infile, fparse, XML_filename);
readXML(infile, fparse, filename.utf8Str());
Element* document = fparse.GetDocument();
infile.close();

View file

@ -57,7 +57,7 @@ using std::string;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGfdmSocket.cpp,v 1.31 2015/03/22 12:19:31 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGfdmSocket.cpp,v 1.32 2017/03/11 12:12:12 bcoconni Exp $");
IDENT(IdHdr,ID_FDMSOCKET);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -93,9 +93,9 @@ FGfdmSocket::FGfdmSocket(const string& address, int port, int protocol)
cout << "Could not get host net address by name..." << endl;
}
} else {
unsigned int ip;
unsigned long ip;
ip = inet_addr(address.c_str());
if ((host = gethostbyaddr((char*)&ip, address.size(), PF_INET)) == NULL) {
if ((host = gethostbyaddr((char*)&ip, sizeof(ip), PF_INET)) == NULL) {
cout << "Could not get host net address by number..." << endl;
}
}

View file

@ -104,6 +104,8 @@ bool FGAccelerations::InitModel(void)
vGravAccel.InitMatrix();
vBodyAccel.InitMatrix();
maxiter = 50;
matrixSize = iter = 0;
return true;
}
@ -255,6 +257,7 @@ void FGAccelerations::ResolveFrictionForces(double dt)
FGColumnVector3 vdot, wdot;
vector<LagrangeMultiplier*>& multipliers = *in.MultipliersList;
size_t n = multipliers.size();
matrixSize = n;
vFrictionForces.InitMatrix();
vFrictionMoments.InitMatrix();
@ -303,7 +306,7 @@ void FGAccelerations::ResolveFrictionForces(double dt)
}
// Resolve the Lagrange multipliers with the projected Gauss-Seidel method
for (int iter=0; iter < 50; iter++) {
for (iter=0; iter < maxiter; iter = iter+1) {
double norm = 0.;
for (unsigned int i=0; i < n; i++) {
@ -384,6 +387,10 @@ void FGAccelerations::bind(void)
PropertyManager->Tie("forces/fbx-gear-lbs", this, eX, (PMF)&FGAccelerations::GetGroundForces);
PropertyManager->Tie("forces/fby-gear-lbs", this, eY, (PMF)&FGAccelerations::GetGroundForces);
PropertyManager->Tie("forces/fbz-gear-lbs", this, eZ, (PMF)&FGAccelerations::GetGroundForces);
iter = PropertyManager->CreatePropertyObject<int>("numerical/friction-resolver/iterations");
maxiter = PropertyManager->CreatePropertyObject<int>("numerical/friction-resolver/max-iterations");
matrixSize = PropertyManager->CreatePropertyObject<int>("numerical/friction-resolver/matrix-size");
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -40,6 +40,7 @@ INCLUDES
#include <vector>
#include "simgear/props/propertyObject.hxx"
#include "models/FGModel.h"
#include "math/FGColumnVector3.h"
#include "math/LagrangeMultiplier.h"
@ -391,6 +392,7 @@ private:
FGColumnVector3 vGravAccel;
FGColumnVector3 vFrictionForces;
FGColumnVector3 vFrictionMoments;
simgear::PropertyObject<int> iter, maxiter, matrixSize;
int gravType;
bool gravTorque;

View file

@ -70,7 +70,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGFCS.cpp,v 1.95 2016/05/16 18:19:57 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGFCS.cpp,v 1.98 2017/02/25 14:23:18 bcoconni Exp $");
IDENT(IdHdr,ID_FCS);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -602,16 +602,15 @@ double FGFCS::GetBrake(FGLGear::BrakeGroup bg)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGFCS::FindFullPathName(const string& sysfilename) const
SGPath FGFCS::FindFullPathName(const SGPath& path) const
{
string name = FGModel::FindFullPathName(sysfilename);
SGPath name = FGModel::FindFullPathName(path);
if (systype != stSystem || !name.isNull()) return name;
if (systype != stSystem || !name.empty()) return name;
name = CheckPathName(FDMExec->GetFullAircraftPath()/string("Systems"), path);
if (!name.isNull()) return name;
name = CheckFullPathName(FDMExec->GetFullAircraftPath() + "/Systems", sysfilename);
if (!name.empty()) return name;
return CheckFullPathName(FDMExec->GetSystemsPath(), sysfilename);
return CheckPathName(FDMExec->GetSystemsPath(), path);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -50,7 +50,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_FCS "$Id: FGFCS.h,v 1.53 2016/05/18 08:06:57 ehofman Exp $"
#define ID_FCS "$Id: FGFCS.h,v 1.55 2017/03/03 23:03:20 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -168,7 +168,7 @@ CLASS DOCUMENTATION
@property gear/tailhook-pos-norm
@author Jon S. Berndt
@version $Revision: 1.53 $
@version $Revision: 1.55 $
@see FGActuator
@see FGDeadBand
@see FGFCSFunction
@ -430,7 +430,7 @@ public:
/** Sets the propeller pitch command for the specified engine
@param engine engine ID number
@param cmd mixture command in percent (0.0 - 1.0)*/
@param cmd pitch command in percent (0.0 - 1.0)*/
void SetPropAdvanceCmd(int engine, double cmd);
/** Sets the propeller feather command for the specified engine
@ -544,7 +544,7 @@ public:
@return true if succesful */
bool Load(Element* el);
std::string FindFullPathName(const std::string& system_filename) const;
SGPath FindFullPathName(const SGPath& path) const;
void AddThrottle(void);
double GetDt(void) const;

View file

@ -50,7 +50,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGInput.cpp,v 1.34 2015/08/23 09:43:31 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGInput.cpp,v 1.35 2017/02/25 14:23:19 bcoconni Exp $");
IDENT(IdHdr,ID_INPUT);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -153,7 +153,7 @@ bool FGInput::Run(bool Holding)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGInput::SetDirectivesFile(const std::string& fname)
bool FGInput::SetDirectivesFile(const SGPath& fname)
{
FGXMLFileRead XMLFile;
Element* document = XMLFile.LoadXMLDocument(fname);

View file

@ -46,7 +46,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_INPUT "$Id: FGInput.h,v 1.13 2015/08/23 09:43:31 bcoconni Exp $"
#define ID_INPUT "$Id: FGInput.h,v 1.14 2017/02/25 14:23:19 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -81,7 +81,7 @@ CLASS DOCUMENTATION
The class FGInput is the manager of the inputs requested by the user. It
manages a list of instances derived from the abstract class FGInputType.
@version $Id: FGInput.h,v 1.13 2015/08/23 09:43:31 bcoconni Exp $
@version $Id: FGInput.h,v 1.14 2017/02/25 14:23:19 bcoconni Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -122,7 +122,7 @@ public:
@param fname the name of the file from which the ouput directives should
be read.
@return true if the execution succeeded. */
bool SetDirectivesFile(const std::string& fname);
bool SetDirectivesFile(const SGPath& fname);
/// Enables the input generation for all input instances.
void Enable(void) { enabled = true; }

View file

@ -61,7 +61,7 @@ DEFINITIONS
GLOBAL DATA
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
IDENT(IdSrc,"$Id: FGLGear.cpp,v 1.124 2016/06/25 17:48:02 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGLGear.cpp,v 1.125 2017/02/21 21:14:13 bcoconni Exp $");
IDENT(IdHdr,ID_LGEAR);
// Body To Structural (body frame is rotated 180 deg about Y and lengths are given in
@ -784,6 +784,12 @@ void FGLGear::bind(void)
property_name = base_property_name + "/WOW";
PropertyManager->Tie( property_name.c_str(), &WOW );
property_name = base_property_name + "/x-position";
PropertyManager->Tie( property_name.c_str(), (FGForce*)this,
&FGForce::GetLocationX, &FGForce::SetLocationX);
property_name = base_property_name + "/y-position";
PropertyManager->Tie( property_name.c_str(), (FGForce*)this,
&FGForce::GetLocationY, &FGForce::SetLocationY);
property_name = base_property_name + "/z-position";
PropertyManager->Tie( property_name.c_str(), (FGForce*)this,
&FGForce::GetLocationZ, &FGForce::SetLocationZ);

View file

@ -49,7 +49,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_LGEAR "$Id: FGLGear.h,v 1.65 2016/05/16 18:19:57 bcoconni Exp $"
#define ID_LGEAR "$Id: FGLGear.h,v 1.66 2017/03/11 12:07:22 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -178,7 +178,7 @@ CLASS DOCUMENTATION
</contact>
@endcode
@author Jon S. Berndt
@version $Id: FGLGear.h,v 1.65 2016/05/16 18:19:57 bcoconni Exp $
@version $Id: FGLGear.h,v 1.66 2017/03/11 12:07:22 bcoconni Exp $
@see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
NASA-Ames", NASA CR-2497, January 1975
@see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
@ -273,7 +273,9 @@ public:
/** Get the console touchdown reporting feature
@return true if reporting is turned on */
bool GetReport(void) const { return ReportEnable; }
double GetSteerNorm(void) const { return radtodeg/maxSteerAngle*SteerAngle; }
double GetSteerNorm(void) const {
return maxSteerAngle == 0.0 ? 0.0 : radtodeg/maxSteerAngle*SteerAngle;
}
void SetSteerCmd(double cmd) { SetSteerAngleDeg(cmd * maxSteerAngle); }
double GetstaticFCoeff(void) const { return staticFCoeff; }

View file

@ -46,7 +46,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGModel.cpp,v 1.26 2015/07/12 19:34:08 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGModel.cpp,v 1.27 2017/02/25 14:23:19 bcoconni Exp $");
IDENT(IdHdr,ID_MODEL);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -103,9 +103,9 @@ bool FGModel::Run(bool Holding)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGModel::FindFullPathName(const string& fname) const
SGPath FGModel::FindFullPathName(const SGPath& path) const
{
return CheckFullPathName(FDMExec->GetFullAircraftPath(), fname);
return CheckPathName(FDMExec->GetFullAircraftPath(), path);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -41,12 +41,13 @@ INCLUDES
#include <string>
#include "math/FGModelFunctions.h"
#include "simgear/misc/sg_path.hxx"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_MODEL "$Id: FGModel.h,v 1.25 2015/08/16 13:19:52 bcoconni Exp $"
#define ID_MODEL "$Id: FGModel.h,v 1.26 2017/02/25 14:23:19 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -100,7 +101,7 @@ public:
FGFDMExec* GetExec(void) {return FDMExec;}
void SetPropertyManager(FGPropertyManager *fgpm) { PropertyManager=fgpm;}
virtual std::string FindFullPathName(const std::string& filename) const;
virtual SGPath FindFullPathName(const SGPath& path) const;
protected:
unsigned int exe_ctr;
@ -119,4 +120,3 @@ protected:
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif

View file

@ -53,7 +53,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGOutput.cpp,v 1.86 2015/08/23 09:43:31 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGOutput.cpp,v 1.87 2017/02/25 14:23:19 bcoconni Exp $");
IDENT(IdHdr,ID_OUTPUT);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -182,7 +182,7 @@ string FGOutput::GetOutputName(unsigned int idx) const
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGOutput::SetDirectivesFile(const std::string& fname)
bool FGOutput::SetDirectivesFile(const SGPath& fname)
{
FGXMLFileRead XMLFile;
Element* document = XMLFile.LoadXMLDocument(fname);

View file

@ -47,7 +47,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_OUTPUT "$Id: FGOutput.h,v 1.33 2015/08/23 09:43:31 bcoconni Exp $"
#define ID_OUTPUT "$Id: FGOutput.h,v 1.34 2017/02/25 14:23:19 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -121,7 +121,7 @@ CLASS DOCUMENTATION
The class FGOutput is the manager of the outputs requested by the user. It
manages a list of instances derived from the abstract class FGOutputType.
@version $Id: FGOutput.h,v 1.33 2015/08/23 09:43:31 bcoconni Exp $
@version $Id: FGOutput.h,v 1.34 2017/02/25 14:23:19 bcoconni Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -181,7 +181,7 @@ public:
@param fname the name of the file from which the ouput directives should
be read.
@return true if the execution succeeded. */
bool SetDirectivesFile(const std::string& fname);
bool SetDirectivesFile(const SGPath& fname);
/// Enables the output generation for all output instances.
void Enable(void) { enabled = true; }
/// Disables the output generation for all output instances.

View file

@ -67,19 +67,19 @@ INCLUDES
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <fstream>
#include "initialization/FGInitialCondition.h"
#include "FGPropagate.h"
#include "FGGroundReactions.h"
#include "FGFDMExec.h"
#include "input_output/FGPropertyManager.h"
#include "simgear/io/iostreams/sgstream.hxx"
using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGPropagate.cpp,v 1.131 2016/05/01 18:25:57 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGPropagate.cpp,v 1.132 2017/02/25 14:23:19 bcoconni Exp $");
IDENT(IdHdr,ID_PROPAGATE);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -659,21 +659,21 @@ void FGPropagate::DumpState(void)
void FGPropagate::WriteStateFile(int num)
{
ofstream outfile;
sg_ofstream outfile;
if (num == 0) return;
string filename = FDMExec->GetFullAircraftPath();
SGPath path = FDMExec->GetFullAircraftPath();
if (filename.empty()) filename = "initfile.";
else filename.append("/initfile.");
if (path.isNull()) path = SGPath("initfile.");
else path.append("initfile.");
// Append sim time to the filename since there may be more than one created during a simulation run
filename += to_string((double)FDMExec->GetSimTime())+".xml";
path.concat(to_string((double)FDMExec->GetSimTime())+".xml");
switch(num) {
case 1:
outfile.open(filename.c_str());
outfile.open(path);
if (outfile.is_open()) {
outfile << "<?xml version=\"1.0\"?>" << endl;
outfile << "<initialize name=\"reset00\">" << endl;
@ -689,11 +689,12 @@ void FGPropagate::WriteStateFile(int num)
outfile << "</initialize>" << endl;
outfile.close();
} else {
cerr << "Could not open and/or write the state to the initial conditions file: " << filename << endl;
cerr << "Could not open and/or write the state to the initial conditions file: "
<< path << endl;
}
break;
case 2:
outfile.open(filename.c_str());
outfile.open(path);
if (outfile.is_open()) {
outfile << "<?xml version=\"1.0\"?>" << endl;
outfile << "<initialize name=\"IC File\" version=\"2.0\">" << endl;
@ -725,7 +726,8 @@ void FGPropagate::WriteStateFile(int num)
outfile << "</initialize>" << endl;
outfile.close();
} else {
cerr << "Could not open and/or write the state to the initial conditions file: " << filename << endl;
cerr << "Could not open and/or write the state to the initial conditions file: "
<< path << endl;
}
break;
default:

View file

@ -65,7 +65,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGPropulsion.cpp,v 1.87 2016/05/05 15:38:09 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGPropulsion.cpp,v 1.88 2017/02/25 14:23:19 bcoconni Exp $");
IDENT(IdHdr,ID_PROPULSION);
extern short debug_lvl;
@ -463,14 +463,15 @@ bool FGPropulsion::Load(Element* el)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGPropulsion::FindFullPathName(const string& filename) const
SGPath FGPropulsion::FindFullPathName(const SGPath& path) const
{
if (!ReadingEngine) return FGModel::FindFullPathName(filename);
if (!ReadingEngine) return FGModel::FindFullPathName(path);
string name = CheckFullPathName(FDMExec->GetFullAircraftPath() + "/Engines", filename);
if (!name.empty()) return name;
SGPath name = CheckPathName(FDMExec->GetFullAircraftPath()/string("Engines"),
path);
if (!name.isNull()) return name;
return CheckFullPathName(FDMExec->GetEnginePath(), filename);
return CheckPathName(FDMExec->GetEnginePath(), path);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -50,7 +50,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_PROPULSION "$Id: FGPropulsion.h,v 1.36 2016/05/05 15:38:08 bcoconni Exp $"
#define ID_PROPULSION "$Id: FGPropulsion.h,v 1.37 2017/02/25 14:23:19 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -93,7 +93,7 @@ CLASS DOCUMENTATION
@endcode
@author Jon S. Berndt
@version $Id: FGPropulsion.h,v 1.36 2016/05/05 15:38:08 bcoconni Exp $
@version $Id: FGPropulsion.h,v 1.37 2017/02/25 14:23:19 bcoconni Exp $
@see
FGEngine
FGTank
@ -180,7 +180,7 @@ public:
const FGColumnVector3& GetTanksMoment(void);
double GetTanksWeight(void) const;
std::string FindFullPathName(const std::string& filename) const;
SGPath FindFullPathName(const SGPath& path) const;
inline int GetActiveEngine(void) const {return ActiveEngine;}
inline bool GetFuelFreeze(void) const {return FuelFreeze;}

0
src/FDM/JSBSim/models/flight_control/FGAngles.cpp Executable file → Normal file
View file

View file

@ -53,7 +53,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGEngine.cpp,v 1.67 2015/09/27 09:54:21 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGEngine.cpp,v 1.68 2017/03/03 23:00:39 bcoconni Exp $");
IDENT(IdHdr,ID_ENGINE);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -158,7 +158,7 @@ void FGEngine::LoadThrusterInputs()
{
Thruster->in.TotalDeltaT = in.TotalDeltaT;
Thruster->in.H_agl = in.H_agl;
Thruster->in.PQR = in.PQR;
Thruster->in.PQRi = in.PQRi;
Thruster->in.AeroPQR = in.AeroPQR;
Thruster->in.AeroUVW = in.AeroUVW;
Thruster->in.Density = in.Density;

View file

@ -53,7 +53,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_ENGINE "$Id: FGEngine.h,v 1.47 2015/09/27 10:16:57 bcoconni Exp $"
#define ID_ENGINE "$Id: FGEngine.h,v 1.48 2017/03/03 23:00:39 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -111,7 +111,7 @@ CLASS DOCUMENTATION
documentation for engine and thruster classes.
</pre>
@author Jon S. Berndt
@version $Id: FGEngine.h,v 1.47 2015/09/27 10:16:57 bcoconni Exp $
@version $Id: FGEngine.h,v 1.48 2017/03/03 23:00:39 bcoconni Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -138,7 +138,7 @@ public:
double H_agl;
FGColumnVector3 AeroUVW;
FGColumnVector3 AeroPQR;
FGColumnVector3 PQR;
FGColumnVector3 PQRi;
std::vector <double> ThrottleCmd;
std::vector <double> MixtureCmd;
std::vector <double> ThrottlePos;

View file

@ -45,7 +45,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGPropeller.cpp,v 1.58 2016/06/04 11:06:51 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGPropeller.cpp,v 1.60 2017/03/03 23:00:39 bcoconni Exp $");
IDENT(IdHdr,ID_PROPELLER);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -80,8 +80,8 @@ FGPropeller::FGPropeller(FGFDMExec* exec, Element* prop_element, int num)
Ixx = max(prop_element->FindElementValueAsNumberConvertTo("ixx", "SLUG*FT2"), 0.001);
Sense_multiplier = 1.0;
if (prop_element->HasAttribute("version"))
if (prop_element->GetAttributeValueAsNumber("version") > 1.0)
if (prop_element->HasAttribute("version")
&& prop_element->GetAttributeValueAsNumber("version") > 1.0)
Sense_multiplier = -1.0;
if (prop_element->FindElement("diameter"))
@ -146,6 +146,7 @@ FGPropeller::FGPropeller(FGFDMExec* exec, Element* prop_element, int num)
Type = ttPropeller;
RPM = 0;
vTorque.InitMatrix();
vH.InitMatrix();
D4 = Diameter*Diameter*Diameter*Diameter;
D5 = D4*Diameter;
Pitch = MinPitch;
@ -186,6 +187,14 @@ FGPropeller::~FGPropeller()
Debug(1);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPropeller::ResetToIC(void)
{
FGThruster::ResetToIC();
Vinduced = 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// We must be getting the aerodynamic velocity here, NOT the inertial velocity.
@ -211,11 +220,11 @@ double FGPropeller::Calculate(double EnginePower)
double Vtip = RPS * Diameter * M_PI;
HelicalTipMach = sqrt(Vtip*Vtip + Vel*Vel) / in.Soundspeed;
PowerAvailable = EnginePower - GetPowerRequired();
if (RPS > 0.0) J = Vel / (Diameter * RPS); // Calculate J normally
else J = Vel / Diameter;
PowerAvailable = EnginePower - GetPowerRequired();
if (MaxPitch == MinPitch) { // Fixed pitch prop
ThrustCoeff = cThrust->GetValue(J);
} else { // Variable pitch prop
@ -265,8 +274,6 @@ double FGPropeller::Calculate(double EnginePower)
// FGForce::GetBodyForces() function.
vH(eX) = Ixx*omega*Sense*Sense_multiplier;
vH(eY) = 0.0;
vH(eZ) = 0.0;
if (omega > 0.0) ExcessTorque = PowerAvailable / omega;
else ExcessTorque = PowerAvailable / 1.0;
@ -277,7 +284,7 @@ double FGPropeller::Calculate(double EnginePower)
// Transform Torque and momentum first, as PQR is used in this
// equation and cannot be transformed itself.
vMn = in.PQR*(Transform()*vH) + Transform()*vTorque;
vMn = in.PQRi*(Transform()*vH) + Transform()*vTorque;
return Thrust; // return thrust in pounds
}
@ -286,13 +293,7 @@ double FGPropeller::Calculate(double EnginePower)
double FGPropeller::GetPowerRequired(void)
{
double cPReq, J;
double rho = in.Density;
double Vel = in.AeroUVW(eU) + Vinduced;
double RPS = RPM / 60.0;
if (RPS != 0.0) J = Vel / (Diameter * RPS);
else J = Vel / Diameter;
double cPReq;
if (MaxPitch == MinPitch) { // Fixed pitch prop
cPReq = cPower->GetValue(J);
@ -303,7 +304,7 @@ double FGPropeller::GetPowerRequired(void)
// do normal calculation when propeller is neither feathered nor reversed
// Note: This method of feathering and reversing was added to support the
// turboprop model. It's left here for backward compatablity, but
// turboprop model. It's left here for backward compatiblity, but
// now feathering and reversing should be done in Manual Pitch Mode.
if (!Feathered) {
if (!Reversed) {
@ -349,9 +350,10 @@ double FGPropeller::GetPowerRequired(void)
// Apply optional Mach effects from CP_MACH table
if (CpMach) cPReq *= CpMach->GetValue(HelicalTipMach);
double RPS = RPM / 60.0;
double local_RPS = RPS < 0.01 ? 0.01 : RPS;
PowerRequired = cPReq*local_RPS*local_RPS*local_RPS*D5*rho;
PowerRequired = cPReq*local_RPS*local_RPS*local_RPS*D5*in.Density;
vTorque(eX) = -Sense*PowerRequired / (local_RPS*2.0*M_PI);
return PowerRequired;

View file

@ -45,7 +45,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_PROPELLER "$Id: FGPropeller.h,v 1.26 2016/01/02 17:42:53 bcoconni Exp $"
#define ID_PROPELLER "$Id: FGPropeller.h,v 1.28 2017/03/03 23:00:39 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -57,13 +57,14 @@ namespace JSBSim {
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** FGPropeller models a propeller given the tabular data for Ct and Cp,
indexed by the advance ratio "J".
/** FGPropeller models a propeller given the tabular data for Ct (thrust) and
Cp (power), indexed by the advance ratio "J".
<h3>Configuration File Format:</h3>
@code
### Configuration File Format
~~~{.xml}
<sense> {1 | -1} </sense>
<propeller name="{string}">
<propeller name="{string}" version="{string}">
<ixx> {number} </ixx>
<diameter unit="IN"> {number} </diameter>
<numblades> {number} </numblades>
@ -102,11 +103,11 @@ CLASS DOCUMENTATION
</tableData>
</table>
</propeller>
@endcode
~~~
### Configuration Parameters
<h3>Configuration Parameters:</h3>
<pre>
\<ixx> - Propeller rotational inertia.
\<diameter> - Propeller disk diameter.
@ -126,25 +127,40 @@ CLASS DOCUMENTATION
\<cp_factor> - A multiplier for the coefficients of power.
</pre>
Two tables are needed. One for coefficient of thrust (Ct) and one for
coefficient of power (Cp).
Two tables are needed. One for coefficient of thrust (Ct) and one for
coefficient of power (Cp).
Two tables are optional. They apply a factor to Ct and Cp based on the
helical tip Mach.
<br>
Two tables are optional. They apply a factor to Ct and Cp based on the
helical tip Mach.
Several references were helpful, here:<ul>
<li>Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
Wiley & Sons, 1979 ISBN 0-471-03032-5</li>
<li>Edwin Hartman, David Biermann, "The Aerodynamic Characteristics of
Full Scale Propellers Having 2, 3, and 4 Blades of Clark Y and R.A.F. 6
Airfoil Sections", NACA Report TN-640, 1938 (?)</li>
<li>Various NACA Technical Notes and Reports</li>
</ul>
@author Jon S. Berndt
@version $Id: FGPropeller.h,v 1.26 2016/01/02 17:42:53 bcoconni Exp $
@see FGEngine
@see FGThruster
In addition to thrust, the propeller applies two moments to the aircraft:
- The torque that tends to roll the aircraft in the direction opposite to the
propeller rotation,
- and the gyroscopic moment.
It should be noted that historically the gyroscopic moment had an incorrect
sign. The correct sign can be obtained by specifying a **version** attribute
higher than 1.0 to the propeller definition
~~~.xml
<propeller name="a_prop" version="1.1">
<!-- propeller definition -->
</propeller>
~~~
For backward compatibility, the absence of the **version** attribute will result
in the gyroscopic moment to be computed with the legacy incorrect sign.
Several references were helpful, here:
+ Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
Wiley & Sons, 1979 ISBN 0-471-03032-5
+ Edwin Hartman, David Biermann, "The Aerodynamic Characteristics of
Full Scale Propellers Having 2, 3, and 4 Blades of Clark Y and R.A.F. 6
Airfoil Sections", NACA Report TN-640, 1938 (?)
+ Various NACA Technical Notes and Reports
@author Jon S. Berndt
@version $Id: FGPropeller.h,v 1.28 2017/03/03 23:00:39 bcoconni Exp $
@see FGEngine
@see FGThruster
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -163,15 +179,19 @@ public:
/// Destructor for FGPropeller - deletes the FGTable objects
~FGPropeller();
/// Reset the initial conditions.
void ResetToIC(void);
/** Sets the Revolutions Per Minute for the propeller. Normally the propeller
instance will calculate its own rotational velocity, given the Torque
produced by the engine and integrating over time using the standard
equation for rotational acceleration "a": a = Q/I , where Q is Torque and
I is moment of inertia for the propeller.
equation for rotational acceleration \f$a\f$: \f$a = Q/I\f$ , where
\f$Q\f$ is Torque and \f$I\f$ is moment of inertia for the propeller.
@param rpm the rotational velocity of the propeller */
void SetRPM(double rpm) {RPM = rpm;}
/** Sets the Revolutions Per Minute for the propeller using the engine gear ratio **/
/** Sets the Revolutions Per Minute for the propeller using the engine gear
ratio */
void SetEngineRPM(double rpm) {RPM = rpm/GearRatio;}
/// Returns true of this propeller is variable pitch
@ -186,6 +206,9 @@ public:
@param pitch the pitch of the blade in degrees. */
void SetPitch(double pitch) {Pitch = pitch;}
/** Set the propeller pitch.
@param advance the pitch command in percent (0.0 - 1.0)
*/
void SetAdvance(double advance) {Advance = advance;}
/// Sets the P-Factor constant
@ -255,20 +278,35 @@ public:
would be slowed.
@return the thrust in pounds */
double Calculate(double EnginePower);
/// Retrieves the P-Factor constant
FGColumnVector3 GetPFactor(void) const;
/// Generate the labels for the thruster standard CSV output
std::string GetThrusterLabels(int id, const std::string& delimeter);
/// Generate the values for the thruster standard CSV output
std::string GetThrusterValues(int id, const std::string& delimeter);
/** Set the propeller reverse pitch.
@param c the reverse pitch command in percent (0.0 - 1.0)
*/
void SetReverseCoef (double c) { Reverse_coef = c; }
/// Retrieves the reverse pitch command.
double GetReverseCoef (void) const { return Reverse_coef; }
/// If true, sets the propeller in reversed position.
void SetReverse (bool r) { Reversed = r; }
/// Returns true if the propeller is in reverse position.
bool GetReverse (void) const { return Reversed; }
/// If true, sets the propeller in feathered position.
void SetFeather (bool f) { Feathered = f; }
/// Returns true if the propeller is in feathered position.
bool GetFeather (void) const { return Feathered; }
/// Retrieves the thrust coefficient
double GetThrustCoefficient(void) const {return ThrustCoeff;}
/// Retrieves the Mach number at the propeller tips.
double GetHelicalTipMach(void) const {return HelicalTipMach;}
/// Returns a non-zero value if the propeller is constant speed.
int GetConstantSpeed(void) const {return ConstantSpeed;}
/// Set the propeller induced velocity
void SetInducedVelocity(double Vi) {Vinduced = Vi;}
/// Get the propeller induced velocity.
double GetInducedVelocity(void) const {return Vinduced;}
private:

View file

@ -48,7 +48,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGTank.cpp,v 1.45 2016/05/05 17:23:10 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGTank.cpp,v 1.46 2017/02/21 21:07:04 bcoconni Exp $");
IDENT(IdHdr,ID_TANK);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -465,6 +465,14 @@ void FGTank::bind(FGPropertyManager* PropertyManager)
PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetIyy);
property_name = base_property_name + "/local-izz-slug_ft2";
PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetIzz);
property_name = base_property_name + "/x-position";
PropertyManager->Tie(property_name.c_str(), (FGTank*)this, &FGTank::GetLocationX, &FGTank::SetLocationX);
property_name = base_property_name + "/y-position";
PropertyManager->Tie(property_name.c_str(), (FGTank*)this, &FGTank::GetLocationY, &FGTank::SetLocationY);
property_name = base_property_name + "/z-position";
PropertyManager->Tie(property_name.c_str(), (FGTank*)this, &FGTank::GetLocationZ, &FGTank::SetLocationZ);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -53,7 +53,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_TANK "$Id: FGTank.h,v 1.31 2015/12/09 04:28:18 jberndt Exp $"
#define ID_TANK "$Id: FGTank.h,v 1.32 2017/02/21 21:07:04 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -283,6 +283,13 @@ public:
double GetIyy(void) const {return Iyy;}
double GetIzz(void) const {return Izz;}
inline double GetLocationX(void) const { return vXYZ(eX); }
inline double GetLocationY(void) const { return vXYZ(eY); }
inline double GetLocationZ(void) const { return vXYZ(eZ); }
inline void SetLocationX(double x) { vXYZ(eX) = x; }
inline void SetLocationY(double y) { vXYZ(eY) = y; }
inline void SetLocationZ(double z) { vXYZ(eZ) = z; }
double GetStandpipe(void) const {return Standpipe;}
int GetPriority(void) const {return Priority;}

View file

@ -46,7 +46,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_THRUSTER "$Id: FGThruster.h,v 1.26 2015/09/27 10:03:53 bcoconni Exp $"
#define ID_THRUSTER "$Id: FGThruster.h,v 1.27 2017/03/03 23:00:39 bcoconni 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.26 2015/09/27 10:03:53 bcoconni Exp $
@version $Id: FGThruster.h,v 1.27 2017/03/03 23:00:39 bcoconni Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -116,7 +116,7 @@ public:
struct Inputs {
double TotalDeltaT;
double H_agl;
FGColumnVector3 PQR;
FGColumnVector3 PQRi;
FGColumnVector3 AeroPQR;
FGColumnVector3 AeroUVW;
double Density;

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

@ -55,7 +55,7 @@ using namespace std;
namespace JSBSim {
IDENT(IdSrc,"$Id: FGTurboProp.cpp,v 1.35 2016/07/10 12:39:28 bcoconni Exp $");
IDENT(IdSrc,"$Id: FGTurboProp.cpp,v 1.36 2017/02/26 11:41:28 bcoconni Exp $");
IDENT(IdHdr,ID_TURBOPROP);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -111,8 +111,6 @@ bool FGTurboProp::Load(FGFDMExec* exec, Element *el)
// ToDo: Need to make sure units are properly accounted for below.
if (el->FindElement("milthrust"))
MilThrust = el->FindElementValueAsNumberConvertTo("milthrust","LBS");
if (el->FindElement("idlen1"))
IdleN1 = el->FindElementValueAsNumber("idlen1");
if (el->FindElement("maxn1"))
@ -197,7 +195,8 @@ void FGTurboProp::Calculate(void)
ThrottlePos = in.ThrottlePos[EngineNumber];
/* The thruster controls the engine RPM because it encapsulates the gear ratio and other transmission variables */
/* The thruster controls the engine RPM because it encapsulates the gear ratio
and other transmission variables */
RPM = Thruster->GetEngineRPM();
if (thrusterType == FGThruster::ttPropeller) {
((FGPropeller*)Thruster)->SetAdvance(in.PropAdvance[EngineNumber]);
@ -320,7 +319,6 @@ double FGTurboProp::Off(void)
double FGTurboProp::Run(void)
{
double thrust = 0.0;
double EngPower_HP;
Running = true; Starter = false; EngStarting = false;
@ -342,7 +340,6 @@ double FGTurboProp::Run(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
//---
EPR = 1.0 + thrust/MilThrust;
OilTemp_degK = Seek(&OilTemp_degK, 353.15, 0.4-N1*0.001, 0.04);
@ -477,7 +474,6 @@ void FGTurboProp::SetDefaults(void)
N1 = 0.0;
HP = 0.0;
Type = etTurboprop;
MilThrust = 10000.0;
IdleN1 = 30.0;
MaxN1 = 100.0;
Reversed = false;
@ -590,7 +586,6 @@ void FGTurboProp::Debug(int from)
if (from == 2) { // called from Load()
cout << "\n ****MUJ MOTOR TURBOPROP****\n";
cout << "\n Engine Name: " << Name << endl;
cout << " MilThrust: " << MilThrust << endl;
cout << " IdleN1: " << IdleN1 << endl;
cout << " MaxN1: " << MaxN1 << endl;

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

@ -46,7 +46,7 @@ INCLUDES
#include "FGEngine.h"
#include "math/FGTable.h"
#define ID_TURBOPROP "$Id: FGTurboProp.h,v 1.24 2016/07/10 12:39:28 bcoconni Exp $"
#define ID_TURBOPROP "$Id: FGTurboProp.h,v 1.25 2017/02/26 11:41:28 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -121,7 +121,6 @@ public:
bool GetCutoff(void) const { return Cutoff; }
double GetN1(void) const {return N1;}
double GetEPR(void) const {return EPR;}
double GetITT(void) const {return Eng_ITT_degC;}
double GetEngStarting(void) const { return EngStarting; }
@ -132,7 +131,6 @@ public:
inline int GetCondition(void) const { return Condition; }
void SetPhase( phaseType p ) { phase = p; }
void SetEPR(double epr) {EPR = epr;}
void SetReverse(bool reversed) { Reversed = reversed; }
void SetCutoff(bool cutoff) { Cutoff = cutoff; }
@ -145,7 +143,6 @@ public:
private:
phaseType phase; ///< Operating mode, or "phase"
double MilThrust; ///< Maximum Unaugmented Thrust, static @ S.L. (lbf)
double IdleN1; ///< Idle N1
double N1; ///< N1
double MaxN1; ///< N1 at 100% throttle
@ -155,7 +152,6 @@ private:
bool Reversed;
bool Cutoff;
double EPR;
double OilPressure_psi;
double OilTemp_degK;

View file

@ -17,7 +17,6 @@
namespace yasim {
// gadgets
inline float norm(float f) { return f<1 ? 1/f : f; }
inline float abs(float f) { return f<0 ? -f : f; }
// Solver threshold. How close to the solution are we trying
@ -57,6 +56,9 @@ Airplane::Airplane()
_tailIncidence = 0;
_failureMsg = 0;
_wingsN = 0;
_cgMaxX = -1e6;
_cgMinX = 1e6;
}
Airplane::~Airplane()
@ -113,16 +115,6 @@ void Airplane::calcFuelWeights()
}
}
ControlMap* Airplane::getControlMap()
{
return &_controls;
}
Model* Airplane::getModel()
{
return &_model;
}
void Airplane::getPilotAccel(float* out)
{
State* s = _model.getState();
@ -145,43 +137,6 @@ void Airplane::getPilotAccel(float* out)
// FIXME: rotational & centripetal acceleration needed
}
void Airplane::setPilotPos(float* pos)
{
int i;
for(i=0; i<3; i++) _pilotPos[i] = pos[i];
}
void Airplane::getPilotPos(float* out)
{
int i;
for(i=0; i<3; i++) out[i] = _pilotPos[i];
}
int Airplane::numGear()
{
return _gears.size();
}
Gear* Airplane::getGear(int g)
{
return ((GearRec*)_gears.get(g))->gear;
}
Hook* Airplane::getHook()
{
return _model.getHook();
}
Launchbar* Airplane::getLaunchbar()
{
return _model.getLaunchbar();
}
Rotorgear* Airplane::getRotorgear()
{
return _model.getRotorgear();
}
void Airplane::updateGearState()
{
for(int i=0; i<_gears.size(); i++) {
@ -247,51 +202,6 @@ void Airplane::addSolutionWeight(bool approach, int idx, float wgt)
_solveWeights.add(w);
}
int Airplane::numTanks()
{
return _tanks.size();
}
float Airplane::getFuel(int tank)
{
return ((Tank*)_tanks.get(tank))->fill;
}
float Airplane::setFuel(int tank, float fuel)
{
return ((Tank*)_tanks.get(tank))->fill = fuel;
}
float Airplane::getFuelDensity(int tank)
{
return ((Tank*)_tanks.get(tank))->density;
}
float Airplane::getTankCapacity(int tank)
{
return ((Tank*)_tanks.get(tank))->cap;
}
void Airplane::setWeight(float weight)
{
_emptyWeight = weight;
}
void Airplane::setWing(Wing* wing)
{
_wing = wing;
}
void Airplane::setTail(Wing* tail)
{
_tail = tail;
}
void Airplane::addVStab(Wing* vstab)
{
_vstabs.add(vstab);
}
void Airplane::addFuselage(float* front, float* back, float width,
float taper, float mid,
float cx, float cy, float cz, float idrag)
@ -330,21 +240,10 @@ void Airplane::addGear(Gear* gear)
g->gear = gear;
g->surf = 0;
_gears.add(g);
}
void Airplane::addHook(Hook* hook)
{
_model.addHook(hook);
}
void Airplane::addHitch(Hitch* hitch)
{
_model.addHitch(hitch);
}
void Airplane::addLaunchbar(Launchbar* launchbar)
{
_model.addLaunchbar(launchbar);
float pos[3];
g->gear->getPosition(pos);
if (pos[0] > _cgMaxX) _cgMaxX = pos[0];
if (pos[0] < _cgMinX) _cgMinX = pos[0];
}
void Airplane::addThruster(Thruster* thruster, float mass, float* cg)
@ -357,12 +256,14 @@ void Airplane::addThruster(Thruster* thruster, float mass, float* cg)
_thrusters.add(t);
}
/// Use ballast to redistribute mass, this is NOT added to empty weight.
void Airplane::addBallast(float* pos, float mass)
{
_model.getBody()->addMass(mass, pos);
_model.getBody()->addMass(mass, pos, true);
_ballast += mass;
}
/// Masses configurable at runtime, e.g. cargo, pax
int Airplane::addWeight(float* pos, float size)
{
WeightRec* wr = new WeightRec();
@ -377,6 +278,7 @@ int Airplane::addWeight(float* pos, float size)
return _weights.add(wr);
}
/// Change weight of a previously added mass point
void Airplane::setWeight(int handle, float mass)
{
WeightRec* wr = (WeightRec*)_weights.get(handle);
@ -398,45 +300,14 @@ void Airplane::setWeight(int handle, float mass)
void Airplane::setFuelFraction(float frac)
{
int i;
for(i=0; i<_tanks.size(); i++) {
for(int i=0; i<_tanks.size(); i++) {
Tank* t = (Tank*)_tanks.get(i);
t->fill = frac * t->cap;
_model.getBody()->setMass(t->handle, t->cap * frac);
}
}
float Airplane::getDragCoefficient()
{
return _dragFactor;
}
float Airplane::getLiftRatio()
{
return _liftRatio;
}
float Airplane::getCruiseAoA()
{
return _cruiseAoA;
}
float Airplane::getTailIncidence()
{
return _tailIncidence;
}
const char* Airplane::getFailureMsg()
{
return _failureMsg;
}
int Airplane::getSolutionIterations()
{
return _solutionIterations;
}
void Airplane::setupState(float aoa, float speed, float gla, State* s)
void Airplane::setupState(const float aoa, const float speed, const float gla, State* s)
{
float cosAoA = Math::cos(aoa);
float sinAoA = Math::sin(aoa);
@ -444,10 +315,10 @@ void Airplane::setupState(float aoa, float speed, float gla, State* s)
s->orient[3] = 0; s->orient[4] = 1; s->orient[5] = 0;
s->orient[6] = -sinAoA; s->orient[7] = 0; s->orient[8] = cosAoA;
//? what is gla? v[1]=y, v[2]=z? should sin go to v2 instead v1?
s->v[0] = speed*Math::cos(gla); s->v[1] = -speed*Math::sin(gla); s->v[2] = 0;
int i;
for(i=0; i<3; i++)
for(int i=0; i<3; i++)
s->pos[i] = s->rot[i] = s->acc[i] = s->racc[i] = 0;
// Put us 1m above the origin, or else the gravity computation in
@ -455,39 +326,59 @@ void Airplane::setupState(float aoa, float speed, float gla, State* s)
s->pos[2] = 1;
}
/**
* @brief add contact point for crash detection
* used to add wingtips and fuselage nose and tail
*
* @param pos ...
* @return void
*/
void Airplane::addContactPoint(float* pos)
{
ContactRec* c = new ContactRec;
c->gear = 0;
c->p[0] = pos[0];
c->p[1] = pos[1];
c->p[2] = pos[2];
Math::set3(pos, c->p);
_contacts.add(c);
}
float Airplane::compileWing(Wing* w)
{
// The tip of the wing is a contact point
float tip[3];
w->getTip(tip);
addContactPoint(tip);
if(w->isMirrored()) {
tip[1] *= -1;
addContactPoint(tip);
}
// Make sure it's initialized. The surfaces will pop out with
// total drag coefficients equal to their areas, which is what we
// want.
w->compile();
float wgt = 0;
int i;
for(i=0; i<w->numSurfaces(); i++) {
Surface* s = (Surface*)w->getSurface(i);
// The tip of the wing is a contact point
float tip[3];
// need compile() before getTip()!
w->getTip(tip);
addContactPoint(tip);
if(w->isMirrored()) {
tip[1] *= -1;
addContactPoint(tip);
tip[1] *= -1; //undo mirror
}
if (_wingsN != 0) {
_wingsN->getNode("tip-x", true)->setFloatValue(tip[0]);
_wingsN->getNode("tip-y", true)->setFloatValue(tip[1]);
_wingsN->getNode("tip-z", true)->setFloatValue(tip[2]);
w->getBase(tip);
_wingsN->getNode("base-x", true)->setFloatValue(tip[0]);
_wingsN->getNode("base-y", true)->setFloatValue(tip[1]);
_wingsN->getNode("base-z", true)->setFloatValue(tip[2]);
_wingsN->getNode("wing-span", true)->setFloatValue(w->getSpan());
_wingsN->getNode("wing-area", true)->setFloatValue(w->getArea());
_wingsN->getNode("aspect-ratio", true)->setFloatValue(w->getAspectRatio());
_wingsN->getNode("standard-mean-chord", true)->setFloatValue(w->getSMC());
}
float wgt = 0;
float dragSum = 0;
for(int i=0; i<w->numSurfaces(); i++) {
Surface* s = (Surface*)w->getSurface(i);
float td = s->getTotalDrag();
s->setTotalDrag(td);
int sid = s->getID();
_model.addSurface(s);
@ -495,8 +386,18 @@ float Airplane::compileWing(Wing* w)
mass = mass * Math::sqrt(mass);
float pos[3];
s->getPosition(pos);
_model.getBody()->addMass(mass, pos);
int mid = _model.getBody()->addMass(mass, pos, true);
if (_wingsN != 0) {
SGPropertyNode_ptr n = _wingsN->getNode("surfaces", true)->getChild("surface", sid, true);
n->getNode("drag", true)->setFloatValue(td);
n->getNode("mass-id", true)->setIntValue(mid);
}
wgt += mass;
dragSum += td;
}
if (_wingsN != 0) {
_wingsN->getNode("weight", true)->setFloatValue(wgt);
_wingsN->getNode("drag", true)->setFloatValue(dragSum);
}
return wgt;
}
@ -547,7 +448,7 @@ float Airplane::compileFuselage(Fuselage* f)
// _Mass_ weighting goes as surface area^(3/2)
float mass = scale*segWgt * Math::sqrt(scale*segWgt);
_model.getBody()->addMass(mass, pos);
_model.getBody()->addMass(mass, pos, true);
wgt += mass;
// Make a Surface too
@ -635,6 +536,13 @@ void Airplane::compileGear(GearRec* gr)
_surfs.add(s);
}
/**
* @brief add "fake gear" per contact point
*
*
* @return void
*/
void Airplane::compileContactPoints()
{
// Figure it will compress by 20cm
@ -648,8 +556,7 @@ void Airplane::compileContactPoints()
float spring = (1/DIST) * 9.8f * 10.0f * mass;
float damp = 2 * Math::sqrt(spring * mass);
int i;
for(i=0; i<_contacts.size(); i++) {
for(int i=0; i<_contacts.size(); i++) {
ContactRec* c = (ContactRec*)_contacts.get(i);
Gear* g = new Gear();
@ -674,6 +581,8 @@ void Airplane::compile()
{
RigidBody* body = _model.getBody();
int firstMass = body->numMasses();
SGPropertyNode_ptr baseN = fgGetNode("/fdm/yasim/model/wings", true);
SGPropertyNode_ptr n;
// Generate the point masses for the plane. Just use unitless
// numbers for a first pass, then go back through and rescale to
@ -682,13 +591,21 @@ void Airplane::compile()
// The Wing objects
if (_wing)
{
if (baseN != 0) _wingsN = baseN->getChild("wing", 0, true);
aeroWgt += compileWing(_wing);
}
if (_tail)
{
if (baseN != 0) _wingsN = baseN->getChild("tail", 0, true);
aeroWgt += compileWing(_tail);
}
int i;
for(i=0; i<_vstabs.size(); i++)
{
if (baseN != 0) _wingsN = baseN->getChild("stab", i, true);
aeroWgt += compileWing((Wing*)_vstabs.get(i));
}
// The fuselage(s)
for(i=0; i<_fuselages.size(); i++)
@ -707,7 +624,7 @@ void Airplane::compile()
// Add the thruster masses
for(i=0; i<_thrusters.size(); i++) {
ThrustRec* t = (ThrustRec*)_thrusters.get(i);
body->addMass(t->mass, t->cg);
body->addMass(t->mass, t->cg, true);
}
// Add the tanks, empty for now.
@ -733,10 +650,23 @@ void Airplane::compile()
}
// Ground effect
// If a double tapered wing is modelled with wing and mstab, wing must
// be outboard to get correct wingspan.
if(_wing) {
float gepos[3];
float gespan = 0;
gespan = _wing->getGroundEffect(gepos);
gespan = _wing->getSpan();
_wing->getBase(gepos);
if(!isVersionOrNewer( Version::YASIM_VERSION_2017_2 )) {
//old code
//float span = _length * Math::cos(_sweep) * Math::cos(_dihedral);
//span = 2*(span + Math::abs(_base[2]));
gespan -= 2*gepos[1]; // cut away base (y-distance)
gespan += 2*Math::abs(gepos[2]); // add (wrong) z-distance
}
if (baseN != 0)
baseN->getChild("wing", 0)->getNode("gnd-eff-span", true)->setFloatValue(gespan);
// where does the hard coded factor 0.15 come from?
_model.setGroundEffect(gepos, gespan, 0.15f);
}
@ -822,11 +752,11 @@ void Airplane::initEngines()
void Airplane::stabilizeThrust()
{
int i;
for(i=0; i<_thrusters.size(); i++)
for(int i=0; i<_thrusters.size(); i++)
_model.getThruster(i)->stabilize();
}
/// Setup weights for cruise or approach during solve.
void Airplane::setupWeights(bool isApproach)
{
int i;
@ -839,6 +769,18 @@ void Airplane::setupWeights(bool isApproach)
}
}
/// load values for controls as defined in cruise configuration
void Airplane::loadCruiseControls()
{
_controls.reset();
for(int i=0; i<_cruiseControls.size(); i++) {
Control* c = (Control*)_cruiseControls.get(i);
_controls.setInput(c->control, c->val);
}
_controls.applyControls();
}
/// Helper for solve()
void Airplane::runCruise()
{
setupState(_cruiseAoA, _cruiseSpeed,_cruiseGlideAngle, &_cruiseState);
@ -847,13 +789,7 @@ void Airplane::runCruise()
Atmosphere::calcStdDensity(_cruiseP, _cruiseT));
// The control configuration
_controls.reset();
int i;
for(i=0; i<_cruiseControls.size(); i++) {
Control* c = (Control*)_cruiseControls.get(i);
_controls.setInput(c->control, c->val);
}
_controls.applyControls(1000000); // Huge dt value
loadCruiseControls();
// The local wind
float wind[3];
@ -865,7 +801,7 @@ void Airplane::runCruise()
// Set up the thruster parameters and iterate until the thrust
// stabilizes.
for(i=0; i<_thrusters.size(); i++) {
for(int i=0; i<_thrusters.size(); i++) {
Thruster* t = ((ThrustRec*)_thrusters.get(i))->thruster;
t->setWind(wind);
t->setAir(_cruiseP, _cruiseT,
@ -882,6 +818,18 @@ void Airplane::runCruise()
_model.calcForces(&_cruiseState);
}
/// load values for controls as defined in approach configuration
void Airplane::loadApproachControls()
{
_controls.reset();
for(int i=0; i<_approachControls.size(); i++) {
Control* c = (Control*)_approachControls.get(i);
_controls.setInput(c->control, c->val);
}
_controls.applyControls();
}
/// Helper for solve()
void Airplane::runApproach()
{
setupState(_approachAoA, _approachSpeed,_approachGlideAngle, &_approachState);
@ -890,13 +838,7 @@ void Airplane::runApproach()
Atmosphere::calcStdDensity(_approachP, _approachT));
// The control configuration
_controls.reset();
int i;
for(i=0; i<_approachControls.size(); i++) {
Control* c = (Control*)_approachControls.get(i);
_controls.setInput(c->control, c->val);
}
_controls.applyControls(1000000);
loadApproachControls();
// The local wind
float wind[3];
@ -909,7 +851,7 @@ void Airplane::runApproach()
// Run the thrusters until they get to a stable setting. FIXME:
// this is lots of wasted work.
for(i=0; i<_thrusters.size(); i++) {
for(int i=0; i<_thrusters.size(); i++) {
Thruster* t = ((ThrustRec*)_thrusters.get(i))->thruster;
t->setWind(wind);
t->setAir(_approachP, _approachT,
@ -926,6 +868,7 @@ void Airplane::runApproach()
_model.calcForces(&_approachState);
}
/// Used only in Airplane::solve() and solveHelicopter(), not at runtime
void Airplane::applyDragFactor(float factor)
{
float applied = Math::pow(factor, SOLVE_TWEAK);
@ -971,6 +914,7 @@ void Airplane::applyDragFactor(float factor)
}
}
/// Used only in Airplane::solve() and solveHelicopter(), not at runtime
void Airplane::applyLiftRatio(float factor)
{
float applied = Math::pow(factor, SOLVE_TWEAK);
@ -986,13 +930,7 @@ void Airplane::applyLiftRatio(float factor)
}
}
float Airplane::clamp(float val, float min, float max)
{
if(val < min) return min;
if(val > max) return max;
return val;
}
/// Helper for solve()
float Airplane::normFactor(float f)
{
if(f < 0) f = -f;
@ -1102,8 +1040,8 @@ void Airplane::solve()
_cruiseAoA += SOLVE_TWEAK*aoaDelta;
_tailIncidence += SOLVE_TWEAK*tailDelta;
_cruiseAoA = clamp(_cruiseAoA, -0.175f, 0.175f);
_tailIncidence = clamp(_tailIncidence, -0.175f, 0.175f);
_cruiseAoA = Math::clamp(_cruiseAoA, -0.175f, 0.175f);
_tailIncidence = Math::clamp(_tailIncidence, -0.175f, 0.175f);
if(abs(xforce/_cruiseWeight) < STHRESH*0.0001 &&
abs(alift/_approachWeight) < STHRESH*0.0001 &&

View file

@ -7,6 +7,7 @@
#include "Rotor.hpp"
#include "Vector.hpp"
#include "Version.hpp"
#include <simgear/props/props.hxx>
namespace yasim {
@ -16,7 +17,9 @@ class Launchbar;
class Thruster;
class Hitch;
/// The Airplane class ties together the different components
class Airplane : public Version {
SGPropertyNode_ptr _wingsN;
public:
Airplane();
~Airplane();
@ -24,30 +27,30 @@ public:
void iterate(float dt);
void calcFuelWeights();
ControlMap* getControlMap();
Model* getModel();
ControlMap* getControlMap() { return &_controls; }
Model* getModel() { return &_model; }
void setPilotPos(float* pos);
void getPilotPos(float* out);
void setPilotPos(float* pos) { Math::set3(pos, _pilotPos); }
void getPilotPos(float* out) { Math::set3(_pilotPos, out); }
void getPilotAccel(float* out);
void setWeight(float weight);
void setEmptyWeight(float weight) { _emptyWeight = weight; }
void setWing(Wing* wing);
void setTail(Wing* tail);
void addVStab(Wing* vstab);
void setWing(Wing* wing) { _wing = wing; }
void setTail(Wing* tail) { _tail = tail; }
void addVStab(Wing* vstab) { _vstabs.add(vstab); }
void addFuselage(float* front, float* back, float width,
float taper=1, float mid=0.5,
float cx=1, float cy=1, float cz=1, float idrag=1);
int addTank(float* pos, float cap, float fuelDensity);
void addGear(Gear* g);
void addHook(Hook* h);
void addLaunchbar(Launchbar* l);
void addHook(Hook* h) { _model.addHook(h); }
void addLaunchbar(Launchbar* l) { _model.addLaunchbar(l); }
void addThruster(Thruster* t, float mass, float* cg);
void addBallast(float* pos, float mass);
void addHitch(Hitch* h);
void addHitch(Hitch* h) { _model.addHitch(h); }
int addWeight(float* pos, float size);
void setWeight(int handle, float mass);
@ -61,39 +64,47 @@ public:
void addSolutionWeight(bool approach, int idx, float wgt);
int numGear();
Gear* getGear(int g);
Hook* getHook();
int numGear() { return _gears.size(); }
Gear* getGear(int g) { return ((GearRec*)_gears.get(g))->gear; }
Hook* getHook() { return _model.getHook(); }
int numHitches() { return _hitches.size(); }
Hitch* getHitch(int h);
Rotorgear* getRotorgear();
Launchbar* getLaunchbar();
Rotorgear* getRotorgear() { return _model.getRotorgear(); }
Launchbar* getLaunchbar() { return _model.getLaunchbar(); }
int numThrusters() { return _thrusters.size(); }
Thruster* getThruster(int n) {
return ((ThrustRec*)_thrusters.get(n))->thruster; }
int numTanks();
int numTanks() { return _tanks.size(); }
void setFuelFraction(float frac); // 0-1, total amount of fuel
float getFuel(int tank); // in kg!
float setFuel(int tank, float fuel); // in kg!
float getFuelDensity(int tank); // kg/m^3
float getTankCapacity(int tank);
// get fuel in kg
float getFuel(int tank) { return ((Tank*)_tanks.get(tank))->fill; }
// set fuel in kg
float setFuel(int tank, float fuel) { return ((Tank*)_tanks.get(tank))->fill = fuel; }
// get fuel density in kg/m^3
float getFuelDensity(int tank) { return ((Tank*)_tanks.get(tank))->density; }
float getTankCapacity(int tank) { return ((Tank*)_tanks.get(tank))->cap; }
void compile(); // generate point masses & such, then solve
void initEngines();
void stabilizeThrust();
// Solution output values
int getSolutionIterations();
float getDragCoefficient();
float getLiftRatio();
float getCruiseAoA();
float getTailIncidence();
int getSolutionIterations() { return _solutionIterations; }
float getDragCoefficient() { return _dragFactor; }
float getLiftRatio() { return _liftRatio; }
float getCruiseAoA() { return _cruiseAoA; }
float getTailIncidence() { return _tailIncidence; }
float getApproachElevator() { return _approachElevator.val; }
const char* getFailureMsg();
const char* getFailureMsg() { return _failureMsg; }
static void setupState(float aoa, float speed, float gla, State* s); // utility
static void setupState(const float aoa, const float speed, const float gla, yasim::State* s); // utility
void loadApproachControls();
void loadCruiseControls();
float getCGMinX() { return _cgMinX; }
float getCGMaxX() { return _cgMaxX; }
private:
struct Tank { float pos[3]; float cap; float fill;
@ -119,7 +130,6 @@ private:
void compileGear(GearRec* gr);
void applyDragFactor(float factor);
void applyLiftRatio(float factor);
float clamp(float val, float min, float max);
void addContactPoint(float* pos);
void compileContactPoints();
float normFactor(float f);
@ -175,6 +185,10 @@ private:
float _tailIncidence;
Control _approachElevator;
const char* _failureMsg;
// hard limits for cg from gear positions
float _cgMaxX;
float _cgMinX;
};
}; // namespace yasim

View file

@ -32,14 +32,18 @@ ControlMap::~ControlMap()
for(i=0; i<_outputs.size(); i++)
delete (OutRec*)_outputs.get(i);
for(i=0; i<_properties.size(); i++) {
PropHandle* p = (PropHandle*)_properties.get(i);
delete[] p->name;
delete p;
}
}
int ControlMap::newInput()
{
Vector* v = new Vector();
return _inputs.add(v);
}
/**
input : index to _inputs
type: identifier (see enum OutputType)
*/
void ControlMap::addMapping(int input, int type, void* object, int options,
float src0, float src1, float dst0, float dst1)
{
@ -55,6 +59,10 @@ void ControlMap::addMapping(int input, int type, void* object, int options,
m->dst1 = dst1;
}
/**
input : index to _inputs
type: identifier (see enum OutputType)
*/
void ControlMap::addMapping(int input, int type, void* object, int options)
{
// See if the output object already exists
@ -210,12 +218,12 @@ void ControlMap::applyControls(float dt)
case LEXTEND: ((Launchbar*)obj)->setExtension(lval); break;
case LACCEL: ((Launchbar*)obj)->setAcceleration(lval); break;
case CASTERING:((Gear*)obj)->setCastering(lval != 0); break;
case SLAT: ((Wing*)obj)->setSlat(lval); break;
case FLAP0: ((Wing*)obj)->setFlap0(lval, rval); break;
case SLAT: ((Wing*)obj)->setSlatPos(lval); break;
case FLAP0: ((Wing*)obj)->setFlap0Pos(lval, rval); break;
case FLAP0EFFECTIVENESS: ((Wing*)obj)->setFlap0Effectiveness(lval); break;
case FLAP1: ((Wing*)obj)->setFlap1(lval, rval); break;
case FLAP1: ((Wing*)obj)->setFlap1Pos(lval, rval); break;
case FLAP1EFFECTIVENESS: ((Wing*)obj)->setFlap1Effectiveness(lval); break;
case SPOILER: ((Wing*)obj)->setSpoiler(lval, rval); break;
case SPOILER: ((Wing*)obj)->setSpoilerPos(lval, rval); break;
case COLLECTIVE: ((Rotor*)obj)->setCollective(lval); break;
case CYCLICAIL: ((Rotor*)obj)->setCyclicail(lval,rval); break;
case CYCLICELE: ((Rotor*)obj)->setCyclicele(lval,rval); break;
@ -278,4 +286,45 @@ float ControlMap::rangeMax(int type)
}
}
/// duplicate null-terminated string
char* ControlMap::dup(const char* s)
{
int len=0;
while(s[len++]);
char* s2 = new char[len+1];
char* p = s2;
while((*p++ = *s++));
s2[len] = 0;
return s2;
}
/// compare null-terminated strings
bool ControlMap::eq(const char* a, const char* b)
{
while(*a && *b && *a == *b) { a++; b++; }
// equal if both a and b points to null chars
return !(*a || *b);
}
/// register property name, return ID (int)
int ControlMap::propertyHandle(const char* name)
{
for(int i=0; i < _properties.size(); i++) {
PropHandle* p = (PropHandle*)_properties.get(i);
if(eq(p->name, name))
return p->handle;
}
// create new
PropHandle* p = new PropHandle();
p->name = dup(name);
fgGetNode(p->name, true);
Vector* v = new Vector();
p->handle = _inputs.add(v);
_properties.add(p);
return p->handle;
}
} // namespace yasim

View file

@ -1,6 +1,7 @@
#ifndef _CONTROL_MAP_HPP
#define _CONTROL_MAP_HPP
#include <simgear/props/props.hxx>
#include "Vector.hpp"
namespace yasim {
@ -26,9 +27,7 @@ public:
OPT_INVERT = 0x02,
OPT_SQUARE = 0x04 };
// Returns a new, not-yet-used "input handle" for addMapping and
// setInput. This typically corresponds to one user axis.
int newInput();
struct PropHandle { char* name; int handle; };
// Adds a mapping to between input handle and a particular setting
// on an output object. The value of output MUST match the type
@ -45,12 +44,13 @@ public:
// setInput() invokations.
void reset();
// Sets the specified input (as returned by newInput) to the
// Sets the specified input (as returned by propertyHandle) to the
// specified value.
void setInput(int input, float value);
void setInput(int propHandle, float value);
// Calculates and applies the settings received since the last reset().
void applyControls(float dt);
/// Calculates and applies the settings received since the last reset().
/// dt defaults to a large value used at solve time.
void applyControls(float dt=1e6);
// Returns the input/output range appropriate for the given
// control. Ailerons go from -1 to 1, while throttles are never
@ -72,6 +72,15 @@ public:
float getOutput(int handle);
float getOutputR(int handle);
// register property name, return handle
int propertyHandle(const char* name);
int numProperties() { return _properties.size(); }
PropHandle* getProperty(const int i) { return ((PropHandle*)_properties.get(i)); }
// helper
char* dup(const char* s);
bool eq(const char* a, const char* b);
private:
struct OutRec { int type; void* object; Vector maps;
float oldL, oldR, time; };
@ -84,6 +93,8 @@ private:
// An unordered list of output settings.
Vector _outputs;
// control properties
Vector _properties;
};
}; // namespace yasim

View file

@ -21,6 +21,7 @@
#include "Rotor.hpp"
#include "Rotorpart.hpp"
#include "Hitch.hpp"
#include "Surface.hpp"
#include "FGFDM.hpp"
@ -28,6 +29,7 @@ namespace yasim {
// Some conversion factors
static const float KTS2MPS = 0.514444444444;
static const float KMH2MPS = 1/3.6;
static const float FT2M = 0.3048;
static const float DEG2RAD = 0.0174532925199;
static const float RPM2RAD = 0.10471975512;
@ -59,7 +61,7 @@ FGFDM::FGFDM()
// Map /controls/flight/elevator to the approach elevator control. This
// should probably be settable, but there are very few aircraft
// who trim their approaches using things other than elevator.
_airplane.setElevatorControl(parseAxis("/controls/flight/elevator-trim"));
_airplane.setElevatorControl(_airplane.getControlMap()->propertyHandle("/controls/flight/elevator-trim"));
// FIXME: read seed from somewhere?
int seed = 0;
@ -68,12 +70,6 @@ FGFDM::FGFDM()
FGFDM::~FGFDM()
{
for(int i=0; i<_axes.size(); i++) {
AxisRec* a = (AxisRec*)_axes.get(i);
delete[] a->name;
delete a;
}
for(int i=0; i<_thrusters.size(); i++) {
EngRec* er = (EngRec*)_thrusters.get(i);
delete[] er->prefix;
@ -124,18 +120,38 @@ Airplane* FGFDM::getAirplane()
void FGFDM::init()
{
//reset id generator, needed on simulator reset/re-init
Surface::resetIDgen();
_turb_magnitude_norm = fgGetNode("/environment/turbulence/magnitude-norm", true);
_turb_rate_hz = fgGetNode("/environment/turbulence/rate-hz", true);
SGPropertyNode_ptr yasimNode = fgGetNode("/fdm/yasim", true);
_gross_weight_lbs = yasimNode->getNode("gross-weight-lbs", true);
_yasimN = fgGetNode("/fdm/yasim", true);
_gross_weight_lbs = _yasimN->getNode("gross-weight-lbs", true);
// alias to older name
fgGetNode("/yasim/gross-weight-lbs", true)->alias(_gross_weight_lbs);
_cg_x = yasimNode->getNode("cg-x-m", true);
_cg_y = yasimNode->getNode("cg-y-m", true);
_cg_z = yasimNode->getNode("cg-z-m", true);
// write some compile time information to property tree
_yasimN->getNode("config-version",true)->setIntValue(_airplane.getVersion());
_yasimN->getNode("model/cg-x-min",true)->setFloatValue(_airplane.getCGMinX());
_yasimN->getNode("model/cg-x-max",true)->setFloatValue(_airplane.getCGMaxX());
// prepare nodes for write at runtime
_cg_x = _yasimN->getNode("cg-x-m", true);
_cg_y = _yasimN->getNode("cg-y-m", true);
_cg_z = _yasimN->getNode("cg-z-m", true);
_vxN = _yasimN->getNode("velocities/v-x", true);
_vyN = _yasimN->getNode("velocities/v-y", true);
_vzN = _yasimN->getNode("velocities/v-z", true);
_vrxN = _yasimN->getNode("velocities/vrot-x", true);
_vryN = _yasimN->getNode("velocities/vrot-y", true);
_vrzN = _yasimN->getNode("velocities/vrot-z", true);
_axN = _yasimN->getNode("accelerations/a-x", true);
_ayN = _yasimN->getNode("accelerations/a-y", true);
_azN = _yasimN->getNode("accelerations/a-z", true);
_arxN = _yasimN->getNode("accelerations/arot-x", true);
_aryN = _yasimN->getNode("accelerations/arot-y", true);
_arzN = _yasimN->getNode("accelerations/arot-z", true);
// Allows the user to start with something other than full fuel
_airplane.setFuelFraction(fgGetFloat("/sim/fuel-fraction", 1));
@ -225,34 +241,64 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
XMLAttributes* a = (XMLAttributes*)&atts;
float v[3];
char buf[64];
float f = 0;
if(eq(name, "airplane")) {
_airplane.setWeight(attrf(a, "mass") * LBS2KG);
if(a->hasAttribute("mass")) { f = attrf(a, "mass") * LBS2KG; }
else if (a->hasAttribute("mass-lbs")) { f = attrf(a, "mass-lbs") * LBS2KG; }
else if (a->hasAttribute("mass-kg")) { f = attrf(a, "mass-kg"); }
else {
SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, airplane needs one of {mass-lbs, mass-kg}");
exit(1);
}
_airplane.setEmptyWeight(f);
if(a->hasAttribute("version")) {
_airplane.setVersion( a->getValue("version") );
}
#if defined(ENABLE_DEV_WARNINGS)
if( !_airplane.isVersionOrNewer( Version::YASIM_VERSION_CURRENT ) ) {
SG_LOG(SG_FLIGHT,SG_ALERT, "This aircraft does not use the latest yasim configuration version.");
SG_LOG(SG_FLIGHT, SG_DEV_ALERT, "This aircraft does not use the latest yasim configuration version.");
}
#endif
} else if(eq(name, "approach")) {
float spd = attrf(a, "speed") * KTS2MPS;
float alt = attrf(a, "alt", 0) * FT2M;
float spd, alt = 0;
if (a->hasAttribute("speed")) { spd = attrf(a, "speed") * KTS2MPS; }
else if (a->hasAttribute("speed-kt")) { spd = attrf(a, "speed-kt") * KTS2MPS; }
else if (a->hasAttribute("speed-kmh")) { spd = attrf(a, "speed-kmh") * KMH2MPS; }
else {
SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, approach needs one of {speed-kt, speed-kmh}");
exit(1);
}
if (a->hasAttribute("alt")) { alt = attrf(a, "alt") * FT2M; }
else if (a->hasAttribute("alt-ft")) { alt = attrf(a, "alt-ft") * FT2M; }
else if (a->hasAttribute("alt-m")) { alt = attrf(a, "alt-m"); }
float aoa = attrf(a, "aoa", 0) * DEG2RAD;
float gla = attrf(a, "glide-angle", 0) * DEG2RAD;
_airplane.setApproach(spd, alt, aoa, attrf(a, "fuel", 0.2),gla);
_airplane.setApproach(spd, alt, aoa, attrf(a, "fuel", 0.2), gla);
_cruiseCurr = false;
} else if(eq(name, "cruise")) {
float spd = attrf(a, "speed") * KTS2MPS;
float alt = attrf(a, "alt") * FT2M;
float spd, alt = 0;
if (a->hasAttribute("speed")) { spd = attrf(a, "speed") * KTS2MPS; }
else if (a->hasAttribute("speed-kt")) { spd = attrf(a, "speed-kt") * KTS2MPS; }
else if (a->hasAttribute("speed-kmh")) { spd = attrf(a, "speed-kmh") * KMH2MPS; }
else {
SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, approach needs one of {speed-kt, speed-kmh}");
exit(1);
}
if (a->hasAttribute("alt")) { alt = attrf(a, "alt") * FT2M; }
else if (a->hasAttribute("alt-ft")) { alt = attrf(a, "alt-ft") * FT2M; }
else if (a->hasAttribute("alt-m")) { alt = attrf(a, "alt-m"); }
float gla = attrf(a, "glide-angle", 0) * DEG2RAD;
_airplane.setCruise(spd, alt, attrf(a, "fuel", 0.5),gla);
_cruiseCurr = true;
} else if(eq(name, "solve-weight")) {
int idx = attri(a, "idx");
float wgt = attrf(a, "weight") * LBS2KG;
_airplane.addSolutionWeight(!_cruiseCurr, idx, wgt);
if(a->hasAttribute("weight")) { f = attrf(a, "weight") * LBS2KG; }
else if(a->hasAttribute("weight-lbs")) { f = attrf(a, "weight-lbs") * LBS2KG; }
else if(a->hasAttribute("weight-kg")) { f = attrf(a, "weight-kg"); }
else {
SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, solve-weight needs one of {weight-lbs, weight-kg}");
exit(1);
}
_airplane.addSolutionWeight(!_cruiseCurr, idx, f);
} else if(eq(name, "cockpit")) {
v[0] = attrf(a, "x");
v[1] = attrf(a, "y");
@ -302,7 +348,14 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
v[0] = attrf(a, "x");
v[1] = attrf(a, "y");
v[2] = attrf(a, "z");
float mass = attrf(a, "mass") * LBS2KG;
float mass;
if(a->hasAttribute("mass")) { mass = attrf(a, "mass") * LBS2KG; }
else if(a->hasAttribute("mass-lbs")) { mass = attrf(a, "mass-lbs") * LBS2KG; }
else if(a->hasAttribute("mass-kg")) { mass = attrf(a, "mass-kg"); }
else {
SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, jet needs one of {mass-lbs, mass-kg}");
exit(1);
}
j->setMaxThrust(attrf(a, "thrust") * LBS2N,
attrf(a, "afterburner", 0) * LBS2N);
j->setVectorAngle(attrf(a, "rotate", 0) * DEG2RAD);
@ -470,12 +523,27 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
float density = 6.0; // gasoline, in lbs/gal
if(a->hasAttribute("jet")) density = 6.72;
density *= LBS2KG*CM2GALS;
_airplane.addTank(v, attrf(a, "capacity") * LBS2KG, density);
float capacity = 0;
if(a->hasAttribute("capacity")) { capacity = attrf(a, "capacity") * LBS2KG; }
else if(a->hasAttribute("capacity-lbs")) { capacity = attrf(a, "capacity-lbs") * LBS2KG; }
else if(a->hasAttribute("capacity-kg")) { capacity = attrf(a, "capacity-kg"); }
else {
SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, tank needs one of {capacity-lbs, capacity-kg}");
exit(1);
}
_airplane.addTank(v, capacity, density);
} else if(eq(name, "ballast")) {
v[0] = attrf(a, "x");
v[1] = attrf(a, "y");
v[2] = attrf(a, "z");
_airplane.addBallast(v, attrf(a, "mass") * LBS2KG);
if(a->hasAttribute("mass")) { f = attrf(a, "mass") * LBS2KG; }
else if (a->hasAttribute("mass-lbs")) { f = attrf(a, "mass-lbs") * LBS2KG; }
else if (a->hasAttribute("mass-kg")) { f = attrf(a, "mass-kg"); }
else {
SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, airplane needs one of {mass-lbs, mass-kg}");
exit(1);
}
_airplane.addBallast(v, f);
} else if(eq(name, "weight")) {
parseWeight(a);
} else if(eq(name, "stall")) {
@ -484,16 +552,16 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
w->setStallWidth(attrf(a, "width", 2) * DEG2RAD);
w->setStallPeak(attrf(a, "peak", 1.5));
} else if(eq(name, "flap0")) {
((Wing*)_currObj)->setFlap0(attrf(a, "start"), attrf(a, "end"),
((Wing*)_currObj)->setFlap0Params(attrf(a, "start"), attrf(a, "end"),
attrf(a, "lift"), attrf(a, "drag"));
} else if(eq(name, "flap1")) {
((Wing*)_currObj)->setFlap1(attrf(a, "start"), attrf(a, "end"),
((Wing*)_currObj)->setFlap1Params(attrf(a, "start"), attrf(a, "end"),
attrf(a, "lift"), attrf(a, "drag"));
} else if(eq(name, "slat")) {
((Wing*)_currObj)->setSlat(attrf(a, "start"), attrf(a, "end"),
((Wing*)_currObj)->setSlatParams(attrf(a, "start"), attrf(a, "end"),
attrf(a, "aoa"), attrf(a, "drag"));
} else if(eq(name, "spoiler")) {
((Wing*)_currObj)->setSpoiler(attrf(a, "start"), attrf(a, "end"),
((Wing*)_currObj)->setSpoilerParams(attrf(a, "start"), attrf(a, "end"),
attrf(a, "lift"), attrf(a, "drag"));
/* } else if(eq(name, "collective")) {
((Rotor*)_currObj)->setcollective(attrf(a, "min"), attrf(a, "max"));
@ -514,21 +582,20 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
// A cruise or approach control setting
const char* axis = a->getValue("axis");
float value = attrf(a, "value", 0);
ControlMap* cm = _airplane.getControlMap();
if(_cruiseCurr)
_airplane.addCruiseControl(parseAxis(axis), value);
_airplane.addCruiseControl(cm->propertyHandle(axis), value);
else
_airplane.addApproachControl(parseAxis(axis), value);
_airplane.addApproachControl(cm->propertyHandle(axis), value);
} else if(eq(name, "control-input")) {
ControlMap* cm = _airplane.getControlMap();
// A mapping of input property to a control
int axis = parseAxis(a->getValue("axis"));
int axis = cm->propertyHandle(a->getValue("axis"));
int control = parseOutput(a->getValue("control"));
int opt = 0;
opt |= a->hasAttribute("split") ? ControlMap::OPT_SPLIT : 0;
opt |= a->hasAttribute("invert") ? ControlMap::OPT_INVERT : 0;
opt |= a->hasAttribute("square") ? ControlMap::OPT_SQUARE : 0;
ControlMap* cm = _airplane.getControlMap();
if(a->hasAttribute("src0")) {
cm->addMapping(axis, control, _currObj, opt,
attrf(a, "src0"), attrf(a, "src1"),
@ -577,10 +644,10 @@ void FGFDM::getExternalInput(float dt)
ControlMap* cm = _airplane.getControlMap();
cm->reset();
for(int i=0; i<_axes.size(); i++) {
AxisRec* a = (AxisRec*)_axes.get(i);
float val = fgGetFloat(a->name, 0);
cm->setInput(a->handle, val);
for(int i=0; i < cm->numProperties(); i++) {
ControlMap::PropHandle *p = cm->getProperty(i);
float val = fgGetFloat(p->name, 0);
cm->setInput(p->handle, val);
}
cm->applyControls(dt);
@ -625,6 +692,26 @@ void FGFDM::setOutputProperties(float dt)
_cg_y->setFloatValue(cg[1]);
_cg_z->setFloatValue(cg[2]);
State* s = _airplane.getModel()->getState();
float v[3], acc[3], rot[3], racc[3];
Math::vmul33(s->orient, s->v, v);
Math::vmul33(s->orient, s->acc, acc);
Math::vmul33(s->orient, s->rot, rot);
Math::vmul33(s->orient, s->racc, racc);
_vxN->setFloatValue(v[0]);
_vyN->setFloatValue(v[1]);
_vzN->setFloatValue(v[2]);
_vrxN->setFloatValue(rot[0]);
_vryN->setFloatValue(rot[1]);
_vrzN->setFloatValue(rot[2]);
_axN->setFloatValue(acc[0]);
_ayN->setFloatValue(acc[1]);
_azN->setFloatValue(acc[2]);
_arxN->setFloatValue(racc[0]);
_aryN->setFloatValue(racc[1]);
_arzN->setFloatValue(racc[2]);
ControlMap* cm = _airplane.getControlMap();
for(int i=0; i<_controlProps.size(); i++) {
PropOut* p = (PropOut*)_controlProps.get(i);
@ -745,7 +832,12 @@ Wing* FGFDM::parseWing(XMLAttributes* a, const char* type, Version * version)
w->setSweep(attrf(a, "sweep", 0) * DEG2RAD);
w->setTaper(attrf(a, "taper", 1));
w->setDihedral(attrf(a, "dihedral", defDihed) * DEG2RAD);
w->setCamber(attrf(a, "camber", 0));
float camber = attrf(a, "camber", 0);
if (!version->isVersionOrNewer(Version::YASIM_VERSION_2017_2) && (camber == 0)) {
SG_LOG(SG_FLIGHT, SG_DEV_WARN, "YASIM warning: versions before 2017.2 are buggy for wings with camber=0");
}
w->setCamber(camber);
// These come in with positive indicating positive AoA, but the
// internals expect a rotation about the left-pointing Y axis, so
@ -1007,26 +1099,7 @@ void FGFDM::parsePropeller(XMLAttributes* a)
_currObj = thruster;
}
// Turns a string axis name into an integer for use by the
// ControlMap. Creates a new axis if this one hasn't been defined
// yet.
int FGFDM::parseAxis(const char* name)
{
for(int i=0; i<_axes.size(); i++) {
AxisRec* a = (AxisRec*)_axes.get(i);
if(eq(a->name, name))
return a->handle;
}
// Not there, make a new one.
AxisRec* a = new AxisRec();
a->name = dup(name);
fgGetNode( a->name, true ); // make sure the property name exists
a->handle = _airplane.getControlMap()->newInput();
_axes.add(a);
return a->handle;
}
/// map identifier (string) to int (enum in ControlMap)
int FGFDM::parseOutput(const char* name)
{
if(eq(name, "THROTTLE")) return ControlMap::THROTTLE;

View file

@ -31,7 +31,6 @@ public:
float getVehicleRadius(void) const { return _vehicle_radius; }
private:
struct AxisRec { char* name; int handle; };
struct EngRec { char* prefix; Thruster* eng; };
struct WeightRec { char* prop; float size; int handle; };
struct PropOut { SGPropertyNode* prop; int handle, type; bool left;
@ -41,7 +40,6 @@ private:
Rotor* parseRotor(XMLAttributes* a, const char* name);
Wing* parseWing(XMLAttributes* a, const char* name, Version * version);
int parseAxis(const char* name);
int parseOutput(const char* name);
void parseWeight(XMLAttributes* a);
void parseTurbineEngine(XMLAttributes* a);
@ -64,10 +62,6 @@ private:
// Aerodynamic turbulence model
Turbulence* _turb;
// The list of "axes" that we expect to find as input. These are
// typically property names.
Vector _axes;
// Settable weights
Vector _weights;
@ -107,9 +101,23 @@ private:
SGPropertyNode_ptr _cg_x;
SGPropertyNode_ptr _cg_y;
SGPropertyNode_ptr _cg_z;
SGPropertyNode_ptr _yasimN;
std::vector<SGPropertyNode_ptr> _tank_level_lbs;
std::vector<ThrusterProps> _thrust_props;
std::vector<FuelProps> _fuel_props;
SGPropertyNode_ptr _vxN;
SGPropertyNode_ptr _vyN;
SGPropertyNode_ptr _vzN;
SGPropertyNode_ptr _vrxN;
SGPropertyNode_ptr _vryN;
SGPropertyNode_ptr _vrzN;
SGPropertyNode_ptr _axN;
SGPropertyNode_ptr _ayN;
SGPropertyNode_ptr _azN;
SGPropertyNode_ptr _arxN;
SGPropertyNode_ptr _aryN;
SGPropertyNode_ptr _arzN;
};
}; // namespace yasim

View file

@ -53,98 +53,6 @@ Gear::Gear()
_global_ground[3] = -1e3;
}
void Gear::setPosition(float* position)
{
int i;
for(i=0; i<3; i++) _pos[i] = position[i];
}
void Gear::setCompression(float* compression)
{
int i;
for(i=0; i<3; i++) _cmpr[i] = compression[i];
}
void Gear::setSpring(float spring)
{
_spring = spring;
}
void Gear::setDamping(float damping)
{
_damp = damping;
}
void Gear::setStaticFriction(float sfric)
{
_sfric = sfric;
}
void Gear::setDynamicFriction(float dfric)
{
_dfric = dfric;
}
void Gear::setBrake(float brake)
{
_brake = Math::clamp(brake, 0, 1);
}
void Gear::setRotation(float rotation)
{
_rot = rotation;
}
void Gear::setExtension(float extension)
{
_extension = Math::clamp(extension, 0, 1);
}
void Gear::setCastering(bool c)
{
_castering = c;
}
void Gear::setContactPoint(bool c)
{
_isContactPoint=c;
}
void Gear::setOnWater(bool c)
{
_onWater = c;
}
void Gear::setOnSolid(bool c)
{
_onSolid = c;
}
void Gear::setIgnoreWhileSolving(bool c)
{
_ignoreWhileSolving = c;
}
void Gear::setSpringFactorNotPlaning(float f)
{
_spring_factor_not_planing = f;
}
void Gear::setSpeedPlaning(float s)
{
_speed_planing = s;
}
void Gear::setReduceFrictionByExtension(float s)
{
_reduceFrictionByExtension = s;
}
void Gear::setInitialLoad(float l)
{
_initialLoad = l;
}
void Gear::setGlobalGround(double *global_ground, float* global_vel,
double globalX, double globalY,
const simgear::BVHMaterial *material)
@ -183,57 +91,9 @@ void Gear::setGlobalGround(double *global_ground, float* global_vel,
}
void Gear::getPosition(float* out)
{
int i;
for(i=0; i<3; i++) out[i] = _pos[i];
}
void Gear::getCompression(float* out)
{
int i;
for(i=0; i<3; i++) out[i] = _cmpr[i];
}
void Gear::getGlobalGround(double* global_ground)
{
int i;
for(i=0; i<4; i++) global_ground[i] = _global_ground[i];
}
float Gear::getSpring()
{
return _spring;
}
float Gear::getDamping()
{
return _damp;
}
float Gear::getStaticFriction()
{
return _sfric;
}
float Gear::getDynamicFriction()
{
return _dfric;
}
float Gear::getBrake()
{
return _brake;
}
float Gear::getRotation()
{
return _rot;
}
float Gear::getExtension()
{
return _extension;
for(int i=0; i<4; i++) global_ground[i] = _global_ground[i];
}
void Gear::getForce(float* force, float* contact)
@ -242,25 +102,6 @@ void Gear::getForce(float* force, float* contact)
Math::set3(_contact, contact);
}
float Gear::getWoW()
{
return _wow;
}
float Gear::getCompressFraction()
{
return _frac;
}
bool Gear::getCastering()
{
return _castering;
}
bool Gear::getGroundIsSolid()
{
return _ground_isSolid;
}
float Gear::getBumpAltitude()
{

View file

@ -1,5 +1,6 @@
#ifndef _GEAR_HPP
#define _GEAR_HPP
#include "Math.hpp"
namespace simgear {
class BVHMaterial;
@ -33,42 +34,43 @@ public:
Gear();
// Externally set values
void setPosition(float* position);
void setCompression(float* compression);
void setSpring(float spring);
void setDamping(float damping);
void setStaticFriction(float sfric);
void setDynamicFriction(float dfric);
void setBrake(float brake);
void setRotation(float rotation);
void setExtension(float extension);
void setCastering(bool castering);
void setOnWater(bool c);
void setOnSolid(bool c);
void setSpringFactorNotPlaning(float f);
void setSpeedPlaning(float s);
void setReduceFrictionByExtension(float s);
void setInitialLoad(float l);
void setIgnoreWhileSolving(bool c);
void setPosition(float* position) { Math::set3(position, _pos); }
void getPosition(float* out) { Math::set3(_pos, out); }
void setCompression(float* compression) { Math::set3(compression, _cmpr); }
void getCompression(float* out) { Math::set3(_cmpr, out); }
void setSpring(float spring) { _spring = spring; }
float getSpring() { return _spring; }
void setDamping(float damping) { _damp = damping; }
float getDamping() {return _damp; }
void setStaticFriction(float sfric) { _sfric = sfric; }
float getStaticFriction() { return _sfric; }
void setDynamicFriction(float dfric) { _dfric = dfric; }
float getDynamicFriction() { return _dfric; }
void setBrake(float brake) { _brake = Math::clamp(brake, 0, 1); }
float getBrake() { return _brake; }
void setRotation(float rotation) { _rot = rotation; }
float getRotation() { return _rot; }
void setExtension(float extension) { _extension = Math::clamp(extension, 0, 1); }
float getExtension() { return _extension; }
void setCastering(bool c) { _castering = c; }
bool getCastering() { return _castering; }
void setOnWater(bool c) { _onWater = c; }
void setOnSolid(bool c) { _onSolid = c; }
void setSpringFactorNotPlaning(float f) { _spring_factor_not_planing = f; }
void setSpeedPlaning(float s) { _speed_planing = s; }
void setReduceFrictionByExtension(float s) { _reduceFrictionByExtension = s; }
void setInitialLoad(float l) { _initialLoad = l; }
float getInitialLoad() {return _initialLoad; }
void setIgnoreWhileSolving(bool c) { _ignoreWhileSolving = c; }
void setGlobalGround(double* global_ground, float* global_vel,
double globalX, double globalY,
const simgear::BVHMaterial *material);
void getPosition(float* out);
void getCompression(float* out);
void getGlobalGround(double* global_ground);
float getSpring();
float getDamping();
float getStaticFriction();
float getDynamicFriction();
float getBrake();
float getRotation();
float getExtension();
float getInitialLoad() {return _initialLoad; }
bool getCastering();
float getCasterAngle() { return _casterAngle; }
float getRollSpeed() { return _rollSpeed; }
float getBumpAltitude();
bool getGroundIsSolid();
bool getGroundIsSolid() { return _ground_isSolid; }
float getGroundFrictionFactor() { return (float)_ground_frictionFactor; }
void integrate(float dt);
@ -81,12 +83,12 @@ public:
// Computed values: total force, weight-on-wheels (force normal to
// ground) and compression fraction.
void getForce(float* force, float* contact);
float getWoW();
float getCompressFraction();
float getWoW() { return _wow; }
float getCompressFraction() { return _frac; }
float getCompressDist() { return _compressDist; }
bool getSubmergable() {return (!_ground_isSolid)&&(!_isContactPoint); }
bool getIgnoreWhileSolving() {return _ignoreWhileSolving; }
void setContactPoint(bool c);
void setContactPoint(bool c) { _isContactPoint=c; }
private:
float calcFriction(float wgt, float v);

View file

@ -44,17 +44,17 @@ public:
// Some 3D vector stuff. In all cases, it is permissible for the
// "out" vector to be the same as one of the inputs.
static inline void set3(float* v, float* out) {
static inline void set3(const float* v, float* out) {
out[0] = v[0];
out[1] = v[1];
out[2] = v[2];
}
static inline float dot3(float* a, float* b) {
static inline float dot3(const float* a, const float* b) {
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
}
static inline void cross3(float* a, float* b, float* out) {
static inline void cross3(const float* a, const float* b, float* out) {
float ax=a[0], ay=a[1], az=a[2];
float bx=b[0], by=b[1], bz=b[2];
out[0] = ay*bz - by*az;
@ -62,30 +62,30 @@ public:
out[2] = ax*by - bx*ay;
}
static inline void mul3(float scalar, float* v, float* out)
static inline void mul3(const float scalar, const float* v, float* out)
{
out[0] = scalar * v[0];
out[1] = scalar * v[1];
out[2] = scalar * v[2];
}
static inline void add3(float* a, float* b, float* out){
static inline void add3(const float* a, const float* b, float* out){
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
}
static inline void sub3(float* a, float* b, float* out) {
static inline void sub3(const float* a, const float* b, float* out) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
}
static inline float mag3(float* v) {
static inline float mag3(const float* v) {
return sqrt(dot3(v, v));
}
static inline void unit3(float* v, float* out) {
static inline void unit3(const float* v, float* out) {
float imag = 1/mag3(v);
mul3(imag, v, out);
}
@ -95,7 +95,7 @@ public:
// 6 7 8
// Multiply two matrices
static void mmul33(float* a, float* b, float* out) {
static void mmul33(const float* a, const float* b, float* out) {
float tmp[9];
tmp[0] = a[0]*b[0] + a[1]*b[3] + a[2]*b[6];
tmp[3] = a[3]*b[0] + a[4]*b[3] + a[5]*b[6];
@ -114,7 +114,7 @@ public:
}
// Multiply by vector
static inline void vmul33(float* m, float* v, float* out) {
static inline void vmul33(const float* m, const float* v, float* out) {
float x = v[0], y = v[1], z = v[2];
out[0] = x*m[0] + y*m[1] + z*m[2];
out[1] = x*m[3] + y*m[4] + z*m[5];
@ -123,43 +123,41 @@ public:
// Multiply the vector by the matrix transpose. Or pre-multiply the
// matrix by v as a row vector. Same thing.
static inline void tmul33(float* m, float* v, float* out) {
static inline void tmul33(const float* m, const float* v, float* out) {
float x = v[0], y = v[1], z = v[2];
out[0] = x*m[0] + y*m[3] + z*m[6];
out[1] = x*m[1] + y*m[4] + z*m[7];
out[2] = x*m[2] + y*m[5] + z*m[8];
}
// Invert matrix
static void invert33(float* m, float* out) {
/// Invert symmetric matrix; ~1/3 less calculations due to symmetry
static void invert33_sym(const float* m, float* out) {
// Compute the inverse as the adjoint matrix times 1/(det M).
// A, B ... I are the cofactors of a b c
// d e f
// g h i
// symetric: d=b, g=c, h=f
float a=m[0], b=m[1], c=m[2];
float d=m[3], e=m[4], f=m[5];
float g=m[6], h=m[7], i=m[8];
float e=m[4], f=m[5];
float i=m[8];
float A = (e*i - h*f);
float B = -(d*i - g*f);
float C = (d*h - g*e);
float D = -(b*i - h*c);
float E = (a*i - g*c);
float F = -(a*h - g*b);
float G = (b*f - e*c);
float H = -(a*f - d*c);
float I = (a*e - d*b);
float A = (e*i - f*f);
float B = -(b*i - c*f);
float C = (b*f - c*e);
float E = (a*i - c*c);
float F = -(a*f - c*b);
float I = (a*e - b*b);
float id = 1/(a*A + b*B + c*C);
out[0] = id*A; out[1] = id*D; out[2] = id*G;
out[3] = id*B; out[4] = id*E; out[5] = id*H;
out[6] = id*C; out[7] = id*F; out[8] = id*I;
out[0] = id*A; out[1] = id*B; out[2] = id*C;
out[3] = out[1]; out[4] = id*E; out[5] = id*F;
out[6] = out[2]; out[7] = out[5]; out[8] = id*I;
}
// Transpose matrix (for an orthonormal orientation matrix, this
// is the same as the inverse).
static inline void trans33(float* m, float* out) {
static inline void trans33(const float* m, float* out) {
// 0 1 2 Elements 0, 4, and 8 are the same
// 3 4 5 Swap elements 1/3, 2/6, and 5/7
// 6 7 8
@ -184,7 +182,7 @@ public:
// xOut becomes the unit vector in the direction of x
// yOut is perpendicular to xOut in the x/y plane
// zOut becomes the unit vector: (xOut cross yOut)
static void ortho33(float* x, float* y,
static void ortho33(const float* x, const float* y,
float* xOut, float* yOut, float* zOut) {
float x0[3], y0[3];
set3(x, x0);

View file

@ -66,13 +66,20 @@ Model::Model()
_hook = 0;
_launchbar = 0;
_groundEffectSpan = 0;
_wingSpan = 0;
_groundEffect = 0;
for(i=0; i<3; i++) _wingCenter[i] = 0;
for(i=0; i<3; i++) _geRefPoint[i] = 0;
_global_ground[0] = 0; _global_ground[1] = 0; _global_ground[2] = 1;
_global_ground[3] = -100000;
_modelN = fgGetNode("/fdm/yasim/forces", true);
_f0xN = _modelN->getNode("f0-aero-x-drag", true);
_f0yN = _modelN->getNode("f0-aero-y-side", true);
_f0zN = _modelN->getNode("f0-aero-z-lift", true);
_gefxN = _modelN->getNode("gndeff-f-x", true);
_gefyN = _modelN->getNode("gndeff-f-y", true);
_gefzN = _modelN->getNode("gndeff-f-z", true);
_wgdistN = _modelN->getNode("wing-gnd-dist", true);
}
Model::~Model()
@ -175,106 +182,12 @@ void Model::iterate()
_integrator.calcNewInterval();
}
bool Model::isCrashed()
{
return _crashed;
}
void Model::setCrashed(bool crashed)
{
_crashed = crashed;
}
float Model::getAGL()
{
return _agl;
}
State* Model::getState()
{
return _s;
}
void Model::setState(State* s)
{
_integrator.setState(s);
_s = _integrator.getState();
}
RigidBody* Model::getBody()
{
return &_body;
}
Integrator* Model::getIntegrator()
{
return &_integrator;
}
Surface* Model::getSurface(int handle)
{
return (Surface*)_surfaces.get(handle);
}
Rotorgear* Model::getRotorgear(void)
{
return &_rotorgear;
}
int Model::addThruster(Thruster* t)
{
return _thrusters.add(t);
}
Hook* Model::getHook(void)
{
return _hook;
}
Launchbar* Model::getLaunchbar(void)
{
return _launchbar;
}
int Model::numThrusters()
{
return _thrusters.size();
}
Thruster* Model::getThruster(int handle)
{
return (Thruster*)_thrusters.get(handle);
}
void Model::setThruster(int handle, Thruster* t)
{
_thrusters.set(handle, t);
}
int Model::addSurface(Surface* surf)
{
return _surfaces.add(surf);
}
int Model::addGear(Gear* gear)
{
return _gears.add(gear);
}
void Model::addHook(Hook* hook)
{
_hook = hook;
}
void Model::addLaunchbar(Launchbar* launchbar)
{
_launchbar = launchbar;
}
int Model::addHitch(Hitch* hitch)
{
return _hitches.add(hitch);
}
void Model::setGroundCallback(Ground* ground_cb)
{
@ -282,30 +195,20 @@ void Model::setGroundCallback(Ground* ground_cb)
_ground_cb = ground_cb;
}
Ground* Model::getGroundCallback(void)
void Model::setGroundEffect(const float* pos, const float span, const float mul)
{
return _ground_cb;
}
void Model::setGroundEffect(float* pos, float span, float mul)
{
Math::set3(pos, _wingCenter);
_groundEffectSpan = span;
Math::set3(pos, _geRefPoint);
_wingSpan = span;
_groundEffect = mul;
}
void Model::setAir(float pressure, float temp, float density)
void Model::setAir(const float pressure, const float temp, const float density)
{
_pressure = pressure;
_temp = temp;
_rho = density;
}
void Model::setWind(float* wind)
{
Math::set3(wind, _wind);
}
void Model::updateGround(State* s)
{
float dummy[3];
@ -431,6 +334,12 @@ void Model::calcForces(State* s)
_body.addForce(pos, force);
_body.addTorque(torque);
}
if (_modelN != 0) {
_f0xN->setFloatValue(faero[0]);
_f0yN->setFloatValue(faero[1]);
_f0zN->setFloatValue(faero[2]);
}
for (j=0; j<_rotorgear.getRotors()->size();j++)
{
Rotor* r = (Rotor *)_rotorgear.getRotors()->get(j);
@ -470,18 +379,30 @@ void Model::calcForces(State* s)
// Account for ground effect by multiplying the vertical force
// component by an amount linear with the fraction of the wingspan
// above the ground.
if ((_groundEffectSpan != 0) && (_groundEffect != 0 ))
if ((_wingSpan != 0) && (_groundEffect != 0 ))
{
float dist = ground[3] - Math::dot3(ground, _wingCenter);
if(dist > 0 && dist < _groundEffectSpan) {
float fz = Math::dot3(faero, ground);
fz *= (_groundEffectSpan - dist) / _groundEffectSpan;
// distance between ground and wing ref. point
float dist = ground[3] - Math::dot3(ground, _geRefPoint);
float fz = 0;
float geForce[3];
if(dist > 0 && dist < _wingSpan) {
fz = Math::dot3(faero, ground);
fz *= (_wingSpan - dist) / _wingSpan;
fz *= _groundEffect;
Math::mul3(fz, ground, faero);
_body.addForce(faero);
}
Math::mul3(fz, ground, geForce);
_body.addForce(geForce);
}
if (_modelN != 0) {
_gefxN->setFloatValue(geForce[0]);
_gefyN->setFloatValue(geForce[1]);
_gefzN->setFloatValue(geForce[2]);
_wgdistN->setFloatValue(dist);
//float ld0 = faero[2]/faero[0];
//float ld = (geForce[2]+faero[2])/(geForce[0]+faero[0]);
//n->getNode("gndeff-ld-ld0", true)->setFloatValue(ld/ld0);
}
}
// Convert the velocity and rotation vectors to local coordinates
float lrot[3], lv[3];
Math::vmul33(s->orient, s->rot, lrot);
@ -561,7 +482,7 @@ void Model::newState(State* s)
// Calculates the airflow direction at the given point and for the
// specified aircraft velocity.
void Model::localWind(float* pos, State* s, float* out, float alt, bool is_rotor)
void Model::localWind(const float* pos, yasim::State* s, float* out, float alt, bool is_rotor)
{
float tmp[3], lwind[3], lrot[3], lv[3];

View file

@ -7,6 +7,7 @@
#include "Vector.hpp"
#include "Turbulence.hpp"
#include "Rotor.hpp"
#include <simgear/props/props.hxx>
namespace yasim {
@ -26,49 +27,49 @@ public:
Model();
virtual ~Model();
RigidBody* getBody();
Integrator* getIntegrator();
RigidBody* getBody() { return &_body; }
Integrator* getIntegrator() { return &_integrator; }
void setTurbulence(Turbulence* turb) { _turb = turb; }
State* getState();
State* getState() { return _s; }
void setState(State* s);
bool isCrashed();
void setCrashed(bool crashed);
float getAGL();
bool isCrashed() { return _crashed; }
void setCrashed(bool crashed) { _crashed = crashed; }
float getAGL() { return _agl; }
void iterate();
// Externally-managed subcomponents
int addThruster(Thruster* t);
int addSurface(Surface* surf);
int addGear(Gear* gear);
void addHook(Hook* hook);
void addLaunchbar(Launchbar* launchbar);
Surface* getSurface(int handle);
Rotorgear* getRotorgear(void);
int addThruster(Thruster* t) { return _thrusters.add(t); }
int addSurface(Surface* surf) { return _surfaces.add(surf); }
int addGear(Gear* gear) { return _gears.add(gear); }
void addHook(Hook* hook) { _hook = hook; }
void addLaunchbar(Launchbar* launchbar) { _launchbar = launchbar; }
Surface* getSurface(int handle) { return (Surface*)_surfaces.get(handle); }
Rotorgear* getRotorgear(void) { return &_rotorgear; }
Gear* getGear(int handle);
Hook* getHook(void);
int addHitch(Hitch* hitch);
Launchbar* getLaunchbar(void);
Hook* getHook(void) { return _hook; }
int addHitch(Hitch* hitch) { return _hitches.add(hitch); }
Launchbar* getLaunchbar(void) { return _launchbar; }
// Semi-private methods for use by the Airplane solver.
int numThrusters();
Thruster* getThruster(int handle);
void setThruster(int handle, Thruster* t);
int numThrusters() { return _thrusters.size(); }
Thruster* getThruster(int handle) { return (Thruster*)_thrusters.get(handle); }
void setThruster(int handle, Thruster* t) { _thrusters.set(handle, t); }
void initIteration();
void getThrust(float* out);
void setGroundCallback(Ground* ground_cb);
Ground* getGroundCallback(void);
Ground* getGroundCallback(void) { return _ground_cb; }
//
// Per-iteration settables
//
void setGroundEffect(float* pos, float span, float mul);
void setWind(float* wind);
void setAir(float pressure, float temp, float density);
void setGroundEffect(const float* pos, const float span, const float mul);
void setWind(float* wind) { Math::set3(wind, _wind); }
void setAir(const float pressure, const float temp, const float density);
void updateGround(State* s);
@ -80,8 +81,7 @@ private:
void initRotorIteration();
void calcGearForce(Gear* g, float* v, float* rot, float* ground);
float gearFriction(float wgt, float v, Gear* g);
void localWind(float* pos, State* s, float* out, float alt,
bool is_rotor = false);
void localWind(const float* pos, State* s, float* out, float alt, bool is_rotor = false);
Integrator _integrator;
RigidBody _body;
@ -96,9 +96,9 @@ private:
Launchbar* _launchbar;
Vector _hitches;
float _groundEffectSpan;
float _wingSpan;
float _groundEffect;
float _wingCenter[3];
float _geRefPoint[3];
Ground* _ground_cb;
double _global_ground[4];
@ -114,6 +114,14 @@ private:
State* _s;
bool _crashed;
float _agl;
SGPropertyNode_ptr _modelN;
SGPropertyNode_ptr _f0xN;
SGPropertyNode_ptr _f0yN;
SGPropertyNode_ptr _f0zN;
SGPropertyNode_ptr _gefxN;
SGPropertyNode_ptr _gefyN;
SGPropertyNode_ptr _gefzN;
SGPropertyNode_ptr _wgdistN;
};
}; // namespace yasim

View file

@ -1,5 +1,6 @@
#include "Math.hpp"
#include <Main/fg_props.hxx>
#include "RigidBody.hpp"
namespace yasim {
RigidBody::RigidBody()
@ -11,6 +12,7 @@ RigidBody::RigidBody()
_masses = new Mass[_massesAlloced];
_gyro[0] = _gyro[1] = _gyro[2] = 0;
_spin[0] = _spin[1] = _spin[2] = 0;
_bodyN = fgGetNode("/fdm/yasim/model/masses", true);
}
RigidBody::~RigidBody()
@ -18,7 +20,9 @@ RigidBody::~RigidBody()
delete[] _masses;
}
int RigidBody::addMass(float mass, float* pos)
/// add new point mass to body
/// isStatic: set to true for masses that do not change per iteration (everything but fuel?)
int RigidBody::addMass(float mass, float* pos, bool isStatic)
{
// If out of space, reallocate twice as much
if(_nMasses == _massesAlloced) {
@ -30,31 +34,37 @@ int RigidBody::addMass(float mass, float* pos)
delete[] _masses;
_masses = m2;
}
_masses[_nMasses].m = mass;
Math::set3(pos, _masses[_nMasses].p);
setMass(_nMasses, mass, pos, isStatic);
return _nMasses++;
}
/// change mass
/// handle: returned by addMass
void RigidBody::setMass(int handle, float mass)
{
if (_masses[handle].m == mass)
return;
_masses[handle].m = mass;
// if static mass is changed, reset pre-calculated mass
// may apply to weights like cargo, pax, that usually do not change with FDM rate
if (_masses[handle].isStatic)
_staticMass.m = 0;
if (_bodyN != 0)
_bodyN->getChild("mass", handle, true)->getNode("mass", true)->setFloatValue(mass);
}
void RigidBody::setMass(int handle, float mass, float* pos)
void RigidBody::setMass(int handle, float mass, const float* pos, bool isStatic)
{
_masses[handle].m = mass;
_masses[handle].isStatic = isStatic;
Math::set3(pos, _masses[handle].p);
}
int RigidBody::numMasses()
{
return _nMasses;
}
float RigidBody::getMass(int handle)
{
return _masses[handle].m;
setMass(handle, mass);
if (_bodyN != 0) {
SGPropertyNode_ptr n = _bodyN->getChild("mass", handle, true);
n->getNode("isStatic", true)->setValue(isStatic);
n->getNode("pos-x", true)->setFloatValue(pos[0]);
n->getNode("pos-y", true)->setFloatValue(pos[1]);
n->getNode("pos-z", true)->setFloatValue(pos[2]);
}
}
void RigidBody::getMassPosition(int handle, float* out)
@ -64,60 +74,129 @@ void RigidBody::getMassPosition(int handle, float* out)
out[2] = _masses[handle].p[2];
}
float RigidBody::getTotalMass()
{
return _totalMass;
}
// Calcualtes the rotational velocity of a particular point. All
// coordinates are local!
void RigidBody::pointVelocity(float* pos, float* rot, float* out)
void RigidBody::pointVelocity(const float* pos, const float* rot, float* out)
{
Math::sub3(pos, _cg, out); // out = pos-cg
Math::cross3(rot, out, out); // = rot cross (pos-cg)
}
void RigidBody::setGyro(float* angularMomentum)
void RigidBody::_recalcStatic()
{
Math::set3(angularMomentum, _gyro);
// aggregate all masses that do not change (e.g. fuselage, wings) into one point mass
_staticMass.m = 0;
_staticMass.p[0] = 0;
_staticMass.p[1] = 0;
_staticMass.p[2] = 0;
int i;
int s = 0;
for(i=0; i<_nMasses; i++) {
if (_masses[i].isStatic) {
s++;
float m = _masses[i].m;
_staticMass.m += m;
_staticMass.p[0] += m * _masses[i].p[0];
_staticMass.p[1] += m * _masses[i].p[1];
_staticMass.p[2] += m * _masses[i].p[2];
}
}
Math::mul3(1/_staticMass.m, _staticMass.p, _staticMass.p);
if (_bodyN != 0) {
_bodyN->getNode("aggregated-mass", true)->setFloatValue(_staticMass.m);
_bodyN->getNode("aggregated-count", true)->setIntValue(s);
_bodyN->getNode("aggregated-pos-x", true)->setFloatValue(_staticMass.p[0]);
_bodyN->getNode("aggregated-pos-y", true)->setFloatValue(_staticMass.p[1]);
_bodyN->getNode("aggregated-pos-z", true)->setFloatValue(_staticMass.p[2]);
}
// Now the inertia tensor:
for(i=0; i<9; i++)
_tI_static[i] = 0;
for(i=0; i<_nMasses; i++) {
if (_masses[i].isStatic) {
float m = _masses[i].m;
float x = _masses[i].p[0] - _staticMass.p[0];
float y = _masses[i].p[1] - _staticMass.p[1];
float z = _masses[i].p[2] - _staticMass.p[2];
float xy = m*x*y; float yz = m*y*z; float zx = m*z*x;
float x2 = m*x*x; float y2 = m*y*y; float z2 = m*z*z;
// tensor is symmetric, so we can save some calculations in the loop
_tI_static[0] += y2+z2; _tI_static[1] -= xy; _tI_static[2] -= zx;
_tI_static[4] += x2+z2; _tI_static[5] -= yz;
_tI_static[8] += x2+y2;
}
}
// copy symmetric elements
_tI_static[3] = _tI_static[1];
_tI_static[6] = _tI_static[2];
_tI_static[7] = _tI_static[5];
}
/// calculate the total mass, centre of gravity and inertia tensor
/**
recalc is used when compiling the model but more important it is called in
Model::iterate() e.g. at FDM rate (120 Hz)
We can save some CPU due to the symmetry of the tensor and by aggregating
masses that do not change during flight.
*/
void RigidBody::recalc()
{
// Calculate the c.g and total mass:
_totalMass = 0;
_cg[0] = _cg[1] = _cg[2] = 0;
//aggregate static masses into one mass
if (_staticMass.m == 0) _recalcStatic();
// Calculate the c.g and total mass
// init with pre-calculated static mass
_totalMass = _staticMass.m;
_cg[0] = _staticMass.m * _staticMass.p[0];
_cg[1] = _staticMass.m * _staticMass.p[1];
_cg[2] = _staticMass.m * _staticMass.p[2];
int i;
for(i=0; i<_nMasses; i++) {
// only masses we did not aggregate
if (!_masses[i].isStatic) {
float m = _masses[i].m;
_totalMass += m;
_cg[0] += m * _masses[i].p[0];
_cg[1] += m * _masses[i].p[1];
_cg[2] += m * _masses[i].p[2];
}
}
Math::mul3(1/_totalMass, _cg, _cg);
// Now the inertia tensor:
for(i=0; i<9; i++)
_tI[i] = 0;
_tI[i] = _tI_static[i];
for(i=0; i<_nMasses; i++) {
if (!_masses[i].isStatic) {
float m = _masses[i].m;
float x = _masses[i].p[0] - _cg[0];
float y = _masses[i].p[1] - _cg[1];
float z = _masses[i].p[2] - _cg[2];
float mx = m*x;
float my = m*y;
float mz = m*z;
float xy = m*x*y; float yz = m*y*z; float zx = m*z*x;
float x2 = m*x*x; float y2 = m*y*y; float z2 = m*z*z;
float xy = mx*y; float yz = my*z; float zx = mz*x;
float x2 = mx*x; float y2 = my*y; float z2 = mz*z;
_tI[0] += y2+z2; _tI[1] -= xy; _tI[2] -= zx;
_tI[3] -= xy; _tI[4] += x2+z2; _tI[5] -= yz;
_tI[6] -= zx; _tI[7] -= yz; _tI[8] += x2+y2;
_tI[4] += x2+z2; _tI[5] -= yz;
_tI[8] += x2+y2;
}
}
// copy symmetric elements
_tI[3] = _tI[1];
_tI[6] = _tI[2];
_tI[7] = _tI[5];
// And its inverse
Math::invert33(_tI, _invI);
//calculate inverse
Math::invert33_sym(_tI, _invI);
}
void RigidBody::reset()
@ -126,17 +205,7 @@ void RigidBody::reset()
_force[0] = _force[1] = _force[2] = 0;
}
void RigidBody::addForce(float* force)
{
Math::add3(_force, force, _force);
}
void RigidBody::addTorque(float* torque)
{
Math::add3(_torque, torque, _torque);
}
void RigidBody::addForce(float* pos, float* force)
void RigidBody::addForce(const float* pos, const float* force)
{
addForce(force);
@ -148,21 +217,6 @@ void RigidBody::addForce(float* pos, float* force)
addTorque(t);
}
void RigidBody::setBodySpin(float* rotation)
{
Math::set3(rotation, _spin);
}
void RigidBody::getCG(float* cgOut)
{
Math::set3(_cg, cgOut);
}
void RigidBody::getAccel(float* accelOut)
{
Math::mul3(1/_totalMass, _force, accelOut);
}
void RigidBody::getAccel(float* pos, float* accelOut)
{
getAccel(accelOut);

View file

@ -1,5 +1,8 @@
#ifndef _RIGIDBODY_HPP
#define _RIGIDBODY_HPP
#include <simgear/props/props.hxx>
#include "Vector.hpp"
#include "Math.hpp"
namespace yasim {
@ -20,27 +23,28 @@ namespace yasim {
//
class RigidBody
{
SGPropertyNode_ptr _bodyN;
public:
RigidBody();
~RigidBody();
// Adds a point mass to the system. Returns a handle so the gyro
// can be later modified via setMass().
int addMass(float mass, float* pos);
int addMass(float mass, float* pos, bool isStatic = false);
// Modifies a previously-added point mass (fuel tank running dry,
// gear going up, swing wing swinging, pilot bailing out, etc...)
void setMass(int handle, float mass);
void setMass(int handle, float mass, float* pos);
void setMass(int handle, float mass, const float* pos, bool isStatic = false);
int numMasses();
float getMass(int handle);
int numMasses() { return _nMasses; }
float getMass(int handle) { return _masses[handle].m; }
void getMassPosition(int handle, float* out);
float getTotalMass();
float getTotalMass() { return _totalMass; }
// The velocity, in local coordinates, of the specified point on a
// body rotating about its c.g. with velocity rot.
void pointVelocity(float* pos, float* rot, float* out);
void pointVelocity(const float* pos, const float* rot, float* out);
// Sets the "gyroscope" for the body. This is the total
// "intrinsic" angular momentum of the body; that is, rotations of
@ -48,27 +52,26 @@ public:
// frame. Because angular momentum is additive in this way, we
// don't need to specify specific gyro objects; just add all their
// momenta together and set it here.
void setGyro(float* angularMomentum);
void setGyro(const float* angularMomentum) { Math::set3(angularMomentum, _gyro); }
// When masses are moved or changed, this object needs to
// regenerate its internal tables. This step is expensive, so
// it's exposed to the client who can amortize the call across
// multiple changes.
// multiple changes. see also _recalcStatic()
void recalc();
// Resets the current force/torque parameters to zero.
void reset();
// Applies a force at the center of gravity.
void addForce(const float* force) { Math::add3(_force, force, _force); }
// Applies a force at the specified position.
void addForce(float* pos, float* force);
// Applies a force at the center of gravity.
void addForce(float* force);
void addForce(const float* pos, const float* force);
// Adds a torque with the specified axis and magnitude
void addTorque(float* torque);
void addTorque(const float* torque) { Math::add3(_torque, torque, _torque); }
// Sets the rotation rate of the body (about its c.g.) within the
// surrounding environment. This is needed to compute torque on
@ -76,17 +79,15 @@ public:
// rotation. NOTE: the rotation vector, like all other
// coordinates used here, is specified IN THE LOCAL COORDINATE
// SYSTEM.
void setBodySpin(float* rotation);
void setBodySpin(const float* rotation) { Math::set3(rotation, _spin); }
// Returns the center of gravity of the masses, in the body
// coordinate system.
void getCG(float* cgOut);
// coordinate system. valid only after recalc()
void getCG(float* cgOut) { Math::set3(_cg, cgOut); }
// Returns the acceleration of the body's c.g. relative to the
// rest of the world, specified in local coordinates.
void getAccel(float* accelOut);
void getAccel(float* accelOut) { Math::mul3(1/_totalMass, _force, accelOut); }
// Returns the acceleration of a specific location in local
// coordinates. If the body is rotating, this will be different
@ -102,17 +103,24 @@ public:
void getInertiaMatrix(float* inertiaOut);
private:
struct Mass { float m; float p[3]; };
/**
Most of the mass points do not change after compilation of the aircraft so
they can be replaced by one aggregated mass at the c.g. of the static masses.
The isStatic flag is used to mark those masses.
*/
struct Mass { float m; float p[3]; bool isStatic; };
void _recalcStatic(); /// aggregate static masses
Mass _staticMass; /// aggregated static masses, calculated once
Mass* _masses; /// mass elements
int _nMasses; /// number of masses
int _massesAlloced; /// counter for memory allocation
// Internal "rotational structure"
Mass* _masses;
int _nMasses;
int _massesAlloced;
float _totalMass;
float _cg[3];
float _gyro[3];
// Inertia tensor, and its inverse. Computed from the above.
float _tI_static[9];
float _tI[9];
float _invI[9];

View file

@ -7,7 +7,7 @@
#include "Math.hpp"
#include <Main/fg_props.hxx>
#include "Surface.hpp"
//#include "Surface.hpp"
#include "Rotorpart.hpp"
#include "Glue.hpp"
#include "Ground.hpp"
@ -962,7 +962,7 @@ float Rotor::findGroundEffectAltitude(Ground * ground_cb,State *s,
);
}
void Rotor::getDownWash(float *pos, float *v_heli, float *downwash)
void Rotor::getDownWash(const float *pos, const float *v_heli, float *downwash)
{
float pos2rotor[3],tmp[3];
Math::sub3(_base,pos,pos2rotor);
@ -1632,7 +1632,7 @@ void Rotorgear::compile()
}
}
void Rotorgear::getDownWash(float *pos, float * v_heli, float *downwash)
void Rotorgear::getDownWash(const float *pos, const float * v_heli, float *downwash)
{
float tmp[3];
downwash[0]=downwash[1]=downwash[2]=0;

View file

@ -9,7 +9,7 @@
namespace yasim {
class Surface;
//class Surface;
class Rotorpart;
class Ground;
const float rho_null=1.184f; //25DegC, 101325Pa
@ -107,7 +107,7 @@ public:
void updateDirectionsAndPositions(float *rot);
void getTip(float* tip);
void calcLiftFactor(float* v, float rho, State *s);
void getDownWash(float *pos, float * v_heli, float *downwash);
void getDownWash(const float* pos, const float* v_heli, float* downwash);
int getNumberOfBlades(){return _number_of_blades;}
void setDownwashFactor(float value);
@ -287,7 +287,7 @@ public:
float getEnginePropFactor() {return _engine_prop_factor;}
Vector* getRotors() { return &_rotors;}
void initRotorIteration(float *lrot,float dt);
void getDownWash(float *pos, float * v_heli, float *downwash);
void getDownWash(const float* pos, const float* v_heli, float* downwash);
int getValueforFGSet(int j,char *b,float *f);
};

View file

@ -1,10 +1,14 @@
#include "Math.hpp"
#include <Main/fg_props.hxx>
#include "Surface.hpp"
namespace yasim {
int Surface::s_idGenerator = 0;
Surface::Surface( Version * version ) :
_version(version)
{
// create id for surface
_id = s_idGenerator++;
// Start in a "sane" mode, so unset stuff doesn't freak us out
_c0 = 1;
_cx = _cy = _cz = 1;
@ -30,91 +34,40 @@ Surface::Surface( Version * version ) :
_slatAlpha = 0;
_spoilerLift = 1;
_inducedDrag = 1;
_stallAlpha = 0;
_alpha = 0;
_surfN = fgGetNode("/fdm/yasim/surfaces", true);
if (_surfN != 0) {
_surfN = _surfN->getChild("surface", _id, true);
_fxN = _surfN->getNode("f-x", true);
_fyN = _surfN->getNode("f-y", true);
_fzN = _surfN->getNode("f-z", true);
_fabsN = _surfN->getNode("f-abs", true);
_alphaN = _surfN->getNode("alpha", true);
_stallAlphaN = _surfN->getNode("stall-alpha", true);
_flapN = _surfN->getNode("flap-pos", true);
_slatN = _surfN->getNode("slat-pos", true);
_spoilerN = _surfN->getNode("spoiler-pos", true);
}
}
void Surface::setPosition(float* p)
void Surface::setPosition(const float* p)
{
int i;
for(i=0; i<3; i++) _pos[i] = p[i];
if (_surfN != 0) {
_surfN->getNode("pos-x", true)->setFloatValue(p[0]);
_surfN->getNode("pos-y", true)->setFloatValue(p[1]);
_surfN->getNode("pos-z", true)->setFloatValue(p[2]);
}
}
void Surface::getPosition(float* out)
void Surface::setOrientation(const float* o)
{
int i;
for(i=0; i<3; i++) out[i] = _pos[i];
for(int i=0; i<9; i++) _orient[i] = o[i];
}
void Surface::setChord(float chord)
{
_chord = chord;
}
void Surface::setTotalDrag(float c0)
{
_c0 = c0;
}
float Surface::getTotalDrag()
{
return _c0;
}
void Surface::setXDrag(float cx)
{
_cx = cx;
}
void Surface::setYDrag(float cy)
{
_cy = cy;
}
void Surface::setZDrag(float cz)
{
_cz = cz;
}
float Surface::getXDrag()
{
return _cx;
}
void Surface::setBaseZDrag(float cz0)
{
_cz0 = cz0;
}
void Surface::setStallPeak(int i, float peak)
{
_peaks[i] = peak;
}
void Surface::setStall(int i, float alpha)
{
_stalls[i] = alpha;
}
void Surface::setStallWidth(int i, float width)
{
_widths[i] = width;
}
void Surface::setOrientation(float* o)
{
int i;
for(i=0; i<9; i++)
_orient[i] = o[i];
}
void Surface::setIncidence(float angle)
{
_incidence = angle;
}
void Surface::setTwist(float angle)
{
_twist = angle;
}
void Surface::setSlatParams(float stallDelta, float dragPenalty)
{
@ -134,42 +87,39 @@ void Surface::setSpoilerParams(float liftPenalty, float dragPenalty)
_spoilerDrag = dragPenalty;
}
void Surface::setFlap(float pos)
void Surface::setFlapPos(float pos)
{
if (_flapPos != pos) {
_flapPos = pos;
if (_surfN != 0) _flapN->setFloatValue(pos);
}
}
void Surface::setFlapEffectiveness(float effectiveness)
{
_flapEffectiveness = effectiveness;
}
double Surface::getFlapEffectiveness()
{
return _flapEffectiveness;
}
void Surface::setSlat(float pos)
void Surface::setSlatPos(float pos)
{
if (_slatPos != pos) {
_slatPos = pos;
if (_surfN != 0) _slatN->setFloatValue(pos);
}
}
void Surface::setSpoiler(float pos)
void Surface::setSpoilerPos(float pos)
{
if (_spoilerPos != pos) {
_spoilerPos = pos;
if (_surfN != 0) _spoilerN->setFloatValue(pos);
}
}
// Calculate the aerodynamic force given a wind vector v (in the
// aircraft's "local" coordinates) and an air density rho. Returns a
// torque about the Y axis, too.
void Surface::calcForce(float* v, float rho, float* out, float* torque)
void Surface::calcForce(const float* v, const float rho, float* out, float* torque)
{
// Split v into magnitude and direction:
float vel = Math::mag3(v);
// Handle the blowup condition. Zero velocity means zero force by
// definition.
// Zero velocity means zero force by definition (also prevents div0).
if(vel == 0) {
int i;
for(i=0; i<3; i++) out[i] = torque[i] = 0;
@ -183,9 +133,8 @@ void Surface::calcForce(float* v, float rho, float* out, float* torque)
return;
}
// Normalize wind and convert to the surface's coordinates
Math::mul3(1/vel, v, out);
// Convert to the surface's coordinates
Math::vmul33(_orient, out, out);
// "Rotate" by the incidence angle. Assume small angles, so we
@ -247,6 +196,15 @@ void Surface::calcForce(float* v, float rho, float* out, float* torque)
float scale = 0.5f*rho*vel*vel*_c0;
Math::mul3(scale, out, out);
Math::mul3(scale, torque, torque);
// if we have a property tree, export info
if (_surfN != 0) {
_fabsN->setFloatValue(Math::mag3(out));
_fxN->setFloatValue(out[0]);
_fyN->setFloatValue(out[1]);
_fzN->setFloatValue(out[2]);
_alphaN->setFloatValue(_alpha);
_stallAlphaN->setFloatValue(_stallAlpha);
}
}
#if 0
@ -257,9 +215,9 @@ void Surface::test()
float rho = Atmosphere::getStdDensity(0);
float spd = 30;
setFlap(0);
setSlat(0);
setSpoiler(0);
setFlapPos(0);
setSlatPos(0);
setSpoilerPos(0);
for(float angle = -90; angle<90; angle += 0.01) {
float rad = angle * DEG2RAD;
@ -281,39 +239,40 @@ float Surface::stallFunc(float* v)
// Sanity check to treat FPU psychopathology
if(v[0] == 0) return 1;
float alpha = Math::abs(v[2]/v[0]);
_alpha = Math::abs(v[2]/v[0]);
// Wacky use of indexing, see setStall*() methods.
int fwdBak = v[0] > 0; // set if this is "backward motion"
int posNeg = v[2] < 0; // set if the airflow is toward -z
int i = (fwdBak<<1) | posNeg;
float stallAlpha = _stalls[i];
if(stallAlpha == 0)
_stallAlpha = _stalls[i];
if(_stallAlpha == 0)
return 1;
// consider slat position, moves the stall aoa some degrees
if(i == 0) {
if( _version->isVersionOrNewer( Version::YASIM_VERSION_32 )) {
stallAlpha += _slatPos * _slatAlpha;
_stallAlpha += _slatPos * _slatAlpha;
} else {
stallAlpha += _slatAlpha;
_stallAlpha += _slatAlpha;
}
}
// Beyond the stall
if(alpha > stallAlpha+_widths[i])
if(_alpha > _stallAlpha+_widths[i])
return 1;
// (note mask: we want to use the "positive" stall angle here)
float scale = 0.5f*_peaks[fwdBak]/_stalls[i&2];
// Before the stall
if(alpha <= stallAlpha)
if(_alpha <= _stallAlpha)
return scale;
// Inside the stall. Compute a cubic interpolation between the
// pre-stall "scale" value and the post-stall unity.
float frac = (alpha - stallAlpha) / _widths[i];
float frac = (_alpha - _stallAlpha) / _widths[i];
frac = frac*frac*(3-2*frac);
return scale*(1-frac) + frac;

View file

@ -1,7 +1,9 @@
#ifndef _SURFACE_HPP
#define _SURFACE_HPP
#include <simgear/props/props.hxx>
#include "Version.hpp"
#include "Math.hpp"
namespace yasim {
@ -10,15 +12,21 @@ namespace yasim {
// front, and flaps act (in both lift and drag) toward the back.
class Surface
{
static int s_idGenerator;
int _id; //index for property tree
public:
Surface( Version * version );
int getID() { return _id; };
static void resetIDgen() { s_idGenerator = 0; };
// Position of this surface in local coords
void setPosition(float* p);
void getPosition(float* out);
void setPosition(const float* p);
void getPosition(float* out) { Math::set3(_pos, out); }
// Distance scale along the X axis
void setChord(float chord);
void setChord(float chord) { _chord = chord; }
// Slats act to move the stall peak by the specified angle, and
// increase drag by the multiplier specified.
@ -32,49 +40,54 @@ public:
// Positions for the controls, in the range [0:1]. [-1:1] for
// flaps, with positive meaning "force goes towards positive Z"
void setFlap(float pos);
void setSlat(float pos);
void setSpoiler(float pos);
void setFlapPos(float pos);
void setSlatPos(float pos);
void setSpoilerPos(float pos);
// Modifier for flap lift coefficient, useful for simulating flap blowing etc.
void setFlapEffectiveness(float effectiveness);
double getFlapEffectiveness();
void setFlapEffectiveness(float effectiveness) { _flapEffectiveness = effectiveness; }
double getFlapEffectiveness() { return _flapEffectiveness; }
// local -> Surface coords
void setOrientation(float* o);
void setOrientation(const float* o);
// For variable-incidence control surfaces. The angle is a
// negative rotation about the surface's Y axis, in radians, so
// positive is "up" (i.e. "positive AoA")
void setIncidence(float angle);
void setIncidence(float angle) { _incidence = angle; }
// The offset from base incidence for this surface.
void setTwist(float angle);
void setTwist(float angle) { _twist = angle; }
void setTotalDrag(float c0);
float getTotalDrag();
void setTotalDrag(float c0) { _c0 = c0; }
float getTotalDrag() { return _c0; }
void setXDrag(float cx);
void setYDrag(float cy);
void setZDrag(float cz);
float getXDrag();
void setXDrag(float cx) { _cx = cx; }
void setYDrag(float cy) { _cy = cy; }
void setZDrag(float cz) { _cz = cz; }
float getXDrag() { return _cx; }
// zero-alpha Z drag ("camber") specified as a fraction of cz
void setBaseZDrag(float cz0);
void setBaseZDrag(float cz0) { _cz0 = cz0; }
// i: 0 == forward, 1 == backwards
void setStallPeak(int i, float peak);
void setStallPeak(int i, float peak) { _peaks[i] = peak; }
// i: 0 == fwd/+z, 1 == fwd/-z, 2 == rev/+z, 3 == rev/-z
void setStall(int i, float alpha);
void setStallWidth(int i, float width);
void setStall(int i, float alpha) { _stalls[i] = alpha; }
void setStallWidth(int i, float width) { _widths[i] = width; }
// Induced drag multiplier
void setInducedDrag(float mul) { _inducedDrag = mul; }
void calcForce(float* v, float rho, float* forceOut, float* torqueOut);
void calcForce(const float* v, const float rho, float* out, float* torque);
float getAlpha() { return _alpha; };
float getStallAlpha() { return _stallAlpha; };
private:
SGPropertyNode_ptr _surfN;
float stallFunc(float* v);
float flapLift(float alpha);
float controlDrag(float lift, float drag);
@ -106,7 +119,20 @@ private:
float _twist;
float _inducedDrag;
// used during calculations
float _stallAlpha;
float _alpha;
Version * _version;
SGPropertyNode* _fxN;
SGPropertyNode* _fyN;
SGPropertyNode* _fzN;
SGPropertyNode* _stallAlphaN;
SGPropertyNode* _alphaN;
SGPropertyNode* _flapN;
SGPropertyNode* _slatN;
SGPropertyNode* _spoilerN;
SGPropertyNode* _fabsN;
};
}; // namespace yasim

View file

@ -5,6 +5,7 @@
#include "Version.hpp"
#include <simgear/debug/logstream.hxx>
#include <string>
#include <iostream>
namespace yasim {
void Version::setVersion( const char * version )
@ -15,11 +16,15 @@ void Version::setVersion( const char * version )
_version = YASIM_VERSION_ORIGINAL;
} else if( v == "YASIM_VERSION_32" ) {
_version = YASIM_VERSION_32;
} else if( v == "2017.2" ) {
_version = YASIM_VERSION_2017_2;
} else if( v == "YASIM_VERSION_CURRENT" ) {
_version = YASIM_VERSION_CURRENT;
} else {
SG_LOG(SG_FLIGHT,SG_ALERT,"unknown yasim version '" << version << "' ignored, using YASIM_VERSION_ORIGINAL");
return;
}
std::cout << "This aircraft uses yasim version '" << v << "'\n";
}
} // namespace yasim

View file

@ -11,10 +11,12 @@ public:
typedef enum {
YASIM_VERSION_ORIGINAL = 0,
YASIM_VERSION_32,
YASIM_VERSION_CURRENT = YASIM_VERSION_32
YASIM_VERSION_2017_2,
YASIM_VERSION_CURRENT = YASIM_VERSION_2017_2
} YASIM_VERSION;
void setVersion( const char * version );
int getVersion() { return _version; }
bool isVersion( YASIM_VERSION version );
bool isVersionOrNewer( YASIM_VERSION version );

View file

@ -1,8 +1,8 @@
#include "Math.hpp"
#include "Surface.hpp"
#include "Wing.hpp"
namespace yasim {
static const float RAD2DEG = 57.2957795131;
Wing::Wing( Version * version ) :
_version(version)
@ -39,6 +39,9 @@ Wing::Wing( Version * version ) :
_slatEnd = 0;
_slatAoA = 0;
_slatDrag = 0;
_meanChord = 0;
_wingspan = 0;
_aspectRatio = 1;
}
Wing::~Wing()
@ -51,82 +54,6 @@ Wing::~Wing()
}
}
int Wing::numSurfaces()
{
return _surfs.size();
}
Surface* Wing::getSurface(int n)
{
return ((SurfRec*)_surfs.get(n))->surface;
}
float Wing::getSurfaceWeight(int n)
{
return ((SurfRec*)_surfs.get(n))->weight;
}
void Wing::setMirror(bool mirror)
{
_mirror = mirror;
}
void Wing::setBase(float* base)
{
int i;
for(i=0; i<3; i++) _base[i] = base[i];
}
void Wing::setLength(float length)
{
_length = length;
}
void Wing::setChord(float chord)
{
_chord = chord;
}
void Wing::setTaper(float taper)
{
_taper = taper;
}
void Wing::setSweep(float sweep)
{
_sweep = sweep;
}
void Wing::setDihedral(float dihedral)
{
_dihedral = dihedral;
}
void Wing::setStall(float aoa)
{
_stall = aoa;
}
void Wing::setStallWidth(float angle)
{
_stallWidth = angle;
}
void Wing::setStallPeak(float fraction)
{
_stallPeak = fraction;
}
void Wing::setTwist(float angle)
{
_twist = angle;
}
void Wing::setCamber(float camber)
{
_camber = camber;
}
void Wing::setIncidence(float incidence)
{
_incidence = incidence;
@ -135,7 +62,7 @@ void Wing::setIncidence(float incidence)
((SurfRec*)_surfs.get(i))->surface->setIncidence(incidence);
}
void Wing::setFlap0(float start, float end, float lift, float drag)
void Wing::setFlap0Params(float start, float end, float lift, float drag)
{
_flap0Start = start;
_flap0End = end;
@ -143,7 +70,7 @@ void Wing::setFlap0(float start, float end, float lift, float drag)
_flap0Drag = drag;
}
void Wing::setFlap1(float start, float end, float lift, float drag)
void Wing::setFlap1Params(float start, float end, float lift, float drag)
{
_flap1Start = start;
_flap1End = end;
@ -151,7 +78,7 @@ void Wing::setFlap1(float start, float end, float lift, float drag)
_flap1Drag = drag;
}
void Wing::setSlat(float start, float end, float aoa, float drag)
void Wing::setSlatParams(float start, float end, float aoa, float drag)
{
_slatStart = start;
_slatEnd = end;
@ -159,7 +86,7 @@ void Wing::setSlat(float start, float end, float aoa, float drag)
_slatDrag = drag;
}
void Wing::setSpoiler(float start, float end, float lift, float drag)
void Wing::setSpoilerParams(float start, float end, float lift, float drag)
{
_spoilerStart = start;
_spoilerEnd = end;
@ -167,14 +94,14 @@ void Wing::setSpoiler(float start, float end, float lift, float drag)
_spoilerDrag = drag;
}
void Wing::setFlap0(float lval, float rval)
void Wing::setFlap0Pos(float lval, float rval)
{
lval = Math::clamp(lval, -1, 1);
rval = Math::clamp(rval, -1, 1);
int i;
for(i=0; i<_flap0Surfs.size(); i++) {
((Surface*)_flap0Surfs.get(i))->setFlap(lval);
if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlap(rval);
((Surface*)_flap0Surfs.get(i))->setFlapPos(lval);
if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlapPos(rval);
}
}
@ -184,18 +111,17 @@ void Wing::setFlap0Effectiveness(float lval)
int i;
for(i=0; i<_flap0Surfs.size(); i++) {
((Surface*)_flap0Surfs.get(i))->setFlapEffectiveness(lval);
// if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlapEffectiveness(rval);
}
}
void Wing::setFlap1(float lval, float rval)
void Wing::setFlap1Pos(float lval, float rval)
{
lval = Math::clamp(lval, -1, 1);
rval = Math::clamp(rval, -1, 1);
int i;
for(i=0; i<_flap1Surfs.size(); i++) {
((Surface*)_flap1Surfs.get(i))->setFlap(lval);
if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlap(rval);
((Surface*)_flap1Surfs.get(i))->setFlapPos(lval);
if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlapPos(rval);
}
}
@ -205,51 +131,26 @@ void Wing::setFlap1Effectiveness(float lval)
int i;
for(i=0; i<_flap1Surfs.size(); i++) {
((Surface*)_flap1Surfs.get(i))->setFlapEffectiveness(lval);
// if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlap(rval);
}
}
void Wing::setSpoiler(float lval, float rval)
void Wing::setSpoilerPos(float lval, float rval)
{
lval = Math::clamp(lval, 0, 1);
rval = Math::clamp(rval, 0, 1);
int i;
for(i=0; i<_spoilerSurfs.size(); i++) {
((Surface*)_spoilerSurfs.get(i))->setSpoiler(lval);
if(_mirror) ((Surface*)_spoilerSurfs.get(++i))->setSpoiler(rval);
((Surface*)_spoilerSurfs.get(i))->setSpoilerPos(lval);
if(_mirror) ((Surface*)_spoilerSurfs.get(++i))->setSpoilerPos(rval);
}
}
void Wing::setSlat(float val)
void Wing::setSlatPos(float val)
{
val = Math::clamp(val, 0, 1);
int i;
for(i=0; i<_slatSurfs.size(); i++)
((Surface*)_slatSurfs.get(i))->setSlat(val);
}
float Wing::getGroundEffect(float* posOut)
{
int i;
for(i=0; i<3; i++) posOut[i] = _base[i];
float span = _length * Math::cos(_sweep) * Math::cos(_dihedral);
span = 2*(span + Math::abs(_base[2]));
return span;
}
void Wing::getTip(float* tip)
{
tip[0] = -Math::tan(_sweep);
tip[1] = Math::cos(_dihedral);
tip[2] = Math::sin(_dihedral);
Math::unit3(tip, tip);
Math::mul3(_length, tip, tip);
Math::add3(_base, tip, tip);
}
bool Wing::isMirrored()
{
return _mirror;
((Surface*)_slatSurfs.get(i))->setSlatPos(val);
}
void Wing::compile()
@ -294,9 +195,8 @@ void Wing::compile()
last = bounds[i];
}
// Calculate a "nominal" segment length equal to an average chord,
// normalized to lie within 0-1 over the length of the wing.
float segLen = _chord * (0.5f*(_taper+1)) / _length;
// prepare wing coordinate system, ignoring incidence and twist for now
// (tail incidence is varied by the solver)
// Generating a unit vector pointing out the left wing.
float left[3];
@ -306,11 +206,12 @@ void Wing::compile()
Math::unit3(left, left);
// Calculate coordinates for the root and tip of the wing
float root[3], tip[3];
Math::set3(_base, root);
Math::set3(left, tip);
Math::mul3(_length, tip, tip);
Math::add3(root, tip, tip);
Math::mul3(_length, left, _tip);
Math::add3(_base, _tip, _tip);
_meanChord = _chord*(_taper+1)*0.5f;
// wingspan in y-direction (not for vstab)
_wingspan = Math::abs(2*_tip[1]);
_aspectRatio = _wingspan / _meanChord;
// The wing's Y axis will be the "left" vector. The Z axis will
// be perpendicular to this and the local (!) X axis, because we
@ -339,6 +240,10 @@ void Wing::compile()
for(i=3; i<6; i++) rightOrient[i] = -rightOrient[i];
}
// Calculate a "nominal" segment length equal to an average chord,
// normalized to lie within 0-1 over the length of the wing.
float segLen = _meanChord / _length;
// Now go through each boundary and make segments
for(i=0; i<(nbounds-1); i++) {
float start = bounds[i];
@ -363,7 +268,7 @@ void Wing::compile()
for(j=0; j<nSegs; j++) {
float frac = start + (j+0.5f) * (end-start)/nSegs;
float pos[3];
interp(root, tip, frac, pos);
interp(_base, _tip, frac, pos);
float chord = _chord * (1 - (1-_taper)*frac);
@ -390,22 +295,16 @@ void Wing::compile()
}
}
}
// Last of all, re-set the incidence in case setIncidence() was
// called before we were compiled.
setIncidence(_incidence);
}
float Wing::getDragScale()
{
return _dragScale;
}
void Wing::setDragScale(float scale)
{
_dragScale = scale;
int i;
for(i=0; i<_surfs.size(); i++) {
for(int i=0; i<_surfs.size(); i++) {
SurfRec* s = (SurfRec*)_surfs.get(i);
s->surface->setTotalDrag(scale * s->weight);
}
@ -414,16 +313,10 @@ void Wing::setDragScale(float scale)
void Wing::setLiftRatio(float ratio)
{
_liftRatio = ratio;
int i;
for(i=0; i<_surfs.size(); i++)
for(int i=0; i<_surfs.size(); i++)
((SurfRec*)_surfs.get(i))->surface->setZDrag(ratio);
}
float Wing::getLiftRatio()
{
return _liftRatio;
}
Surface* Wing::newSurface(float* pos, float* orient, float chord,
bool flap0, bool flap1, bool slat, bool spoiler)
{
@ -442,15 +335,21 @@ Surface* Wing::newSurface(float* pos, float* orient, float chord,
s->setStallWidth(0, _stallWidth);
s->setStallPeak(0, _stallPeak);
// The negative AoA stall is the same if we're using an uncambered
// airfoil, otherwise a "little badder".
// The negative AoA stall is the same if we're using an symmetric
// airfoil, otherwise a "little worse".
if(_camber > 0) {
s->setStall(1, stallAoA * 0.8f);
s->setStallWidth(1, _stallWidth * 0.5f);
} else {
s->setStall(1, stallAoA);
if( _version->isVersionOrNewer( Version::YASIM_VERSION_2017_2 )) {
// what was presumably meant
s->setStallWidth(1, _stallWidth);
} else {
// old code; presumably a copy&paste error
s->setStall(1, _stallWidth);
}
}
// The "reverse" stalls are unmeasurable junk. Just use 13deg and
// "sharp".
@ -476,7 +375,7 @@ Surface* Wing::newSurface(float* pos, float* orient, float chord,
return s;
}
void Wing::interp(float* v1, float* v2, float frac, float* out)
void Wing::interp(const float* v1, const float* v2, const float frac, float* out)
{
out[0] = v1[0] + frac*(v2[0]-v1[0]);
out[1] = v1[1] + frac*(v2[1]-v1[1]);

View file

@ -3,6 +3,7 @@
#include "Vector.hpp"
#include "Version.hpp"
#include "Math.hpp"
namespace yasim {
@ -15,64 +16,81 @@ public:
~Wing();
// Do we mirror ourselves about the XZ plane?
void setMirror(bool mirror);
void setMirror(bool mirror) { _mirror = mirror; }
bool isMirrored() { return _mirror; };
// Wing geometry:
void setBase(float* base); // in local coordinates
void setLength(float length); // dist. ALONG wing (not span!)
void setChord(float chord); // at base, measured along X axis
void setTaper(float taper); // fraction, 0-1
void setSweep(float sweep); // radians
void setDihedral(float dihedral); // radians, positive is "up"
// Wing geometry in local coordinates:
// base point of wing
void setBase(const float* base) { Math::set3(base, _base); }
void getBase(float* base) { Math::set3(_base, base); };
// dist. ALONG wing (not span!)
void setLength(float length) { _length = length; }
float getLength() { return _length; };
// at base, measured along X axis
void setChord(float chord) { _chord = chord; }
float getChord() { return _chord; };
// fraction of chord at wing tip, 0..1
void setTaper(float taper) { _taper = taper; }
float getTaper() { return _taper; };
// radians
void setSweep(float sweep) { _sweep = sweep; }
float getSweep() { return _sweep; };
// radians, positive is "up"
void setDihedral(float dihedral) { _dihedral = dihedral; }
float getDihedral() { return _dihedral; };
void setStall(float aoa);
void setStallWidth(float angle);
void setStallPeak(float fraction);
void setTwist(float angle);
void setCamber(float camber);
void setIncidence(float incidence);
void setTwist(float angle) { _twist = angle; }
// parameters for stall curve
void setStall(float aoa) { _stall = aoa; }
void setStallWidth(float angle) { _stallWidth = angle; }
void setStallPeak(float fraction) { _stallPeak = fraction; }
void setCamber(float camber) { _camber = camber; }
void setInducedDrag(float drag) { _inducedDrag = drag; }
void setFlap0(float start, float end, float lift, float drag);
void setFlap1(float start, float end, float lift, float drag);
void setSpoiler(float start, float end, float lift, float drag);
void setSlat(float start, float end, float aoa, float drag);
void setFlap0Params(float start, float end, float lift, float drag);
void setFlap1Params(float start, float end, float lift, float drag);
void setSpoilerParams(float start, float end, float lift, float drag);
void setSlatParams(float start, float end, float aoa, float drag);
// Set the control axes for the sub-surfaces
void setFlap0(float lval, float rval);
void setFlap1(float lval, float rval);
void setSpoiler(float lval, float rval);
void setSlat(float val);
void setFlap0Pos(float lval, float rval);
void setFlap1Pos(float lval, float rval);
void setSpoilerPos(float lval, float rval);
void setSlatPos(float val);
void setFlap0Effectiveness(float lval);
void setFlap1Effectiveness(float lval);
// Compile the thing into a bunch of Surface objects
void compile();
void getTip(float* tip) { Math::set3(_tip, tip);};
void getTip(float* tip);
// valid only after Wing::compile() was called
float getSpan() { return _wingspan; };
float getArea() { return _wingspan*_meanChord; };
float getAspectRatio() { return _aspectRatio; };
float getSMC() { return _meanChord; };
bool isMirrored();
// Ground effect information
float getGroundEffect(float* posOut);
// Query the list of Surface objects
int numSurfaces();
Surface* getSurface(int n);
float getSurfaceWeight(int n);
int numSurfaces() { return _surfs.size(); }
Surface* getSurface(int n) { return ((SurfRec*)_surfs.get(n))->surface; }
float getSurfaceWeight(int n) { return ((SurfRec*)_surfs.get(n))->weight; }
// The overall drag coefficient for the wing as a whole. Units are
// arbitrary.
void setDragScale(float scale);
float getDragScale();
float getDragScale() { return _dragScale; }
// The ratio of force along the Z (lift) direction of each wing
// segment to that along the X (drag) direction.
void setLiftRatio(float ratio);
float getLiftRatio();
float getLiftRatio() { return _liftRatio; }
private:
void interp(float* v1, float* v2, float frac, float* out);
void interp(const float* v1, const float* v2, const float frac, float* out);
Surface* newSurface(float* pos, float* orient, float chord,
bool flap0, bool flap1, bool slat, bool spoiler);
@ -93,6 +111,12 @@ private:
float _sweep;
float _dihedral;
// calculated from above
float _tip[3];
float _meanChord; // std. mean chord
float _wingspan;
float _aspectRatio;
float _stall;
float _stallWidth;
float _stallPeak;

View file

@ -9,6 +9,7 @@
#include "FGFDM.hpp"
#include "Atmosphere.hpp"
#include "RigidBody.hpp"
#include "Airplane.hpp"
using namespace yasim;
@ -27,9 +28,17 @@ bool fgSetDouble (const char * name, double defaultValue = 0.0) { return 0; }
static const float RAD2DEG = 57.2957795131;
static const float DEG2RAD = 0.0174532925199;
/// knots 2 meters per second
static const float KTS2MPS = 0.514444444444;
enum Config
{
CONFIG_NONE,
CONFIG_APPROACH,
CONFIG_CRUISE,
};
// Generate a graph of lift, drag and L/D against AoA at the specified
// speed and altitude. The result is a space-separated file of
// numbers: "aoa lift drag LD" (aoa in degrees, lift and drag in
@ -40,7 +49,7 @@ static const float KTS2MPS = 0.514444444444;
"dat" using 1:3 with lines title 'drag', \
"dat" using 1:4 with lines title 'LD'
*/
void yasim_graph(Airplane* a, float alt, float kts)
void yasim_graph(Airplane* a, const float alt, const float kts, int cfg = CONFIG_NONE)
{
Model* m = a->getModel();
State s;
@ -48,9 +57,24 @@ void yasim_graph(Airplane* a, float alt, float kts)
m->setAir(Atmosphere::getStdPressure(alt),
Atmosphere::getStdTemperature(alt),
Atmosphere::getStdDensity(alt));
m->getBody()->recalc();
for(int deg=-179; deg<=179; deg++) {
switch (cfg) {
case CONFIG_APPROACH:
a->loadApproachControls();
break;
case CONFIG_CRUISE:
a->loadCruiseControls();
break;
case CONFIG_NONE:
break;
}
//if we fake the properties we could also use FGFDM::getExternalInput()
m->getBody()->recalc();
float cl_max = 0, cd_min = 1e6, ld_max = 0;
int cl_max_deg = 0, cd_min_deg = 0, ld_max_deg = 0;
for(int deg=-15; deg<=90; deg++) {
float aoa = deg * DEG2RAD;
Airplane::setupState(aoa, kts * KTS2MPS, 0 ,&s);
m->getBody()->reset();
@ -63,47 +87,161 @@ void yasim_graph(Airplane* a, float alt, float kts)
float drag = acc[0] * (-1/9.8);
float lift = 1 + acc[2] * (1/9.8);
float ld = lift/drag;
printf("%d %g %g %g\n", deg, lift, drag, lift/drag);
if (cd_min > drag) {
cd_min = drag;
cd_min_deg = deg;
}
if (cl_max < lift) {
cl_max = lift;
cl_max_deg = deg;
}
if (ld_max < ld) {
ld_max= ld;
ld_max_deg = deg;
}
printf("%d %g %g %g\n", deg, lift, drag, ld);
}
printf("# cl_max %g at %d deg\n", cl_max, cl_max_deg);
printf("# cd_min %g at %d deg\n", cd_min, cd_min_deg);
printf("# ld_max %g at %d deg\n", ld_max, ld_max_deg);
}
void yasim_masses(Airplane* a)
{
RigidBody* body = a->getModel()->getBody();
int i, N = body->numMasses();
float pos[3];
float m, mass = 0;
printf("id posx posy posz mass\n");
for (i = 0; i < N; i++)
{
body->getMassPosition(i, pos);
m = body->getMass(i);
printf("%d %.3f %.3f %.3f %.3f\n", i, pos[0], pos[1], pos[2], m);
mass += m;
}
printf("Total mass: %g", mass);
}
void yasim_drag(Airplane* a, const float aoa, const float alt, int cfg = CONFIG_NONE)
{
fprintf(stderr,"yasim_drag");
Model* m = a->getModel();
State s;
m->setAir(Atmosphere::getStdPressure(alt),
Atmosphere::getStdTemperature(alt),
Atmosphere::getStdDensity(alt));
switch (cfg) {
case CONFIG_APPROACH:
a->loadApproachControls();
break;
case CONFIG_CRUISE:
a->loadCruiseControls();
break;
case CONFIG_NONE:
break;
}
m->getBody()->recalc();
float cd_min = 1e6;
int cd_min_kts = 0;
printf("#kts, drag\n");
for(int kts=15; kts<=150; kts++) {
Airplane::setupState(aoa, kts * KTS2MPS, 0 ,&s);
m->getBody()->reset();
m->initIteration();
m->calcForces(&s);
float acc[3];
m->getBody()->getAccel(acc);
Math::tmul33(s.orient, acc, acc);
float drag = acc[0] * (-1/9.8);
if (cd_min > drag) {
cd_min = drag;
cd_min_kts = kts;
}
printf("%d %g\n", kts, drag);
}
printf("# cd_min %g at %d kts\n", cd_min, cd_min_kts);
}
int usage()
{
fprintf(stderr, "Usage: yasim <ac.xml> [-g [-a alt] [-s kts]]\n");
fprintf(stderr, "Usage: \n");
fprintf(stderr, " yasim <aircraft.xml> [-g [-a meters] [-s kts] [-approach | -cruise] ]\n");
fprintf(stderr, " yasim <aircraft.xml> [-d [-a meters] [-approach | -cruise] ]\n");
fprintf(stderr, " yasim <aircraft.xml> [-m]\n");
fprintf(stderr, " -g print lift/drag table: aoa, lift, drag, lift/drag \n");
fprintf(stderr, " -d print drag over TAS: kts, drag\n");
fprintf(stderr, " -a set altitude in meters!\n");
fprintf(stderr, " -s set speed in knots\n");
fprintf(stderr, " -m print mass distribution table: id, x, y, z, mass \n");
return 1;
}
int main(int argc, char** argv)
{
FGFDM* fdm = new FGFDM();
Airplane* a = fdm->getAirplane();
if(argc < 2) return usage();
// Read
try {
string file = argv[1];
readXML(SGPath(file), *fdm);
} catch (const sg_exception &e) {
printf("XML parse error: %s (%s)\n",
e.getFormattedMessage().c_str(), e.getOrigin());
}
catch (const sg_exception &e) {
printf("XML parse error: %s (%s)\n", e.getFormattedMessage().c_str(), e.getOrigin());
}
// ... and run
a->compile();
if(a->getFailureMsg())
printf("SOLUTION FAILURE: %s\n", a->getFailureMsg());
if(!a->getFailureMsg() && argc > 2 && strcmp(argv[2], "-g") == 0) {
if(!a->getFailureMsg() && argc > 2 ) {
if(strcmp(argv[2], "-g") == 0) {
float alt = 5000, kts = 100;
int cfg = CONFIG_NONE;
for(int i=3; i<argc; i++) {
if (std::strcmp(argv[i], "-a") == 0) alt = std::atof(argv[++i]);
else if(std::strcmp(argv[i], "-s") == 0) kts = std::atof(argv[++i]);
if (std::strcmp(argv[i], "-a") == 0) {
if (i+1 < argc) alt = std::atof(argv[++i]);
}
else if(std::strcmp(argv[i], "-s") == 0) {
if(i+1 < argc) kts = std::atof(argv[++i]);
}
else if(std::strcmp(argv[i], "-approach") == 0) cfg = CONFIG_APPROACH;
else if(std::strcmp(argv[i], "-cruise") == 0) cfg = CONFIG_CRUISE;
else return usage();
}
yasim_graph(a, alt, kts);
} else {
yasim_graph(a, alt, kts, cfg);
}
else if(strcmp(argv[2], "-d") == 0) {
float alt = 2000, aoa = a->getCruiseAoA();
int cfg = CONFIG_NONE;
for(int i=3; i<argc; i++) {
if (std::strcmp(argv[i], "-a") == 0) {
if (i+1 < argc) alt = std::atof(argv[++i]);
}
else if(std::strcmp(argv[i], "-approach") == 0) cfg = CONFIG_APPROACH;
else if(std::strcmp(argv[i], "-cruise") == 0) cfg = CONFIG_CRUISE;
else return usage();
}
yasim_drag(a, aoa, alt, cfg);
}
else if(strcmp(argv[2], "-m") == 0) {
yasim_masses(a);
}
}
else {
printf("Solution results:");
float aoa = a->getCruiseAoA() * RAD2DEG;
float tail = -1 * a->getTailIncidence() * RAD2DEG;
float drag = 1000 * a->getDragCoefficient();
@ -114,7 +252,6 @@ int main(int argc, char** argv)
float SI_inertia[9];
a->getModel()->getBody()->getInertiaMatrix(SI_inertia);
printf("Solution results:");
printf(" Iterations: %d\n", a->getSolutionIterations());
printf(" Drag Coefficient: %f\n", drag);
printf(" Lift Ratio: %f\n", a->getLiftRatio());
@ -122,9 +259,10 @@ int main(int argc, char** argv)
printf(" Tail Incidence: %f\n", tail);
printf("Approach Elevator: %f\n", a->getApproachElevator());
printf(" CG: x:%.3f, y:%.3f, z:%.3f\n\n", cg[0], cg[1], cg[2]);
printf(" Inertia tensor : %.3f, %.3f, %.3f\n", SI_inertia[0], SI_inertia[1], SI_inertia[2]);
printf(" [kg*m^2] %.3f, %.3f, %.3f\n", SI_inertia[3], SI_inertia[4], SI_inertia[5]);
printf(" Origo at CG %.3f, %.3f, %.3f\n", SI_inertia[6], SI_inertia[7], SI_inertia[8]);
printf("Inertia tensor [kg*m^2], origo at CG:\n");
printf(" %7.3f, %7.3f, %7.3f\n", SI_inertia[0], SI_inertia[1], SI_inertia[2]);
printf(" %7.3f, %7.3f, %7.3f\n", SI_inertia[3], SI_inertia[4], SI_inertia[5]);
printf(" %7.3f, %7.3f, %7.3f\n", SI_inertia[6], SI_inertia[7], SI_inertia[8]);
}
delete fdm;
return 0;

View file

@ -67,7 +67,6 @@
#include <Main/globals.hxx>
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
#include "flight.hxx"
@ -330,7 +329,7 @@ FGGroundCache::prepare_ground_cache(double startSimTime, double endSimTime,
SGGeod geodPt = SGGeod::fromCart(pt);
// Don't blow away the cache ground_radius and stuff if there's no
// scenery
if (!globals->get_tile_mgr()->schedule_scenery(geodPt, rad, 1.0)) {
if (!globals->get_scenery()->schedule_scenery(geodPt, rad, 1.0)) {
SG_LOG(SG_FLIGHT, SG_BULK, "prepare_ground_cache(): scenery_available "
"returns false at " << geodPt << " " << pt << " " << rad);
return false;

View file

@ -59,6 +59,12 @@ CatalogRef AddCatalogDialog::addedCatalog()
return m_result;
}
void AddCatalogDialog::setNonInteractiveMode()
{
m_nonInteractiveMode = true;
ui->buttonBox->hide();
}
void AddCatalogDialog::setUrlAndDownload(QUrl url)
{
m_catalogUrl = url;
@ -199,6 +205,10 @@ void AddCatalogDialog::onCatalogStatusChanged(Catalog* cat)
}
ui->stack->setCurrentIndex(STATE_FINISHED);
if (m_nonInteractiveMode) {
QDialog::accept(); // we're done
}
updateUi();
}

View file

@ -42,6 +42,13 @@ public:
simgear::pkg::CatalogRef addedCatalog();
/**
* @brief setNonInteractiveMode - display progres but don't wait for user
* interaction at all. (Hides the buttons, closes autoamtically on success
* or failure)
*/
void setNonInteractiveMode();
void setUrlAndDownload(QUrl url);
private slots:
virtual void reject();
@ -69,6 +76,7 @@ private:
simgear::pkg::RootRef m_packageRoot;
QUrl m_catalogUrl;
simgear::pkg::CatalogRef m_result;
bool m_nonInteractiveMode = false;
};
#endif // FG_GUI_ADDCATALOGDIALOG_HXX

View file

@ -46,6 +46,8 @@ AircraftItemDelegate::AircraftItemDelegate(QListView* view) :
m_leftArrowIcon.load(":/left-arrow-icon");
m_rightArrowIcon.load(":/right-arrow-icon");
m_openPreviewsIcon.load(":/preview-icon");
m_openPreviewsIcon = m_openPreviewsIcon.scaled(32, 32, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
void AircraftItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option,
@ -79,15 +81,22 @@ void AircraftItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem
painter->drawLine(option.rect.topLeft(), option.rect.topRight());
}
// thumbnail
QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
quint32 yPos = contentRect.center().y() - (thumbnail.height() / 2);
painter->drawPixmap(contentRect.left(), yPos, thumbnail);
// draw 1px frame
QRect thumbFrame(contentRect.left(), yPos, thumbnail.width(), thumbnail.height());
painter->setPen(QColor(0x7f, 0x7f, 0x7f));
painter->setBrush(Qt::NoBrush);
painter->drawRect(contentRect.left(), yPos, thumbnail.width(), thumbnail.height());
painter->drawRect(thumbFrame);
if (!index.data(AircraftPreviewsRole).toList().empty()) {
QRect previewIconRect = m_openPreviewsIcon.rect();
previewIconRect.moveBottomLeft(thumbFrame.bottomLeft());
painter->drawPixmap(previewIconRect, m_openPreviewsIcon);
}
// draw bottom dividing line
painter->drawLine(contentRect.left(), contentRect.bottom() + MARGIN,
@ -337,6 +346,13 @@ bool AircraftItemDelegate::eventFilter( QObject*, QEvent* event )
return true;
}
if ((event->type() == QEvent::MouseButtonRelease) &&
!index.data(AircraftPreviewsRole).toList().empty() &&
showPreviewsRect(vr, index).contains(me->pos()))
{
emit showPreviews(index);
}
} else if ( event->type() == QEvent::MouseMove ) {
}
@ -381,6 +397,18 @@ QRect AircraftItemDelegate::packageButtonRect(const QRect& visualRect, const QMo
BUTTON_WIDTH, BUTTON_HEIGHT);
}
QRect AircraftItemDelegate::showPreviewsRect(const QRect& visualRect, const QModelIndex& index) const
{
QRect contentRect = visualRect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
const quint32 yPos = contentRect.center().y() - (thumbnail.height() / 2);
QRect thumbFrame(contentRect.left(), yPos, thumbnail.width(), thumbnail.height());
QRect previewIconRect = m_openPreviewsIcon.rect();
previewIconRect.moveBottomLeft(thumbFrame.bottomLeft());
return previewIconRect;
}
void AircraftItemDelegate::drawRating(QPainter* painter, QString label, const QRect& box, int value) const
{
QRect dotBox = box;

View file

@ -50,17 +50,23 @@ Q_SIGNALS:
void requestUninstall(const QModelIndex& index);
void cancelDownload(const QModelIndex& index);
void showPreviews(const QModelIndex& index);
private:
QRect leftCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const;
QRect rightCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const;
QRect packageButtonRect(const QRect& visualRect, const QModelIndex& index) const;
QRect showPreviewsRect(const QRect& visualRect, const QModelIndex& index) const;
void drawRating(QPainter* painter, QString label, const QRect& box, int value) const;
QListView* m_view;
QPixmap m_leftArrowIcon,
m_rightArrowIcon;
m_rightArrowIcon,
m_openPreviewsIcon;
};
#endif

View file

@ -40,28 +40,18 @@
// FlightGear
#include <Main/globals.hxx>
const int STANDARD_THUMBNAIL_HEIGHT = 128;
const int STANDARD_THUMBNAIL_WIDTH = 172;
static quint32 CACHE_VERSION = 7;
using namespace simgear::pkg;
AircraftItem::AircraftItem() :
excluded(false),
usesHeliports(false),
usesSeaports(false)
AircraftItem::AircraftItem()
{
// oh for C++11 initialisers
for (int i=0; i<4; ++i) ratings[i] = 0;
}
AircraftItem::AircraftItem(QDir dir, QString filePath) :
excluded(false),
usesHeliports(false),
usesSeaports(false)
AircraftItem::AircraftItem(QDir dir, QString filePath)
{
for (int i=0; i<4; ++i) ratings[i] = 0;
SGPropertyNode root;
readProperties(filePath.toStdString(), &root);
@ -97,6 +87,12 @@ AircraftItem::AircraftItem(QDir dir, QString filePath) :
if (sim->hasChild("variant-of")) {
variantOf = sim->getStringValue("variant-of");
} else {
isPrimary = true;
}
if (sim->hasChild("primary-set")) {
isPrimary = sim->getBoolValue("primary-set");
}
if (sim->hasChild("tags")) {
@ -113,6 +109,22 @@ AircraftItem::AircraftItem(QDir dir, QString filePath) :
}
} // of tags iteration
} // of set-xml has tags
if (sim->hasChild("previews")) {
SGPropertyNode_ptr previewsNode = sim->getChild("previews");
for (auto previewNode : previewsNode->getChildren("preview")) {
// add file path as url
QString pathInXml = QString::fromStdString(previewNode->getStringValue("path"));
QString previewPath = dir.absoluteFilePath(pathInXml);
previews.append(QUrl::fromLocalFile(previewPath));
}
}
if (sim->hasChild("thumbnail")) {
thumbnailPath = sim->getStringValue("thumbnail");
} else {
thumbnailPath = "thumbnail.jpg";
}
}
QString AircraftItem::baseName() const
@ -129,8 +141,10 @@ void AircraftItem::fromDataStream(QDataStream& ds)
return;
}
ds >> description >> longDescription >> authors >> variantOf;
ds >> description >> longDescription >> authors >> variantOf >> isPrimary;
for (int i=0; i<4; ++i) ds >> ratings[i];
ds >> previews;
ds >> thumbnailPath;
}
void AircraftItem::toDataStream(QDataStream& ds) const
@ -140,8 +154,10 @@ void AircraftItem::toDataStream(QDataStream& ds) const
return;
}
ds << description << longDescription << authors << variantOf;
ds << description << longDescription << authors << variantOf << isPrimary;
for (int i=0; i<4; ++i) ds << ratings[i];
ds << previews;
ds << thumbnailPath;
}
QPixmap AircraftItem::thumbnail(bool loadIfRequired) const
@ -149,8 +165,8 @@ QPixmap AircraftItem::thumbnail(bool loadIfRequired) const
if (m_thumbnail.isNull() && loadIfRequired) {
QFileInfo info(path);
QDir dir = info.dir();
if (dir.exists("thumbnail.jpg")) {
m_thumbnail.load(dir.filePath("thumbnail.jpg"));
if (dir.exists(thumbnailPath)) {
m_thumbnail.load(dir.filePath(thumbnailPath));
// resize to the standard size
if (m_thumbnail.height() > STANDARD_THUMBNAIL_HEIGHT) {
m_thumbnail = m_thumbnail.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT, Qt::SmoothTransformation);
@ -161,9 +177,6 @@ QPixmap AircraftItem::thumbnail(bool loadIfRequired) const
return m_thumbnail;
}
static quint32 CACHE_VERSION = 5;
class AircraftScanThread : public QThread
{
Q_OBJECT
@ -284,7 +297,7 @@ private:
continue;
}
if (item->variantOf.isNull()) {
if (item->isPrimary) {
baseAircraft.insert(item->baseName(), item);
} else {
variants.append(item);
@ -402,14 +415,22 @@ protected:
if (pix.height() > STANDARD_THUMBNAIL_HEIGHT) {
pix = pix.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT, Qt::SmoothTransformation);
}
m_model->m_thumbnailPixmapCache.insert(QString::fromStdString(aThumbnailUrl), pix);
// notify any affected items. Linear scan here avoids another map/dict
// structure.
m_model->m_downloadedPixmapCache.insert(QString::fromStdString(aThumbnailUrl), pix);
// notify any affected items. Linear scan here avoids another map/dict structure.
for (auto pkg : m_model->m_packages) {
const string_list& urls(pkg->thumbnailUrls());
auto cit = std::find(urls.begin(), urls.end(), aThumbnailUrl);
if (cit != urls.end()) {
const int variantCount = pkg->variants().size();
bool notifyChanged = false;
for (int v=0; v < variantCount; ++v) {
const Package::Thumbnail& thumb(pkg->thumbnailForVariant(v));
if (thumb.url == aThumbnailUrl) {
notifyChanged = true;
}
}
if (notifyChanged) {
QModelIndex mi = indexForPackage(pkg);
m_model->dataChanged(mi, mi);
}
@ -432,7 +453,7 @@ private:
AircraftItemModel* m_model;
};
AircraftItemModel::AircraftItemModel(QObject* pr ) :
AircraftItemModel::AircraftItemModel(QObject* pr) :
QAbstractListModel(pr)
{
}
@ -593,10 +614,6 @@ QVariant AircraftItemModel::data(const QModelIndex& index, int role) const
return m_delegateStates.at(row).variant;
}
if (role == AircraftCurrentThumbnailRole) {
return m_delegateStates.at(row).thumbnail;
}
if (row >= m_items.size()) {
quint32 packageIndex = row - m_items.size();
const PackageRef& pkg(m_packages[packageIndex]);
@ -623,20 +640,7 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
return item->variants.count();
}
if (role == AircraftThumbnailCountRole) {
QPixmap p = item->thumbnail();
return p.isNull() ? 0 : 1;
}
if (role == AircraftThumbnailSizeRole) {
QPixmap pm = item->thumbnail(false);
if (pm.isNull()) {
return QSize(STANDARD_THUMBNAIL_WIDTH, STANDARD_THUMBNAIL_HEIGHT);
}
return pm.size();
}
if ((role >= AircraftVariantDescriptionRole) && (role < AircraftThumbnailRole)) {
if (role >= AircraftVariantDescriptionRole) {
int variantIndex = role - AircraftVariantDescriptionRole;
return item->variants.at(variantIndex)->description;
}
@ -648,6 +652,14 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
}
}
if (role == AircraftThumbnailSizeRole) {
QPixmap pm = item->thumbnail(false);
if (pm.isNull()) {
return QSize(STANDARD_THUMBNAIL_WIDTH, STANDARD_THUMBNAIL_HEIGHT);
}
return pm.size();
}
if (role == Qt::DisplayRole) {
if (item->description.isEmpty()) {
return tr("Missing description for: %1").arg(item->baseName());
@ -662,7 +674,13 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
return item->authors;
} else if ((role >= AircraftRatingRole) && (role < AircraftVariantDescriptionRole)) {
return item->ratings[role - AircraftRatingRole];
} else if (role >= AircraftThumbnailRole) {
} else if (role == AircraftPreviewsRole) {
QVariantList result;
Q_FOREACH(QUrl u, item->previews) {
result.append(u);
}
return result;
} else if (role == AircraftThumbnailRole) {
return item->thumbnail();
} else if (role == AircraftPackageIdRole) {
// can we fake an ID? otherwise fall through to a null variant
@ -692,10 +710,10 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, const DelegateState& state, int role) const
{
if (role == Qt::DecorationRole) {
role = AircraftThumbnailRole; // use first thumbnail
role = AircraftThumbnailRole;
}
if ((role >= AircraftVariantDescriptionRole) && (role < AircraftThumbnailRole)) {
if (role >= AircraftVariantDescriptionRole) {
int variantIndex = role - AircraftVariantDescriptionRole;
QString desc = QString::fromStdString(item->nameForVariant(variantIndex));
if (desc.isEmpty()) {
@ -743,11 +761,10 @@ QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, const Delega
if (pm.isNull())
return QSize(STANDARD_THUMBNAIL_WIDTH, STANDARD_THUMBNAIL_HEIGHT);
return pm.size();
} else if (role >= AircraftThumbnailRole) {
DelegateState changedState(state);
// override the current thumbnail as required
changedState.thumbnail = (role - AircraftThumbnailRole);
return packageThumbnail(item, changedState);
} else if (role == AircraftThumbnailRole) {
return packageThumbnail(item, state);
} else if (role == AircraftPreviewsRole) {
return packagePreviews(item, state);
} else if (role == AircraftAuthorsRole) {
std::string authors = item->getLocalisedProp("author", state.variant);
if (!authors.empty()) {
@ -776,46 +793,69 @@ QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, const Delega
QVariant AircraftItemModel::packageThumbnail(PackageRef p, const DelegateState& ds, bool download) const
{
const string_list& thumbnails(p->thumbnailUrls());
if (ds.thumbnail >= static_cast<int>(thumbnails.size())) {
const Package::Thumbnail& thumb(p->thumbnailForVariant(ds.variant));
if (thumb.url.empty()) {
return QVariant();
}
std::string thumbnailUrl = thumbnails.at(ds.thumbnail);
QString urlQString(QString::fromStdString(thumbnailUrl));
if (m_thumbnailPixmapCache.contains(urlQString)) {
QString urlQString(QString::fromStdString(thumb.url));
if (m_downloadedPixmapCache.contains(urlQString)) {
// cache hit, easy
return m_thumbnailPixmapCache.value(urlQString);
return m_downloadedPixmapCache.value(urlQString);
}
// check the on-disk store. This relies on the order of thumbnails in the
// results of thumbnailUrls and thumbnails corresponding
// check the on-disk store.
InstallRef ex = p->existingInstall();
if (ex.valid()) {
const string_list& thumbNames(p->thumbnails());
if (!thumbNames.empty()) {
SGPath path(ex->path());
path.append(p->thumbnails()[ds.thumbnail]);
if (path.exists()) {
SGPath thumbPath = ex->path() / thumb.path;
if (thumbPath.exists()) {
QPixmap pix;
pix.load(QString::fromStdString(path.utf8Str()));
pix.load(QString::fromStdString(thumbPath.utf8Str()));
// resize to the standard size
if (pix.height() > STANDARD_THUMBNAIL_HEIGHT) {
pix = pix.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT);
}
m_thumbnailPixmapCache[urlQString] = pix;
m_downloadedPixmapCache[urlQString] = pix;
return pix;
}
} // of have thumbnail file names
} // of have existing install
if (download) {
m_packageRoot->requestThumbnailData(thumbnailUrl);
m_packageRoot->requestThumbnailData(thumb.url);
}
return QVariant();
}
QVariant AircraftItemModel::packagePreviews(PackageRef p, const DelegateState& ds) const
{
const Package::PreviewVec& previews = p->previewsForVariant(ds.variant);
if (previews.empty()) {
return QVariant();
}
QVariantList result;
// if we have an install, return file URLs, not remote (http) ones
InstallRef ex = p->existingInstall();
if (ex.valid()) {
for (auto p : previews) {
SGPath localPreviewPath = ex->path() / p.path;
if (!localPreviewPath.exists()) {
qWarning() << "missing local preview" << QString::fromStdString(localPreviewPath.utf8Str());
continue;
}
result.append(QUrl::fromLocalFile(QString::fromStdString(localPreviewPath.utf8Str())));
}
}
// return remote urls
for (auto p : previews) {
result.append(QUrl(QString::fromStdString(p.url)));
}
return result;
}
bool AircraftItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
int row = index.row();
@ -831,16 +871,6 @@ bool AircraftItemModel::setData(const QModelIndex &index, const QVariant &value,
return true;
}
if (role == AircraftCurrentThumbnailRole) {
if (m_delegateStates[row].thumbnail == newValue) {
return true;
}
m_delegateStates[row].thumbnail = newValue;
emit dataChanged(index, index);
return true;
}
return false;
}

View file

@ -38,7 +38,6 @@ const int AircraftPathRole = Qt::UserRole + 1;
const int AircraftAuthorsRole = Qt::UserRole + 2;
const int AircraftVariantRole = Qt::UserRole + 3;
const int AircraftVariantCountRole = Qt::UserRole + 4;
const int AircraftThumbnailCountRole = Qt::UserRole + 5;
const int AircraftPackageIdRole = Qt::UserRole + 6;
const int AircraftPackageStatusRole = Qt::UserRole + 7;
const int AircraftPackageProgressRole = Qt::UserRole + 8;
@ -51,12 +50,12 @@ const int AircraftURIRole = Qt::UserRole + 14;
const int AircraftThumbnailSizeRole = Qt::UserRole + 15;
const int AircraftIsHelicopterRole = Qt::UserRole + 16;
const int AircraftIsSeaplaneRole = Qt::UserRole + 17;
const int AircraftCurrentThumbnailRole = Qt::UserRole + 18;
const int AircraftPackageRefRole = Qt::UserRole + 19;
const int AircraftThumbnailRole = Qt::UserRole + 20;
const int AircraftPreviewsRole = Qt::UserRole + 21;
const int AircraftRatingRole = Qt::UserRole + 100;
const int AircraftVariantDescriptionRole = Qt::UserRole + 200;
const int AircraftThumbnailRole = Qt::UserRole + 300;
class AircraftScanThread;
class QDataStream;
@ -81,17 +80,20 @@ struct AircraftItem
QPixmap thumbnail(bool loadIfRequired = true) const;
bool excluded;
bool excluded = false;
QString path;
QString description;
QString longDescription;
QString authors;
int ratings[4];
int ratings[4] = {0, 0, 0, 0};
QString variantOf;
QDateTime pathModTime;
QList<AircraftItemPtr> variants;
bool usesHeliports;
bool usesSeaports;
bool usesHeliports = false;
bool usesSeaports = false;
QList<QUrl> previews;
bool isPrimary = false;
QString thumbnailPath;
private:
mutable QPixmap m_thumbnail;
};
@ -199,6 +201,8 @@ private:
QVariant packageThumbnail(simgear::pkg::PackageRef p,
const DelegateState& state, bool download = true) const;
QVariant packagePreviews(simgear::pkg::PackageRef p, const DelegateState &ds) const;
void abandonCurrentScan();
void refreshPackages();
@ -217,7 +221,7 @@ private:
simgear::pkg::RootRef m_packageRoot;
simgear::pkg::PackageList m_packages;
mutable QHash<QString, QPixmap> m_thumbnailPixmapCache;
mutable QHash<QString, QPixmap> m_downloadedPixmapCache;
};
#endif // of FG_GUI_AIRCRAFT_MODEL

View file

@ -189,7 +189,8 @@ void AirportDiagram::addRunway(FGRunwayRef rwy)
r.runway = rwy;
m_runways.append(r);
recomputeBounds(false);
extendBounds(r.p1);
extendBounds(r.p2);
update();
}
@ -224,7 +225,7 @@ void AirportDiagram::addParking(FGParkingRef park)
{
ParkingData pd = { project(park->geod()), park };
m_parking.push_back(pd);
recomputeBounds(false);
extendBounds(pd.pt);
update();
}
@ -232,7 +233,7 @@ void AirportDiagram::addHelipad(FGHelipadRef pad)
{
HelipadData pd = { project(pad->geod()), pad };
m_helipads.push_back(pd);
recomputeBounds(false);
extendBounds(pd.pt);
update();
}

View file

@ -587,6 +587,17 @@ void BaseDiagram::doComputeBounds()
void BaseDiagram::extendBounds(const QPointF& p)
{
// this check added after a bug where apt.dat reports SCSL as
// https://airportguide.com/airport/info/AG0003 (British Columbia)
// but the groundnet is for
// https://en.wikipedia.org/wiki/Salar_de_Atacama_Airport
// causing a rather large airport boundary.
QPointF v = (p - m_bounds.center());
if (v.manhattanLength() > 20000) {
qWarning() << "Excessively distant point" << p << v.manhattanLength();
return;
}
extendRect(m_bounds, p);
}

View file

@ -117,11 +117,13 @@ if (HAVE_QT)
InstallSceneryDialog.cxx
EditCustomMPServerDialog.cxx
EditCustomMPServerDialog.hxx
previewwindow.cpp
previewwindow.h
${uic_sources}
${qrc_sources})
set_property(TARGET fglauncher PROPERTY AUTOMOC ON)
target_link_libraries(fglauncher Qt5::Core Qt5::Widgets SimGearCore)
target_link_libraries(fglauncher Qt5::Core Qt5::Widgets Qt5::Network SimGearCore)
target_include_directories(fglauncher PRIVATE ${PROJECT_BINARY_DIR}/src/GUI)

View file

@ -34,7 +34,7 @@
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="summaryTab">
<attribute name="title">
@ -698,4 +698,4 @@
<include location="resources.qrc"/>
</resources>
<connections/>
</ui>
</ui>

View file

@ -536,7 +536,7 @@ void LocationWidget::setLocationProperties()
QStringList props = QStringList() << "vor-id" << "fix" << "ndb-id" <<
"runway-requested" << "navaid-id" << "offset-azimuth-deg" <<
"offset-distance-nm" << "glideslope-deg" <<
"speed-set" << "on-ground" << "airspeed-kt" << "heading-deg" <<
"speed-set" << "on-ground" << "airspeed-kt" <<
"airport-id" << "runway" << "parkpos";
Q_FOREACH(QString s, props) {
@ -556,10 +556,10 @@ void LocationWidget::setLocationProperties()
return;
}
fgSetDouble("/sim/presets/latitude-deg", -9999.0);
fgSetDouble("/sim/presets/longitude-deg", -9999.0);
fgSetDouble("/sim/presets/latitude-deg", 9999.0);
fgSetDouble("/sim/presets/longitude-deg", 9999.0);
fgSetDouble("/sim/presets/altitude-ft", -9999.0);
fgSetDouble("/sim/presets/heading-deg", 9999.0);
if (!m_location) {
return;
@ -569,6 +569,7 @@ void LocationWidget::setLocationProperties()
FGAirport* apt = static_cast<FGAirport*>(m_location.ptr());
fgSetString("/sim/presets/airport-id", apt->ident());
fgSetBool("/sim/presets/on-ground", true);
fgSetBool("/sim/presets/airport-requested", true);
if (m_ui->runwayRadio->isChecked()) {
if (apt->type() == FGPositioned::AIRPORT) {

View file

@ -105,15 +105,24 @@ void AddOnsPage::onAddSceneryPath()
// validation
SGPath p(path.toStdString());
SGPath objectsPath = p / "Objects";
SGPath terrainPath = p / "Terrain";
bool isValid = false;
if (!objectsPath.exists() && !terrainPath.exists()) {
for (const auto& dir: {"Objects", "Terrain", "Buildings", "Roads",
"Pylons", "NavData"}) {
if ((p / dir).exists()) {
isValid = true;
break;
}
}
if (!isValid) {
QMessageBox mb;
mb.setText(QString("The folder '%1' doesn't appear to contain scenery - add anyway?").arg(path));
mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
mb.setDefaultButton(QMessageBox::No);
mb.setInformativeText("Added scenery should contain folders called 'Objects' and / or 'Terrain'");
mb.setInformativeText(
"Added scenery should contain at least one of the following "
"folders: Objects, Terrain, Buildings, Roads, Pylons, NavData.");
mb.exec();
if (mb.result() == QMessageBox::No) {
@ -124,11 +133,6 @@ void AddOnsPage::onAddSceneryPath()
m_ui->sceneryPathsList->addItem(path);
saveSceneryPaths();
}
// work around a Qt OS-X bug - this dialog is ending ordered
// behind the main settings dialog (consequence of modal-dialog
// showing a modla dialog showing a modial dialog)
window()->raise();
}
void AddOnsPage::onRemoveSceneryPath()
@ -175,11 +179,8 @@ void AddOnsPage::onAddAircraftPath()
}
saveAircraftPaths();
emit aircraftPathsChanged();
}
// work around a Qt OS-X bug - this dialog is ending ordered
// behind the main settings dialog (consequence of modal-dialog
// showing a modla dialog showing a modial dialog)
window()->raise();
}
void AddOnsPage::onRemoveAircraftPath()
@ -187,6 +188,7 @@ void AddOnsPage::onRemoveAircraftPath()
if (m_ui->aircraftPathsList->currentItem()) {
delete m_ui->aircraftPathsList->currentItem();
saveAircraftPaths();
emit aircraftPathsChanged();
}
}
@ -237,13 +239,13 @@ void AddOnsPage::onAddCatalog()
void AddOnsPage::onAddDefaultCatalog()
{
addDefaultCatalog(this);
addDefaultCatalog(this, false /* not silent */);
m_catalogsModel->refresh();
updateUi();
}
void AddOnsPage::addDefaultCatalog(QWidget* pr)
void AddOnsPage::addDefaultCatalog(QWidget* pr, bool silent)
{
// check it's not a duplicate somehow
FGHTTPClient* http = globals->get_subsystem<FGHTTPClient>();
@ -252,6 +254,9 @@ void AddOnsPage::addDefaultCatalog(QWidget* pr)
QScopedPointer<AddCatalogDialog> dlg(new AddCatalogDialog(pr, globals->packageRoot()));
QUrl url(QString::fromStdString(http->getDefaultCatalogUrl()));
if (silent) {
dlg->setNonInteractiveMode();
}
dlg->setUrlAndDownload(url);
dlg->exec();

View file

@ -20,11 +20,12 @@ public:
explicit AddOnsPage(QWidget *parent, simgear::pkg::RootRef root);
~AddOnsPage();
static void addDefaultCatalog(QWidget* pr);
static void addDefaultCatalog(QWidget* pr, bool silent);
signals:
void downloadDirChanged();
void sceneryPathsChanged();
void aircraftPathsChanged();
private slots:
void onAddSceneryPath();

View file

@ -69,6 +69,7 @@
#include "AircraftModel.hxx"
#include "PathsDialog.hxx"
#include "EditCustomMPServerDialog.hxx"
#include "previewwindow.h"
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
@ -696,6 +697,20 @@ bool runLauncherDialog()
// try to initialise various Cocoa structures.
flightgear::WindowBuilder::setPoseAsStandaloneApp(false);
if (!settings.contains("initial-default-hangar-added")) {
settings.setValue("initial-default-hangar-added", true);
// ensure subsystems get updated while the dialog is running; we don't
// yet have the QtLauncher window's pump installed
QTimer subsystemPump;
subsystemPump.setInterval(0);
QObject::connect(&subsystemPump, &QTimer::timeout, [](){ globals->get_subsystem_mgr()->update(0.0); });
subsystemPump.start();
// will only add if needed
AddOnsPage::addDefaultCatalog(nullptr, true /* silent */);
}
QtLauncher dlg;
dlg.show();
@ -840,6 +855,8 @@ QtLauncher::QtLauncher() :
this, &QtLauncher::onRequestPackageUninstall);
connect(delegate, &AircraftItemDelegate::cancelDownload,
this, &QtLauncher::onCancelDownload);
connect(delegate, &AircraftItemDelegate::showPreviews,
this, &QtLauncher::onShowPreviews);
connect(m_aircraftModel, &AircraftItemModel::aircraftInstallCompleted,
this, &QtLauncher::onAircraftInstalledCompleted);
@ -856,6 +873,8 @@ QtLauncher::QtLauncher() :
this, &QtLauncher::onDownloadDirChanged);
connect(addOnsPage, &AddOnsPage::sceneryPathsChanged,
this, &QtLauncher::setSceneryPaths);
connect(addOnsPage, &AddOnsPage::aircraftPathsChanged,
this, &QtLauncher::onAircraftPathsChanged);
m_ui->tabWidget->addTab(addOnsPage, tr("Add-ons"));
// after any kind of reset, try to restore selection and scroll
@ -1202,6 +1221,11 @@ void QtLauncher::onRun()
if (a.arg.startsWith("prop:")) {
QString v = a.arg.mid(5) + "=" + a.value;
opt->addOption("prop", v.toStdString());
} else if (a.arg == "console") {
// this option is handled very early, in normal startup. If the user
// requests it via the launcher, parseOptions never sees it, so
// achieve the same result manually.
simgear::requestConsole();
} else {
opt->addOption(a.arg.toStdString(), a.value.toStdString());
}
@ -1385,6 +1409,14 @@ void QtLauncher::onRequestPackageUninstall(const QModelIndex& index)
}
}
void QtLauncher::onShowPreviews(const QModelIndex &index)
{
QVariant urls = index.data(AircraftPreviewsRole);
PreviewWindow* previewWindow = new PreviewWindow;
previewWindow->setUrls(urls.toList());
}
void QtLauncher::onCancelDownload(const QModelIndex& index)
{
QString pkg = index.data(AircraftPackageIdRole).toString();
@ -1621,8 +1653,9 @@ void QtLauncher::onDownloadDirChanged()
globals->get_subsystem<FGHTTPClient>()->init();
QSettings settings;
// re-scan the aircraft list
QSettings settings;
m_aircraftModel->setPackageRoot(globals->packageRoot());
m_aircraftModel->setPaths(settings.value("aircraft-paths").toStringList());
m_aircraftModel->scanDirs();
@ -1633,6 +1666,13 @@ void QtLauncher::onDownloadDirChanged()
setSceneryPaths();
}
void QtLauncher::onAircraftPathsChanged()
{
QSettings settings;
m_aircraftModel->setPaths(settings.value("aircraft-paths").toStringList());
m_aircraftModel->scanDirs();
}
bool QtLauncher::shouldShowOfficialCatalogMessage() const
{
QSettings settings;
@ -1663,7 +1703,7 @@ void QtLauncher::onOfficialCatalogMessageLink(QUrl link)
QSettings settings;
settings.setValue("hide-official-catalog-message", true);
} else if (s == "action:add-official") {
AddOnsPage::addDefaultCatalog(this);
AddOnsPage::addDefaultCatalog(this, false /* not silent */);
}
checkOfficialCatalogMessage();

View file

@ -75,7 +75,7 @@ private slots:
void onAircraftSelected(const QModelIndex& index);
void onRequestPackageInstall(const QModelIndex& index);
void onRequestPackageUninstall(const QModelIndex& index);
void onShowPreviews(const QModelIndex& index);
void onCancelDownload(const QModelIndex& index);
void onPopupAircraftHistory();
@ -109,6 +109,7 @@ private slots:
void onPackagesNeedUpdate(bool yes);
void onAircraftPathsChanged();
private:
/**

View file

@ -17,13 +17,13 @@ FGMenuBar::~FGMenuBar ()
{
}
const char*
std::string
FGMenuBar::getLocalizedLabel(SGPropertyNode* node)
{
const char* name = node->getStringValue("name", 0);
const char* translated = globals->get_locale()->getLocalizedString(name, "menu");
if (translated)
std::string translated = globals->get_locale()->getLocalizedString(name, "menu");
if (!translated.empty())
return translated;
// return default with fallback to name

View file

@ -3,6 +3,8 @@
#ifndef __MENUBAR_HXX
#define __MENUBAR_HXX 1
#include <string>
class SGPropertyNode;
/**
@ -51,7 +53,7 @@ public:
* Take care of mapping it to the appropriate translation, if available.
* Returns an UTF-8 encoded string.
*/
static const char* getLocalizedLabel(SGPropertyNode* node);
static std::string getLocalizedLabel(SGPropertyNode* node);
};

BIN
src/GUI/preview-close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Some files were not shown because too many files have changed in this diff Show more