Merge branch 'next-2' into multiplayer-dev
This commit is contained in:
commit
c5cc666288
188 changed files with 9190 additions and 4157 deletions
2
3rdparty/sqlite3/CMakeLists.txt
vendored
2
3rdparty/sqlite3/CMakeLists.txt
vendored
|
@ -2,4 +2,4 @@
|
||||||
add_definitions(-DSQLITE_OMIT_LOAD_EXTENSION)
|
add_definitions(-DSQLITE_OMIT_LOAD_EXTENSION)
|
||||||
add_definitions(-DNDEBUG)
|
add_definitions(-DNDEBUG)
|
||||||
add_library(fgsqlite3 sqlite3.c)
|
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")
|
||||||
|
|
|
@ -25,6 +25,13 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||||
"MinSizeRel" "RelWithDebInfo")
|
"MinSizeRel" "RelWithDebInfo")
|
||||||
endif()
|
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)
|
if(APPLE)
|
||||||
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks")
|
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks")
|
||||||
# when building, don't use the install RPATH already
|
# 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_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_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(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
|
# additional utilities
|
||||||
option(ENABLE_FGELEV "Set to ON to build the fgelev application (default)" ON)
|
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_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_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_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)
|
include (DetectArch)
|
||||||
|
|
||||||
|
@ -305,7 +311,7 @@ endif (USE_DBUS)
|
||||||
## Qt5 setup setup
|
## Qt5 setup setup
|
||||||
if (ENABLE_QT)
|
if (ENABLE_QT)
|
||||||
message(STATUS "Qt launcher enabled, checking for Qt 5.1 / qmake")
|
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)
|
if (Qt5Widgets_FOUND)
|
||||||
message(STATUS "Will enable Qt launcher GUI")
|
message(STATUS "Will enable Qt launcher GUI")
|
||||||
message(STATUS " Qt5Widgets version: ${Qt5Widgets_VERSION_STRING}")
|
message(STATUS " Qt5Widgets version: ${Qt5Widgets_VERSION_STRING}")
|
||||||
|
@ -357,6 +363,24 @@ else()
|
||||||
message(STATUS "RTI: DISABLED")
|
message(STATUS "RTI: DISABLED")
|
||||||
endif(ENABLE_RTI)
|
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)
|
if (ENABLE_SIMD)
|
||||||
message(STATUS "SSE/SSE2 support: ENABLED")
|
message(STATUS "SSE/SSE2 support: ENABLED")
|
||||||
else()
|
else()
|
||||||
|
@ -485,6 +509,23 @@ configure_file (
|
||||||
|
|
||||||
add_subdirectory(3rdparty)
|
add_subdirectory(3rdparty)
|
||||||
add_subdirectory(utils)
|
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(src)
|
||||||
add_subdirectory(man)
|
add_subdirectory(man)
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Scenery/scenery.hxx>
|
#include <Scenery/scenery.hxx>
|
||||||
#include <Scenery/tilemgr.hxx>
|
|
||||||
#include <Airports/dynamics.hxx>
|
#include <Airports/dynamics.hxx>
|
||||||
#include <Airports/airport.hxx>
|
#include <Airports/airport.hxx>
|
||||||
#include <Main/util.hxx>
|
#include <Main/util.hxx>
|
||||||
|
@ -551,7 +550,7 @@ void FGAIAircraft::getGroundElev(double dt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
double range = 500.0;
|
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;
|
double alt;
|
||||||
if (getGroundElevationM(SGGeod::fromGeodM(pos, 20000), alt, 0))
|
if (getGroundElevationM(SGGeod::fromGeodM(pos, 20000), alt, 0))
|
||||||
|
|
|
@ -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);
|
sm->pitch_offset = new FGXMLAutopilot::InputValue(*prop_root, b ? *b : n);
|
||||||
if (b) old = true;
|
if (b) old = true;
|
||||||
|
|
||||||
#if defined(ENABLE_DEV_WARNINGS)
|
|
||||||
if (old) {
|
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
|
// Randomness
|
||||||
|
|
|
@ -36,7 +36,7 @@ static string NO_ATIS("nil");
|
||||||
static string EMPTY("");
|
static string EMPTY("");
|
||||||
#define SPACE append(1,' ')
|
#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 );
|
string key = "n" + boost::lexical_cast<std::string>( i );
|
||||||
return globals->get_locale()->getLocalizedString(key.c_str(), "atc", "" );
|
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 )
|
string ATCSpeech::getSpokenNumber( int number, bool leadingZero, int digits )
|
||||||
{
|
{
|
||||||
vector<const char *> spokenDigits;
|
string_list spokenDigits;
|
||||||
bool negative = false;
|
bool negative = false;
|
||||||
if( number < 0 ) {
|
if( number < 0 ) {
|
||||||
negative = true;
|
negative = true;
|
||||||
|
|
|
@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
class ATCSpeech {
|
class ATCSpeech {
|
||||||
public:
|
public:
|
||||||
static const char * getSpokenDigit( int i );
|
static std::string getSpokenDigit( int i );
|
||||||
static std::string getSpokenNumber( std::string number );
|
static std::string getSpokenNumber( std::string number );
|
||||||
static std::string getSpokenNumber( int number, bool leadingZero = false, int digits = 1 );
|
static std::string getSpokenNumber( int number, bool leadingZero = false, int digits = 1 );
|
||||||
static std::string getSpokenAltitude( int altitude );
|
static std::string getSpokenAltitude( int altitude );
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include "CommStation.hxx"
|
#include "CommStation.hxx"
|
||||||
#include <Airports/airport.hxx>
|
#include <Airports/airport.hxx>
|
||||||
#include <Navaids/NavDataCache.hxx>
|
#include <Navaids/NavDataCache.hxx>
|
||||||
|
|
|
@ -724,7 +724,7 @@ void FGAirport::validateILSData()
|
||||||
|
|
||||||
SGPath path;
|
SGPath path;
|
||||||
if (!XMLLoader::findAirportData(ident(), "ils", path)) {
|
if (!XMLLoader::findAirportData(ident(), "ils", path)) {
|
||||||
return; // no XML tower data
|
return; // no XML ILS data
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -99,7 +99,6 @@ void APTLoader::readAptDatFile(const SGPath &aptdb_file,
|
||||||
sg_location(aptdb_file));
|
sg_location(aptdb_file));
|
||||||
}
|
}
|
||||||
|
|
||||||
SG_LOG( SG_GENERAL, SG_INFO, "Opened apt.dat file: '" << apt_dat << "'" );
|
|
||||||
string line;
|
string line;
|
||||||
|
|
||||||
unsigned int rowCode = 0; // terminology used in the apt.dat format spec
|
unsigned int rowCode = 0; // terminology used in the apt.dat format spec
|
||||||
|
|
|
@ -69,7 +69,7 @@ void FGGroundNetXMLLoader::endXML ()
|
||||||
for (it = _parkingPushbacks.begin(); it != _parkingPushbacks.end(); ++it) {
|
for (it = _parkingPushbacks.begin(); it != _parkingPushbacks.end(); ++it) {
|
||||||
NodeIndexMap::const_iterator j = _indexMap.find(it->second);
|
NodeIndexMap::const_iterator j = _indexMap.find(it->second);
|
||||||
if (j == _indexMap.end()) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ void FGGroundNetXMLLoader::endXML ()
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_FOREACH(FGTaxiNodeRef node, _unreferencedNodes) {
|
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()) {
|
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)));
|
SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
|
||||||
|
@ -200,7 +200,7 @@ void FGGroundNetXMLLoader::startArc(const XMLAttributes &atts)
|
||||||
|
|
||||||
IntPair e(begin, end);
|
IntPair e(begin, end);
|
||||||
if (_arcSet.find(e) != _arcSet.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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ void FGGroundNetXMLLoader::startArc(const XMLAttributes &atts)
|
||||||
FGTaxiNodeRef fromNode, toNode;
|
FGTaxiNodeRef fromNode, toNode;
|
||||||
it = _indexMap.find(begin);
|
it = _indexMap.find(begin);
|
||||||
if (it == _indexMap.end()) {
|
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;
|
return;
|
||||||
} else {
|
} else {
|
||||||
_unreferencedNodes.erase(it->second);
|
_unreferencedNodes.erase(it->second);
|
||||||
|
@ -217,7 +217,7 @@ void FGGroundNetXMLLoader::startArc(const XMLAttributes &atts)
|
||||||
|
|
||||||
it = _indexMap.find(end);
|
it = _indexMap.find(end);
|
||||||
if (it == _indexMap.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;
|
return;
|
||||||
} else {
|
} else {
|
||||||
_unreferencedNodes.erase(it->second);
|
_unreferencedNodes.erase(it->second);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include "gnnode.hxx"
|
#include "gnnode.hxx"
|
||||||
|
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
|
|
@ -259,16 +259,16 @@ void FGRouteMgr::init() {
|
||||||
magvar = fgGetNode("/environment/magnetic-variation-deg", true);
|
magvar = fgGetNode("/environment/magnetic-variation-deg", true);
|
||||||
|
|
||||||
departure = fgGetNode(RM "departure", true);
|
departure = fgGetNode(RM "departure", true);
|
||||||
departure->tie("airport", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
departure->tie("airport", SGStringValueMethods<FGRouteMgr>(*this,
|
||||||
&FGRouteMgr::getDepartureICAO, &FGRouteMgr::setDepartureICAO));
|
&FGRouteMgr::getDepartureICAO, &FGRouteMgr::setDepartureICAO));
|
||||||
departure->tie("runway", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
departure->tie("runway", SGStringValueMethods<FGRouteMgr>(*this,
|
||||||
&FGRouteMgr::getDepartureRunway,
|
&FGRouteMgr::getDepartureRunway,
|
||||||
&FGRouteMgr::setDepartureRunway));
|
&FGRouteMgr::setDepartureRunway));
|
||||||
departure->tie("sid", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
departure->tie("sid", SGStringValueMethods<FGRouteMgr>(*this,
|
||||||
&FGRouteMgr::getSID,
|
&FGRouteMgr::getSID,
|
||||||
&FGRouteMgr::setSID));
|
&FGRouteMgr::setSID));
|
||||||
|
|
||||||
departure->tie("name", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
departure->tie("name", SGStringValueMethods<FGRouteMgr>(*this,
|
||||||
&FGRouteMgr::getDepartureName, NULL));
|
&FGRouteMgr::getDepartureName, NULL));
|
||||||
departure->tie("field-elevation-ft", SGRawValueMethods<FGRouteMgr, double>(*this,
|
departure->tie("field-elevation-ft", SGRawValueMethods<FGRouteMgr, double>(*this,
|
||||||
&FGRouteMgr::getDepartureFieldElevation, NULL));
|
&FGRouteMgr::getDepartureFieldElevation, NULL));
|
||||||
|
@ -278,19 +278,19 @@ void FGRouteMgr::init() {
|
||||||
destination = fgGetNode(RM "destination", true);
|
destination = fgGetNode(RM "destination", true);
|
||||||
destination->getChild("airport", 0, true);
|
destination->getChild("airport", 0, true);
|
||||||
|
|
||||||
destination->tie("airport", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
destination->tie("airport", SGStringValueMethods<FGRouteMgr>(*this,
|
||||||
&FGRouteMgr::getDestinationICAO, &FGRouteMgr::setDestinationICAO));
|
&FGRouteMgr::getDestinationICAO, &FGRouteMgr::setDestinationICAO));
|
||||||
destination->tie("runway", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
destination->tie("runway", SGStringValueMethods<FGRouteMgr>(*this,
|
||||||
&FGRouteMgr::getDestinationRunway,
|
&FGRouteMgr::getDestinationRunway,
|
||||||
&FGRouteMgr::setDestinationRunway));
|
&FGRouteMgr::setDestinationRunway));
|
||||||
destination->tie("star", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
destination->tie("star", SGStringValueMethods<FGRouteMgr>(*this,
|
||||||
&FGRouteMgr::getSTAR,
|
&FGRouteMgr::getSTAR,
|
||||||
&FGRouteMgr::setSTAR));
|
&FGRouteMgr::setSTAR));
|
||||||
destination->tie("approach", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
destination->tie("approach", SGStringValueMethods<FGRouteMgr>(*this,
|
||||||
&FGRouteMgr::getApproach,
|
&FGRouteMgr::getApproach,
|
||||||
&FGRouteMgr::setApproach));
|
&FGRouteMgr::setApproach));
|
||||||
|
|
||||||
destination->tie("name", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
destination->tie("name", SGStringValueMethods<FGRouteMgr>(*this,
|
||||||
&FGRouteMgr::getDestinationName, NULL));
|
&FGRouteMgr::getDestinationName, NULL));
|
||||||
destination->tie("field-elevation-ft", SGRawValueMethods<FGRouteMgr, double>(*this,
|
destination->tie("field-elevation-ft", SGRawValueMethods<FGRouteMgr, double>(*this,
|
||||||
&FGRouteMgr::getDestinationFieldElevation, NULL));
|
&FGRouteMgr::getDestinationFieldElevation, NULL));
|
||||||
|
@ -637,7 +637,7 @@ void FGRouteMgr::update_mirror()
|
||||||
SGPropertyNode *prop = mirror->getChild("wp", i, 1);
|
SGPropertyNode *prop = mirror->getChild("wp", i, 1);
|
||||||
|
|
||||||
const SGGeod& pos(wp->position());
|
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("longitude-deg", pos.getLongitudeDeg());
|
||||||
prop->setDoubleValue("latitude-deg",pos.getLatitudeDeg());
|
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());
|
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()) {
|
if (!_plan || !_plan->departureAirport()) {
|
||||||
return "";
|
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()) {
|
if (!_plan || !_plan->departureAirport()) {
|
||||||
return "";
|
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()) {
|
if (_plan && _plan->departureRunway()) {
|
||||||
return _plan->departureRunway()->ident().c_str();
|
return _plan->departureRunway()->ident();
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGRouteMgr::setDepartureRunway(const char* aIdent)
|
void FGRouteMgr::setDepartureRunway(const std::string& aIdent)
|
||||||
{
|
{
|
||||||
if (!_plan) {
|
if (!_plan) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FGAirport* apt = _plan->departureAirport();
|
FGAirport* apt = _plan->departureAirport();
|
||||||
if (!apt || (aIdent == NULL)) {
|
if (!apt || aIdent.empty()) {
|
||||||
_plan->setDeparture(apt);
|
_plan->setDeparture(apt);
|
||||||
} else if (apt->hasRunwayWithIdent(aIdent)) {
|
} else if (apt->hasRunwayWithIdent(aIdent)) {
|
||||||
_plan->setDeparture(apt->getRunwayByIdent(aIdent));
|
_plan->setDeparture(apt->getRunwayByIdent(aIdent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGRouteMgr::setDepartureICAO(const char* aIdent)
|
void FGRouteMgr::setDepartureICAO(const std::string& aIdent)
|
||||||
{
|
{
|
||||||
if (!_plan) {
|
if (!_plan) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((aIdent == NULL) || (strlen(aIdent) < 4)) {
|
if (aIdent.length() < 4) {
|
||||||
_plan->setDeparture((FGAirport*) NULL);
|
_plan->setDeparture((FGAirport*) NULL);
|
||||||
} else {
|
} else {
|
||||||
_plan->setDeparture(FGAirport::findByIdent(aIdent));
|
_plan->setDeparture(FGAirport::findByIdent(aIdent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* FGRouteMgr::getSID() const
|
std::string FGRouteMgr::getSID() const
|
||||||
{
|
{
|
||||||
if (_plan && _plan->sid()) {
|
if (_plan && _plan->sid()) {
|
||||||
return _plan->sid()->ident().c_str();
|
return _plan->sid()->ident();
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
|
@ -923,19 +923,19 @@ flightgear::SID* createDefaultSID(FGRunway* aRunway, double enrouteCourse)
|
||||||
return flightgear::SID::createTempSID("DEFAULT", aRunway, wpts);
|
return flightgear::SID::createTempSID("DEFAULT", aRunway, wpts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGRouteMgr::setSID(const char* aIdent)
|
void FGRouteMgr::setSID(const std::string& aIdent)
|
||||||
{
|
{
|
||||||
if (!_plan) {
|
if (!_plan) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FGAirport* apt = _plan->departureAirport();
|
FGAirport* apt = _plan->departureAirport();
|
||||||
if (!apt || (aIdent == NULL)) {
|
if (!apt || aIdent.empty()) {
|
||||||
_plan->setSID((flightgear::SID*) NULL);
|
_plan->setSID((flightgear::SID*) NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(aIdent, "DEFAULT")) {
|
if (aIdent == "DEFAULT") {
|
||||||
double enrouteCourse = -1.0;
|
double enrouteCourse = -1.0;
|
||||||
if (_plan->destinationAirport()) {
|
if (_plan->destinationAirport()) {
|
||||||
enrouteCourse = SGGeodesy::courseDeg(apt->geod(), _plan->destinationAirport()->geod());
|
enrouteCourse = SGGeodesy::courseDeg(apt->geod(), _plan->destinationAirport()->geod());
|
||||||
|
@ -945,11 +945,10 @@ void FGRouteMgr::setSID(const char* aIdent)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string ident(aIdent);
|
size_t hyphenPos = aIdent.find('-');
|
||||||
size_t hyphenPos = ident.find('-');
|
|
||||||
if (hyphenPos != string::npos) {
|
if (hyphenPos != string::npos) {
|
||||||
string sidIdent = ident.substr(0, hyphenPos);
|
string sidIdent = aIdent.substr(0, hyphenPos);
|
||||||
string transIdent = ident.substr(hyphenPos + 1);
|
string transIdent = aIdent.substr(hyphenPos + 1);
|
||||||
|
|
||||||
flightgear::SID* sid = apt->findSIDWithIdent(sidIdent);
|
flightgear::SID* sid = apt->findSIDWithIdent(sidIdent);
|
||||||
Transition* trans = sid ? sid->findTransitionByName(transIdent) : NULL;
|
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()) {
|
if (!_plan || !_plan->destinationAirport()) {
|
||||||
return "";
|
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()) {
|
if (!_plan || !_plan->destinationAirport()) {
|
||||||
return "";
|
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) {
|
if (!_plan) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((aIdent == NULL) || (strlen(aIdent) < 4)) {
|
if (aIdent.length() < 4) {
|
||||||
_plan->setDestination((FGAirport*) NULL);
|
_plan->setDestination((FGAirport*) NULL);
|
||||||
} else {
|
} else {
|
||||||
_plan->setDestination(FGAirport::findByIdent(aIdent));
|
_plan->setDestination(FGAirport::findByIdent(aIdent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* FGRouteMgr::getDestinationRunway() const
|
std::string FGRouteMgr::getDestinationRunway() const
|
||||||
{
|
{
|
||||||
if (_plan && _plan->destinationRunway()) {
|
if (_plan && _plan->destinationRunway()) {
|
||||||
return _plan->destinationRunway()->ident().c_str();
|
return _plan->destinationRunway()->ident();
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGRouteMgr::setDestinationRunway(const char* aIdent)
|
void FGRouteMgr::setDestinationRunway(const std::string& aIdent)
|
||||||
{
|
{
|
||||||
if (!_plan) {
|
if (!_plan) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FGAirport* apt = _plan->destinationAirport();
|
FGAirport* apt = _plan->destinationAirport();
|
||||||
if (!apt || (aIdent == NULL)) {
|
if (!apt || aIdent.empty()) {
|
||||||
_plan->setDestination(apt);
|
_plan->setDestination(apt);
|
||||||
} else if (apt->hasRunwayWithIdent(aIdent)) {
|
} else if (apt->hasRunwayWithIdent(aIdent)) {
|
||||||
_plan->setDestination(apt->getRunwayByIdent(aIdent));
|
_plan->setDestination(apt->getRunwayByIdent(aIdent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* FGRouteMgr::getApproach() const
|
std::string FGRouteMgr::getApproach() const
|
||||||
{
|
{
|
||||||
if (_plan && _plan->approach()) {
|
if (_plan && _plan->approach()) {
|
||||||
return _plan->approach()->ident().c_str();
|
return _plan->approach()->ident();
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
|
@ -1082,14 +1081,14 @@ flightgear::Approach* createDefaultApproach(FGRunway* aRunway, double aEnrouteCo
|
||||||
return Approach::createTempApproach("DEFAULT", aRunway, wpts);
|
return Approach::createTempApproach("DEFAULT", aRunway, wpts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGRouteMgr::setApproach(const char* aIdent)
|
void FGRouteMgr::setApproach(const std::string& aIdent)
|
||||||
{
|
{
|
||||||
if (!_plan) {
|
if (!_plan) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FGAirport* apt = _plan->destinationAirport();
|
FGAirport* apt = _plan->destinationAirport();
|
||||||
if (!strcmp(aIdent, "DEFAULT")) {
|
if (aIdent == "DEFAULT") {
|
||||||
double enrouteCourse = -1.0;
|
double enrouteCourse = -1.0;
|
||||||
if (_plan->departureAirport()) {
|
if (_plan->departureAirport()) {
|
||||||
enrouteCourse = SGGeodesy::courseDeg(_plan->departureAirport()->geod(), apt->geod());
|
enrouteCourse = SGGeodesy::courseDeg(_plan->departureAirport()->geod(), apt->geod());
|
||||||
|
@ -1099,30 +1098,30 @@ void FGRouteMgr::setApproach(const char* aIdent)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!apt || (aIdent == NULL)) {
|
if (!apt || aIdent.empty()) {
|
||||||
_plan->setApproach(NULL);
|
_plan->setApproach(NULL);
|
||||||
} else {
|
} else {
|
||||||
_plan->setApproach(apt->findApproachWithIdent(aIdent));
|
_plan->setApproach(apt->findApproachWithIdent(aIdent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* FGRouteMgr::getSTAR() const
|
std::string FGRouteMgr::getSTAR() const
|
||||||
{
|
{
|
||||||
if (_plan && _plan->star()) {
|
if (_plan && _plan->star()) {
|
||||||
return _plan->star()->ident().c_str();
|
return _plan->star()->ident();
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGRouteMgr::setSTAR(const char* aIdent)
|
void FGRouteMgr::setSTAR(const std::string& aIdent)
|
||||||
{
|
{
|
||||||
if (!_plan) {
|
if (!_plan) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FGAirport* apt = _plan->destinationAirport();
|
FGAirport* apt = _plan->destinationAirport();
|
||||||
if (!apt || (aIdent == NULL)) {
|
if (!apt || aIdent.empty()) {
|
||||||
_plan->setSTAR((STAR*) NULL);
|
_plan->setSTAR((STAR*) NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,28 +183,28 @@ private:
|
||||||
virtual void currentWaypointChanged();
|
virtual void currentWaypointChanged();
|
||||||
|
|
||||||
// tied getters and setters
|
// tied getters and setters
|
||||||
const char* getDepartureICAO() const;
|
std::string getDepartureICAO() const;
|
||||||
const char* getDepartureName() const;
|
std::string getDepartureName() const;
|
||||||
void setDepartureICAO(const char* aIdent);
|
void setDepartureICAO(const std::string& aIdent);
|
||||||
|
|
||||||
const char* getDepartureRunway() const;
|
std::string getDepartureRunway() const;
|
||||||
void setDepartureRunway(const char* aIdent);
|
void setDepartureRunway(const std::string& aIdent);
|
||||||
|
|
||||||
const char* getSID() const;
|
std::string getSID() const;
|
||||||
void setSID(const char* aIdent);
|
void setSID(const std::string& aIdent);
|
||||||
|
|
||||||
const char* getDestinationICAO() const;
|
std::string getDestinationICAO() const;
|
||||||
const char* getDestinationName() const;
|
std::string getDestinationName() const;
|
||||||
void setDestinationICAO(const char* aIdent);
|
void setDestinationICAO(const std::string& aIdent);
|
||||||
|
|
||||||
const char* getDestinationRunway() const;
|
std::string getDestinationRunway() const;
|
||||||
void setDestinationRunway(const char* aIdent);
|
void setDestinationRunway(const std::string& aIdent);
|
||||||
|
|
||||||
const char* getApproach() const;
|
std::string getApproach() const;
|
||||||
void setApproach(const char* aIdent);
|
void setApproach(const std::string& aIdent);
|
||||||
|
|
||||||
const char* getSTAR() const;
|
std::string getSTAR() const;
|
||||||
void setSTAR(const char* aIdent);
|
void setSTAR(const std::string& aIdent);
|
||||||
|
|
||||||
double getDepartureFieldElevation() const;
|
double getDepartureFieldElevation() const;
|
||||||
double getDestinationFieldElevation() const;
|
double getDestinationFieldElevation() const;
|
||||||
|
|
|
@ -183,7 +183,7 @@ private:
|
||||||
class SymbolRule
|
class SymbolRule
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SymbolRule()
|
SymbolRule() : enabled(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,13 @@
|
||||||
|
|
||||||
#include <simgear/constants.h>
|
#include <simgear/constants.h>
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#ifdef FG_TESTLIB
|
||||||
|
#include <tests/fake_sgSky.hxx>
|
||||||
|
#else
|
||||||
#include <simgear/scene/sky/sky.hxx>
|
#include <simgear/scene/sky/sky.hxx>
|
||||||
#include <simgear/scene/model/particles.hxx>
|
#include <simgear/scene/model/particles.hxx>
|
||||||
|
#endif
|
||||||
#include <simgear/structure/event_mgr.hxx>
|
#include <simgear/structure/event_mgr.hxx>
|
||||||
|
|
||||||
#include <Main/main.hxx>
|
#include <Main/main.hxx>
|
||||||
|
@ -47,6 +52,7 @@
|
||||||
#include "gravity.hxx"
|
#include "gravity.hxx"
|
||||||
#include "magvarmanager.hxx"
|
#include "magvarmanager.hxx"
|
||||||
|
|
||||||
|
#ifndef FG_TESTLIB
|
||||||
class FG3DCloudsListener : public SGPropertyChangeListener {
|
class FG3DCloudsListener : public SGPropertyChangeListener {
|
||||||
public:
|
public:
|
||||||
FG3DCloudsListener( FGClouds * fgClouds );
|
FG3DCloudsListener( FGClouds * fgClouds );
|
||||||
|
@ -77,19 +83,26 @@ void FG3DCloudsListener::valueChanged( SGPropertyNode * node )
|
||||||
{
|
{
|
||||||
_fgClouds->set_3dClouds( _enableNode->getBoolValue() );
|
_fgClouds->set_3dClouds( _enableNode->getBoolValue() );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
FGEnvironmentMgr::FGEnvironmentMgr () :
|
FGEnvironmentMgr::FGEnvironmentMgr () :
|
||||||
_environment(new FGEnvironment()),
|
_environment(new FGEnvironment()),
|
||||||
fgClouds(new FGClouds()),
|
fgClouds(nullptr),
|
||||||
_cloudLayersDirty(true),
|
_cloudLayersDirty(true),
|
||||||
_3dCloudsEnableListener(new FG3DCloudsListener(fgClouds) ),
|
_3dCloudsEnableListener(nullptr),
|
||||||
_sky(globals->get_renderer()->getSky())
|
_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("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);
|
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 ) ));
|
set_subsystem("terrainsampler", Environment::TerrainSampler::createInstance( fgGetNode("/environment/terrain", true ) ));
|
||||||
|
#endif
|
||||||
set_subsystem("ridgelift", new FGRidgeLift);
|
set_subsystem("ridgelift", new FGRidgeLift);
|
||||||
|
|
||||||
set_subsystem("magvar", new FGMagVarManager);
|
set_subsystem("magvar", new FGMagVarManager);
|
||||||
|
@ -104,10 +117,11 @@ FGEnvironmentMgr::~FGEnvironmentMgr ()
|
||||||
remove_subsystem("controller");
|
remove_subsystem("controller");
|
||||||
remove_subsystem("magvar");
|
remove_subsystem("magvar");
|
||||||
|
|
||||||
|
#ifndef FG_TESTLIB
|
||||||
delete fgClouds;
|
delete fgClouds;
|
||||||
delete _environment;
|
|
||||||
|
|
||||||
delete _3dCloudsEnableListener;
|
delete _3dCloudsEnableListener;
|
||||||
|
#endif
|
||||||
|
delete _environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
SGSubsystem::InitStatus FGEnvironmentMgr::incrementalInit()
|
SGSubsystem::InitStatus FGEnvironmentMgr::incrementalInit()
|
||||||
|
@ -115,7 +129,9 @@ SGSubsystem::InitStatus FGEnvironmentMgr::incrementalInit()
|
||||||
|
|
||||||
InitStatus r = SGSubsystemGroup::incrementalInit();
|
InitStatus r = SGSubsystemGroup::incrementalInit();
|
||||||
if (r == INIT_DONE) {
|
if (r == INIT_DONE) {
|
||||||
|
#ifndef FG_TESTLIB
|
||||||
fgClouds->Init();
|
fgClouds->Init();
|
||||||
|
#endif
|
||||||
globals->get_event_mgr()->addTask("updateClosestAirport", this,
|
globals->get_event_mgr()->addTask("updateClosestAirport", this,
|
||||||
&FGEnvironmentMgr::updateClosestAirport, 30 );
|
&FGEnvironmentMgr::updateClosestAirport, 30 );
|
||||||
}
|
}
|
||||||
|
@ -148,10 +164,11 @@ FGEnvironmentMgr::bind ()
|
||||||
_tiedProperties.Tie( "effective-visibility-m", _sky,
|
_tiedProperties.Tie( "effective-visibility-m", _sky,
|
||||||
&SGSky::get_visibility );
|
&SGSky::get_visibility );
|
||||||
|
|
||||||
|
#ifndef FG_TESTLIB
|
||||||
_tiedProperties.Tie("rebuild-layers", fgClouds,
|
_tiedProperties.Tie("rebuild-layers", fgClouds,
|
||||||
&FGClouds::get_update_event,
|
&FGClouds::get_update_event,
|
||||||
&FGClouds::set_update_event);
|
&FGClouds::set_update_event);
|
||||||
|
#endif
|
||||||
// _tiedProperties.Tie("turbulence/use-cloud-turbulence", &sgEnviro,
|
// _tiedProperties.Tie("turbulence/use-cloud-turbulence", &sgEnviro,
|
||||||
// &SGEnviro::get_turbulence_enable_state,
|
// &SGEnviro::get_turbulence_enable_state,
|
||||||
// &SGEnviro::set_turbulence_enable_state);
|
// &SGEnviro::set_turbulence_enable_state);
|
||||||
|
@ -221,7 +238,6 @@ FGEnvironmentMgr::bind ()
|
||||||
_tiedProperties.Tie("clouds3d-use-impostors", _sky,
|
_tiedProperties.Tie("clouds3d-use-impostors", _sky,
|
||||||
&SGSky::get_3dCloudUseImpostors,
|
&SGSky::get_3dCloudUseImpostors,
|
||||||
&SGSky::set_3dCloudUseImpostors);
|
&SGSky::set_3dCloudUseImpostors);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -240,13 +256,14 @@ FGEnvironmentMgr::update (double dt)
|
||||||
SGGeod aircraftPos(globals->get_aircraft_position());
|
SGGeod aircraftPos(globals->get_aircraft_position());
|
||||||
_environment->set_elevation_ft( aircraftPos.getElevationFt() );
|
_environment->set_elevation_ft( aircraftPos.getElevationFt() );
|
||||||
|
|
||||||
|
#ifndef FG_TESTLIB
|
||||||
simgear::Particles::setWindFrom( _environment->get_wind_from_heading_deg(),
|
simgear::Particles::setWindFrom( _environment->get_wind_from_heading_deg(),
|
||||||
_environment->get_wind_speed_kt() );
|
_environment->get_wind_speed_kt() );
|
||||||
if( _cloudLayersDirty ) {
|
if( _cloudLayersDirty ) {
|
||||||
_cloudLayersDirty = false;
|
_cloudLayersDirty = false;
|
||||||
fgClouds->set_update_event( fgClouds->get_update_event()+1 );
|
fgClouds->set_update_event( fgClouds->get_update_event()+1 );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
fgSetDouble( "/environment/gravitational-acceleration-mps2",
|
fgSetDouble( "/environment/gravitational-acceleration-mps2",
|
||||||
Environment::Gravity::instance()->getGravity(aircraftPos));
|
Environment::Gravity::instance()->getGravity(aircraftPos));
|
||||||
|
|
|
@ -160,7 +160,7 @@ FGMetar::FGMetar(const string& icao) :
|
||||||
|
|
||||||
long FGMetar::getAge_min() const
|
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;
|
return (now - _time) / 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,10 @@
|
||||||
class FGPrecipitationMgr : public SGSubsystem
|
class FGPrecipitationMgr : public SGSubsystem
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
#ifndef FG_TESTLIB
|
||||||
osg::ref_ptr<osg::MatrixTransform> transform;
|
osg::ref_ptr<osg::MatrixTransform> transform;
|
||||||
osg::ref_ptr<SGPrecipitation> precipitation;
|
osg::ref_ptr<SGPrecipitation> precipitation;
|
||||||
|
#endif
|
||||||
float getPrecipitationAtAltitudeMax(void);
|
float getPrecipitationAtAltitudeMax(void);
|
||||||
simgear::TiedPropertyList _tiedProperties;
|
simgear::TiedPropertyList _tiedProperties;
|
||||||
|
|
||||||
|
@ -56,4 +58,3 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
IDENT(IdHdr,ID_FDMEXEC);
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -428,7 +428,7 @@ void FGFDMExec::LoadInputs(unsigned int idx)
|
||||||
Propulsion->in.PropAdvance = FCS->GetPropAdvance();
|
Propulsion->in.PropAdvance = FCS->GetPropAdvance();
|
||||||
Propulsion->in.PropFeather = FCS->GetPropFeather();
|
Propulsion->in.PropFeather = FCS->GetPropFeather();
|
||||||
Propulsion->in.H_agl = Propagate->GetDistanceAGL();
|
Propulsion->in.H_agl = Propagate->GetDistanceAGL();
|
||||||
Propulsion->in.PQR = Propagate->GetPQR();
|
Propulsion->in.PQRi = Propagate->GetPQRi();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case eAerodynamics:
|
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;
|
bool result;
|
||||||
|
|
||||||
Script = new FGScript(this);
|
Script = new FGScript(this);
|
||||||
result = Script->LoadScript(RootDir + script, deltaT, initfile);
|
result = Script->LoadScript(GetFullPath(script), deltaT, initfile);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
bool FGFDMExec::LoadModel(const string& AircraftPath, const string& EnginePath, const string& SystemsPath,
|
bool FGFDMExec::LoadModel(const SGPath& AircraftPath, const SGPath& EnginePath,
|
||||||
const string& model, bool addModelToPath)
|
const SGPath& SystemsPath, const string& model,
|
||||||
|
bool addModelToPath)
|
||||||
{
|
{
|
||||||
FGFDMExec::AircraftPath = RootDir + AircraftPath;
|
FGFDMExec::AircraftPath = GetFullPath(AircraftPath);
|
||||||
FGFDMExec::EnginePath = RootDir + EnginePath;
|
FGFDMExec::EnginePath = GetFullPath(EnginePath);
|
||||||
FGFDMExec::SystemsPath = RootDir + SystemsPath;
|
FGFDMExec::SystemsPath = GetFullPath(SystemsPath);
|
||||||
|
|
||||||
return LoadModel(model, addModelToPath);
|
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)
|
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
|
bool result = false; // initialize result to false, indicating input file not yet read
|
||||||
|
|
||||||
modelName = model; // Set the class modelName attribute
|
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 << "Error: attempted to load aircraft with undefined ";
|
||||||
cerr << "aircraft, engine, and system paths" << endl;
|
cerr << "aircraft, engine, and system paths" << endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FullAircraftPath = AircraftPath;
|
FullAircraftPath = AircraftPath;
|
||||||
if (addModelToPath) FullAircraftPath += "/" + model;
|
if (addModelToPath) FullAircraftPath.append(model);
|
||||||
aircraftCfgFileName = FullAircraftPath + "/" + model + ".xml";
|
aircraftCfgFileName = FullAircraftPath/(model + ".xml");
|
||||||
|
|
||||||
if (modelLoaded) {
|
if (modelLoaded) {
|
||||||
DeAllocate();
|
DeAllocate();
|
||||||
|
|
|
@ -49,12 +49,13 @@ INCLUDES
|
||||||
#include "models/FGPropagate.h"
|
#include "models/FGPropagate.h"
|
||||||
#include "math/FGColumnVector3.h"
|
#include "math/FGColumnVector3.h"
|
||||||
#include "models/FGOutput.h"
|
#include "models/FGOutput.h"
|
||||||
|
#include "simgear/misc/sg_path.hxx"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -178,7 +179,7 @@ CLASS DOCUMENTATION
|
||||||
property actually maps toa function call of DoTrim().
|
property actually maps toa function call of DoTrim().
|
||||||
|
|
||||||
@author Jon S. Berndt
|
@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
|
@param addModelToPath set to true to add the model name to the
|
||||||
AircraftPath, defaults to true
|
AircraftPath, defaults to true
|
||||||
@return true if successful */
|
@return true if successful */
|
||||||
bool LoadModel(const std::string& AircraftPath, const std::string& EnginePath,
|
bool LoadModel(const SGPath& AircraftPath, const SGPath& EnginePath,
|
||||||
const std::string& SystemsPath, const std::string& model,
|
const SGPath& SystemsPath, const std::string& model,
|
||||||
bool addModelToPath = true);
|
bool addModelToPath = true);
|
||||||
|
|
||||||
/** Loads an aircraft model. The paths to the aircraft and engine
|
/** 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
|
the file specified in the script will be used. If an initialization file
|
||||||
is not given in either place, an error will result.
|
is not given in either place, an error will result.
|
||||||
@return true if successfully loads; false otherwise. */
|
@return true if successfully loads; false otherwise. */
|
||||||
bool LoadScript(const std::string& Script, double deltaT=0.0,
|
bool LoadScript(const SGPath& Script, double deltaT=0.0,
|
||||||
const std::string& initfile="");
|
const SGPath& initfile=SGPath());
|
||||||
|
|
||||||
/** Sets the path to the engine config file directories.
|
/** Sets the path to the engine config file directories.
|
||||||
@param path path to the directory under which engine config
|
@param path path to the directory under which engine config
|
||||||
files are kept, for instance "engine" */
|
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.
|
/** Sets the path to the aircraft config file directories.
|
||||||
@param path path to the aircraft directory. For instance:
|
@param path path to the aircraft directory. For instance:
|
||||||
"aircraft". Under aircraft, then, would be directories for various
|
"aircraft". Under aircraft, then, would be directories for various
|
||||||
modeled aircraft such as C172/, x15/, etc. */
|
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.
|
/** Sets the path to the systems config file directories.
|
||||||
@param path path to the directory under which systems config
|
@param path path to the directory under which systems config
|
||||||
files are kept, for instance "systems" */
|
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
|
/// @name Top-level executive State and Model retrieval mechanism
|
||||||
///@{
|
///@{
|
||||||
|
@ -378,13 +388,13 @@ public:
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
/// Retrieves the engine path.
|
/// Retrieves the engine path.
|
||||||
const std::string& GetEnginePath(void) {return EnginePath;}
|
const SGPath& GetEnginePath(void) {return EnginePath;}
|
||||||
/// Retrieves the aircraft path.
|
/// Retrieves the aircraft path.
|
||||||
const std::string& GetAircraftPath(void) {return AircraftPath;}
|
const SGPath& GetAircraftPath(void) {return AircraftPath;}
|
||||||
/// Retrieves the systems path.
|
/// Retrieves the systems path.
|
||||||
const std::string& GetSystemsPath(void) {return SystemsPath;}
|
const SGPath& GetSystemsPath(void) {return SystemsPath;}
|
||||||
/// Retrieves the full aircraft path name.
|
/// 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.
|
/** Retrieves the value of a property.
|
||||||
@param property the name of the property
|
@param property the name of the property
|
||||||
|
@ -428,8 +438,8 @@ public:
|
||||||
be logged.
|
be logged.
|
||||||
@param fname the filename of an output directives file.
|
@param fname the filename of an output directives file.
|
||||||
*/
|
*/
|
||||||
bool SetOutputDirectives(const std::string& fname)
|
bool SetOutputDirectives(const SGPath& fname)
|
||||||
{return Output->SetDirectivesFile(RootDir + fname);}
|
{ return Output->SetDirectivesFile(GetFullPath(fname)); }
|
||||||
|
|
||||||
/** Forces the specified output object to print its items once */
|
/** Forces the specified output object to print its items once */
|
||||||
void ForceOutput(int idx=0) { Output->ForceOutput(idx); }
|
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.
|
/** Sets the root directory where JSBSim starts looking for its system directories.
|
||||||
@param rootDir the string containing the root directory. */
|
@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.
|
/** Retrieves the Root Directory.
|
||||||
@return the string representing the root (base) JSBSim 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
|
/** Increments the simulation time if not in Holding mode. The Frame counter
|
||||||
is also incremented.
|
is also incremented.
|
||||||
|
@ -606,13 +616,13 @@ private:
|
||||||
bool modelLoaded;
|
bool modelLoaded;
|
||||||
bool IsChild;
|
bool IsChild;
|
||||||
std::string modelName;
|
std::string modelName;
|
||||||
std::string AircraftPath;
|
SGPath AircraftPath;
|
||||||
std::string FullAircraftPath;
|
SGPath FullAircraftPath;
|
||||||
std::string EnginePath;
|
SGPath EnginePath;
|
||||||
std::string SystemsPath;
|
SGPath SystemsPath;
|
||||||
std::string CFGVersion;
|
std::string CFGVersion;
|
||||||
std::string Release;
|
std::string Release;
|
||||||
std::string RootDir;
|
SGPath RootDir;
|
||||||
|
|
||||||
// Standard Model pointers - shortcuts for internal executive use only.
|
// Standard Model pointers - shortcuts for internal executive use only.
|
||||||
FGPropagate* Propagate;
|
FGPropagate* Propagate;
|
||||||
|
@ -664,6 +674,12 @@ private:
|
||||||
bool Allocate(void);
|
bool Allocate(void);
|
||||||
bool DeAllocate(void);
|
bool DeAllocate(void);
|
||||||
int GetDisperse(void) const {return disperse;}
|
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);
|
void Debug(int from);
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,18 +77,18 @@ using JSBSim::Element;
|
||||||
DEFINITIONS
|
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
|
GLOBAL DATA
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
string RootDir = "";
|
SGPath RootDir;
|
||||||
string ScriptName;
|
SGPath ScriptName;
|
||||||
string AircraftName;
|
string AircraftName;
|
||||||
string ResetName;
|
SGPath ResetName;
|
||||||
vector <string> LogOutputName;
|
vector <string> LogOutputName;
|
||||||
vector <string> LogDirectiveName;
|
vector <SGPath> LogDirectiveName;
|
||||||
vector <string> CommandLineProperties;
|
vector <string> CommandLineProperties;
|
||||||
vector <double> CommandLinePropertyValues;
|
vector <double> CommandLinePropertyValues;
|
||||||
JSBSim::FGFDMExec* FDMExec;
|
JSBSim::FGFDMExec* FDMExec;
|
||||||
|
@ -151,28 +151,28 @@ void PrintHelp(void);
|
||||||
of file is given on the command line */
|
of file is given on the command line */
|
||||||
class XMLFile : public FGXMLFileRead {
|
class XMLFile : public FGXMLFileRead {
|
||||||
public:
|
public:
|
||||||
bool IsScriptFile(std::string filename) {
|
bool IsScriptFile(const SGPath& filename) {
|
||||||
bool result=false;
|
bool result=false;
|
||||||
Element *document = LoadXMLDocument(filename, false);
|
Element *document = LoadXMLDocument(filename, false);
|
||||||
if (document && document->GetName() == "runscript") result = true;
|
if (document && document->GetName() == "runscript") result = true;
|
||||||
ResetParser();
|
ResetParser();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
bool IsLogDirectiveFile(std::string filename) {
|
bool IsLogDirectiveFile(const SGPath& filename) {
|
||||||
bool result=false;
|
bool result=false;
|
||||||
Element *document = LoadXMLDocument(filename, false);
|
Element *document = LoadXMLDocument(filename, false);
|
||||||
if (document && document->GetName() == "output") result = true;
|
if (document && document->GetName() == "output") result = true;
|
||||||
ResetParser();
|
ResetParser();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
bool IsAircraftFile(std::string filename) {
|
bool IsAircraftFile(const SGPath& filename) {
|
||||||
bool result=false;
|
bool result=false;
|
||||||
Element* document = LoadXMLDocument(filename, false);
|
Element* document = LoadXMLDocument(filename, false);
|
||||||
if (document && document->GetName() == "fdm_config") result = true;
|
if (document && document->GetName() == "fdm_config") result = true;
|
||||||
ResetParser();
|
ResetParser();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
bool IsInitFile(std::string filename) {
|
bool IsInitFile(const SGPath& filename) {
|
||||||
bool result=false;
|
bool result=false;
|
||||||
Element *document = LoadXMLDocument(filename, false);
|
Element *document = LoadXMLDocument(filename, false);
|
||||||
if (document && document->GetName() == "initialize") result = true;
|
if (document && document->GetName() == "initialize") result = true;
|
||||||
|
@ -345,9 +345,9 @@ int real_main(int argc, char* argv[])
|
||||||
// *** SET UP JSBSIM *** //
|
// *** SET UP JSBSIM *** //
|
||||||
FDMExec = new JSBSim::FGFDMExec();
|
FDMExec = new JSBSim::FGFDMExec();
|
||||||
FDMExec->SetRootDir(RootDir);
|
FDMExec->SetRootDir(RootDir);
|
||||||
FDMExec->SetAircraftPath("aircraft");
|
FDMExec->SetAircraftPath(SGPath("aircraft"));
|
||||||
FDMExec->SetEnginePath("engine");
|
FDMExec->SetEnginePath(SGPath("engine"));
|
||||||
FDMExec->SetSystemsPath("systems");
|
FDMExec->SetSystemsPath(SGPath("systems"));
|
||||||
FDMExec->GetPropertyManager()->Tie("simulation/frame_start_time", &actual_elapsed_time);
|
FDMExec->GetPropertyManager()->Tie("simulation/frame_start_time", &actual_elapsed_time);
|
||||||
FDMExec->GetPropertyManager()->Tie("simulation/cycle_duration", &cycle_duration);
|
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 *** //
|
// *** OPTION A: LOAD A SCRIPT, WHICH LOADS EVERYTHING ELSE *** //
|
||||||
if (!ScriptName.empty()) {
|
if (!ScriptName.isNull()) {
|
||||||
|
|
||||||
result = FDMExec->LoadScript(ScriptName, override_sim_rate_value, ResetName);
|
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 *** //
|
// *** 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 (catalog) FDMExec->SetDebugLevel(0);
|
||||||
|
|
||||||
if ( ! FDMExec->LoadModel( "aircraft",
|
if ( ! FDMExec->LoadModel(SGPath("aircraft"),
|
||||||
"engine",
|
SGPath("engine"),
|
||||||
"systems",
|
SGPath("systems"),
|
||||||
AircraftName)) {
|
AircraftName)) {
|
||||||
cerr << " JSBSim could not be started" << endl << endl;
|
cerr << " JSBSim could not be started" << endl << endl;
|
||||||
delete FDMExec;
|
delete FDMExec;
|
||||||
|
@ -417,7 +417,7 @@ int real_main(int argc, char* argv[])
|
||||||
|
|
||||||
// Load output directives file[s], if given
|
// Load output directives file[s], if given
|
||||||
for (unsigned int i=0; i<LogDirectiveName.size(); i++) {
|
for (unsigned int i=0; i<LogDirectiveName.size(); i++) {
|
||||||
if (!LogDirectiveName[i].empty()) {
|
if (!LogDirectiveName[i].isNull()) {
|
||||||
if (!FDMExec->SetOutputDirectives(LogDirectiveName[i])) {
|
if (!FDMExec->SetOutputDirectives(LogDirectiveName[i])) {
|
||||||
cout << "Output directives not properly set in file " << LogDirectiveName[i] << endl;
|
cout << "Output directives not properly set in file " << LogDirectiveName[i] << endl;
|
||||||
delete FDMExec;
|
delete FDMExec;
|
||||||
|
@ -621,17 +621,14 @@ bool options(int count, char **arg)
|
||||||
}
|
}
|
||||||
} else if (keyword == "--logdirectivefile") {
|
} else if (keyword == "--logdirectivefile") {
|
||||||
if (n != string::npos) {
|
if (n != string::npos) {
|
||||||
LogDirectiveName.push_back(value);
|
LogDirectiveName.push_back(SGPath::fromLocal8Bit(value.c_str()));
|
||||||
} else {
|
} else {
|
||||||
gripe;
|
gripe;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if (keyword == "--root") {
|
} else if (keyword == "--root") {
|
||||||
if (n != string::npos) {
|
if (n != string::npos) {
|
||||||
RootDir = value;
|
RootDir = SGPath::fromLocal8Bit(value.c_str());
|
||||||
if (RootDir[RootDir.length()-1] != '/') {
|
|
||||||
RootDir += '/';
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
gripe;
|
gripe;
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -645,14 +642,14 @@ bool options(int count, char **arg)
|
||||||
}
|
}
|
||||||
} else if (keyword == "--script") {
|
} else if (keyword == "--script") {
|
||||||
if (n != string::npos) {
|
if (n != string::npos) {
|
||||||
ScriptName = value;
|
ScriptName = SGPath::fromLocal8Bit(value.c_str());
|
||||||
} else {
|
} else {
|
||||||
gripe;
|
gripe;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if (keyword == "--initfile") {
|
} else if (keyword == "--initfile") {
|
||||||
if (n != string::npos) {
|
if (n != string::npos) {
|
||||||
ResetName = value;
|
ResetName = SGPath::fromLocal8Bit(value.c_str());
|
||||||
} else {
|
} else {
|
||||||
gripe;
|
gripe;
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -704,12 +701,13 @@ bool options(int count, char **arg)
|
||||||
// See what kind of files we are specifying on the command line
|
// See what kind of files we are specifying on the command line
|
||||||
|
|
||||||
XMLFile xmlFile;
|
XMLFile xmlFile;
|
||||||
|
SGPath path = SGPath::fromLocal8Bit(keyword.c_str());
|
||||||
|
|
||||||
if (xmlFile.IsScriptFile(keyword)) ScriptName = keyword;
|
if (xmlFile.IsScriptFile(path)) ScriptName = path;
|
||||||
else if (xmlFile.IsLogDirectiveFile(keyword)) LogDirectiveName.push_back(keyword);
|
else if (xmlFile.IsLogDirectiveFile(path)) LogDirectiveName.push_back(path);
|
||||||
else if (xmlFile.IsAircraftFile("aircraft/" + keyword + "/" + keyword)) AircraftName = keyword;
|
else if (xmlFile.IsAircraftFile(SGPath("aircraft")/keyword/keyword)) AircraftName = keyword;
|
||||||
else if (xmlFile.IsInitFile(keyword)) ResetName = keyword;
|
else if (xmlFile.IsInitFile(path)) ResetName = path;
|
||||||
else if (xmlFile.IsInitFile("aircraft/" + AircraftName + "/" + keyword)) ResetName = keyword;
|
else if (xmlFile.IsInitFile(SGPath("aircraft")/AircraftName/keyword)) ResetName = SGPath("aircraft")/AircraftName/keyword;
|
||||||
else {
|
else {
|
||||||
cerr << "The argument \"" << keyword << "\" cannot be interpreted as a file name or option." << endl;
|
cerr << "The argument \"" << keyword << "\" cannot be interpreted as a file name or option." << endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -727,15 +725,15 @@ bool options(int count, char **arg)
|
||||||
|
|
||||||
// Post-processing for script options. check for incompatible options.
|
// 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;
|
cerr << "Cannot specify catalog with script option" << endl << endl;
|
||||||
result = false;
|
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;
|
cerr << "You must specify an initialization file with the aircraft name." << endl << endl;
|
||||||
result = false;
|
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;
|
cerr << "You cannot specify an aircraft file with a script." << endl;
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,6 +188,11 @@ FGJSBsim::FGJSBsim( double dt )
|
||||||
case SG_POPUP:
|
case SG_POPUP:
|
||||||
FGJSBBase::debug_lvl = 0x00;
|
FGJSBBase::debug_lvl = 0x00;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// silence warning about unhandled cases
|
||||||
|
FGJSBBase::debug_lvl = 0x00;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if flight is excluded, don't bother
|
// if flight is excluded, don't bother
|
||||||
|
@ -234,9 +239,7 @@ FGJSBsim::FGJSBsim( double dt )
|
||||||
|
|
||||||
fdmex->Setdt( dt );
|
fdmex->Setdt( dt );
|
||||||
|
|
||||||
result = fdmex->LoadModel( aircraft_path.local8BitStr(),
|
result = fdmex->LoadModel( aircraft_path, engine_path, systems_path,
|
||||||
engine_path.local8BitStr(),
|
|
||||||
systems_path.local8BitStr(),
|
|
||||||
fgGetString("/sim/aero"), false );
|
fgGetString("/sim/aero"), false );
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
|
|
|
@ -58,7 +58,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
IDENT(IdHdr,ID_INITIALCONDITION);
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
|
@ -709,10 +709,10 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt)
|
||||||
altitudeASL=alt;
|
altitudeASL=alt;
|
||||||
position.SetAltitudeASL(alt);
|
position.SetAltitudeASL(alt);
|
||||||
|
|
||||||
if (lastLatitudeSet == setgeod) {
|
// The call to SetAltitudeASL has most likely modified the geodetic latitude
|
||||||
double h = ComputeGeodAltitude(geodLatitude);
|
// so we need to restore it to its initial value.
|
||||||
position.SetPositionGeodetic(position.GetLongitude(), geodLatitude, h);
|
if (lastLatitudeSet == setgeod)
|
||||||
}
|
SetGeodLatitudeRadIC(geodLatitude);
|
||||||
|
|
||||||
soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
||||||
rho = Atmosphere->GetDensity(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;
|
SGPath init_file_name;
|
||||||
if( useStoredPath ) {
|
if(useStoredPath && rstfile.isRelative()) {
|
||||||
init_file_name = fdmex->GetFullAircraftPath() + "/" + rstfile + ".xml";
|
init_file_name = fdmex->GetFullAircraftPath()/rstfile.utf8Str();
|
||||||
} else {
|
} else {
|
||||||
init_file_name = rstfile;
|
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
|
// Given an altitude above the mean sea level (or a position radius which is the
|
||||||
// same) and a geodetic latitude, compute the geodetic altitude. It is assumed
|
// same) and a geodetic latitude, compute the geodetic altitude.
|
||||||
// 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.
|
|
||||||
//
|
//
|
||||||
// This is an acceptable trade off because this routine is only used by
|
// TODO: extend the routine to the case where lastAltitudeSet is equal to
|
||||||
// standalone JSBSim which uses FGDefaultGroundCallback which assumes that the
|
// setagl.
|
||||||
// Earth is a sphere.
|
|
||||||
|
|
||||||
double FGInitialCondition::ComputeGeodAltitude(double geodLatitude)
|
double FGInitialCondition::ComputeGeodAltitude(double geodLatitude)
|
||||||
{
|
{
|
||||||
|
@ -978,11 +973,8 @@ bool FGInitialCondition::LoadLatitude(Element* position_el)
|
||||||
|
|
||||||
string lat_type = latitude_el->GetAttributeValue("type");
|
string lat_type = latitude_el->GetAttributeValue("type");
|
||||||
|
|
||||||
if (lat_type == "geod" || lat_type == "geodetic") {
|
if (lat_type == "geod" || lat_type == "geodetic")
|
||||||
double h = ComputeGeodAltitude(latitude);
|
SetGeodLatitudeRadIC(latitude);
|
||||||
position.SetPositionGeodetic(position.GetLongitude(), latitude, h);
|
|
||||||
lastLatitudeSet = setgeod;
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
position.SetLatitude(latitude);
|
position.SetLatitude(latitude);
|
||||||
lastLatitudeSet = setgeoc;
|
lastLatitudeSet = setgeoc;
|
||||||
|
@ -1491,10 +1483,14 @@ void FGInitialCondition::bind(FGPropertyManager* PropertyManager)
|
||||||
&FGInitialCondition::GetRRadpsIC,
|
&FGInitialCondition::GetRRadpsIC,
|
||||||
&FGInitialCondition::SetRRadpsIC,
|
&FGInitialCondition::SetRRadpsIC,
|
||||||
true);
|
true);
|
||||||
PropertyManager->Tie("ic/lat-geod-rad", &position,
|
PropertyManager->Tie("ic/lat-geod-rad", this,
|
||||||
&FGLocation::GetGeodLatitudeRad);
|
&FGInitialCondition::GetGeodLatitudeRadIC,
|
||||||
PropertyManager->Tie("ic/lat-geod-deg", &position,
|
&FGInitialCondition::SetGeodLatitudeRadIC,
|
||||||
&FGLocation::GetGeodLatitudeDeg);
|
true);
|
||||||
|
PropertyManager->Tie("ic/lat-geod-deg", this,
|
||||||
|
&FGInitialCondition::GetGeodLatitudeDegIC,
|
||||||
|
&FGInitialCondition::SetGeodLatitudeDegIC,
|
||||||
|
true);
|
||||||
PropertyManager->Tie("ic/geod-alt-ft", &position,
|
PropertyManager->Tie("ic/geod-alt-ft", &position,
|
||||||
&FGLocation::GetGeodAltitude);
|
&FGLocation::GetGeodAltitude);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,12 +49,13 @@ INCLUDES
|
||||||
|
|
||||||
#include "math/FGLocation.h"
|
#include "math/FGLocation.h"
|
||||||
#include "math/FGQuaternion.h"
|
#include "math/FGQuaternion.h"
|
||||||
|
#include "simgear/misc/sg_path.hxx"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -220,7 +221,7 @@ CLASS DOCUMENTATION
|
||||||
@property ic/r-rad_sec (read/write) Yaw rate initial condition in radians/second
|
@property ic/r-rad_sec (read/write) Yaw rate initial condition in radians/second
|
||||||
|
|
||||||
@author Tony Peden
|
@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 */
|
@param lat Initial latitude in degrees */
|
||||||
void SetLatitudeDegIC(double lat) { SetLatitudeRadIC(lat*degtorad); }
|
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.
|
/** Sets the initial longitude.
|
||||||
@param lon Initial longitude in degrees */
|
@param lon Initial longitude in degrees */
|
||||||
void SetLongitudeDegIC(double lon) { SetLongitudeRadIC(lon*degtorad); }
|
void SetLongitudeDegIC(double lon) { SetLongitudeRadIC(lon*degtorad); }
|
||||||
|
@ -369,6 +377,11 @@ public:
|
||||||
@return Initial geocentric latitude in degrees */
|
@return Initial geocentric latitude in degrees */
|
||||||
double GetLatitudeDegIC(void) const { return position.GetLatitudeDeg(); }
|
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.
|
/** Gets the initial longitude.
|
||||||
@return Initial longitude in degrees */
|
@return Initial longitude in degrees */
|
||||||
double GetLongitudeDegIC(void) const { return position.GetLongitudeDeg(); }
|
double GetLongitudeDegIC(void) const { return position.GetLongitudeDeg(); }
|
||||||
|
@ -628,6 +641,11 @@ public:
|
||||||
@return Initial latitude in radians */
|
@return Initial latitude in radians */
|
||||||
double GetLatitudeRadIC(void) const { return position.GetLatitude(); }
|
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.
|
/** Gets the initial longitude.
|
||||||
@return Initial longitude in radians */
|
@return Initial longitude in radians */
|
||||||
double GetLongitudeRadIC(void) const { return position.GetLongitude(); }
|
double GetLongitudeRadIC(void) const { return position.GetLongitude(); }
|
||||||
|
@ -660,7 +678,7 @@ public:
|
||||||
@param rstname The name of an initial conditions file
|
@param rstname The name of an initial conditions file
|
||||||
@param useStoredPath true if the stored path to the IC file should be used
|
@param useStoredPath true if the stored path to the IC file should be used
|
||||||
@return true if successful */
|
@return true if successful */
|
||||||
bool Load(std::string rstname, bool useStoredPath = true );
|
bool Load(const SGPath& rstname, bool useStoredPath = true );
|
||||||
|
|
||||||
/** Is an engine running ?
|
/** Is an engine running ?
|
||||||
@param index of the engine to be checked
|
@param index of the engine to be checked
|
||||||
|
|
|
@ -46,7 +46,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
IDENT(IdHdr, ID_MODELLOADER);
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -60,28 +60,21 @@ Element_ptr FGModelLoader::Open(Element *el)
|
||||||
|
|
||||||
if (!fname.empty()) {
|
if (!fname.empty()) {
|
||||||
FGXMLFileRead XMLFileRead;
|
FGXMLFileRead XMLFileRead;
|
||||||
string file;
|
SGPath path(SGPath::fromLocal8Bit(fname.c_str()));
|
||||||
|
|
||||||
try {
|
if (path.isRelative())
|
||||||
file = model->FindFullPathName(fname);
|
path = model->FindFullPathName(path);
|
||||||
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 (CachedFiles.find(file) != CachedFiles.end())
|
if (CachedFiles.find(path.utf8Str()) != CachedFiles.end())
|
||||||
document = CachedFiles[file];
|
document = CachedFiles[path.utf8Str()];
|
||||||
else {
|
else {
|
||||||
document = XMLFileRead.LoadXMLDocument(file);
|
document = XMLFileRead.LoadXMLDocument(path);
|
||||||
if (document == 0L) {
|
if (document == 0L) {
|
||||||
cerr << endl << el->ReadFrom()
|
cerr << endl << el->ReadFrom()
|
||||||
<< "Could not open file: " << file << endl;
|
<< "Could not open file: " << path << endl;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
CachedFiles[file] = document;
|
CachedFiles[path.utf8Str()] = document;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document->GetName() != el->GetName()) {
|
if (document->GetName() != el->GetName()) {
|
||||||
|
@ -93,19 +86,12 @@ Element_ptr FGModelLoader::Open(Element *el)
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
SGPath CheckPathName(const SGPath& path, const SGPath& filename) {
|
||||||
|
SGPath fullName = path/filename.utf8Str();
|
||||||
|
|
||||||
string CheckFullPathName(const string& path, const string& fname)
|
if (fullName.extension() != "xml")
|
||||||
{
|
fullName.concat(".xml");
|
||||||
string name = path + "/" + fname;
|
|
||||||
|
|
||||||
if (name.length() <=4 || name.substr(name.length()-4, 4) != ".xml")
|
return fullName.exists() ? fullName : SGPath();
|
||||||
name.append(".xml");
|
|
||||||
|
|
||||||
ifstream file(name.c_str());
|
|
||||||
if (!file.is_open())
|
|
||||||
return string();
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,13 @@ INCLUDES
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "FGXMLElement.h"
|
#include "FGXMLElement.h"
|
||||||
|
#include "simgear/misc/sg_path.hxx"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -75,7 +76,7 @@ private:
|
||||||
std::map<std::string, Element_ptr> CachedFiles;
|
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
|
#endif
|
||||||
|
|
|
@ -47,7 +47,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
IDENT(IdHdr,ID_OUTPUTFILE);
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -65,8 +65,8 @@ FGOutputFile::FGOutputFile(FGFDMExec* fdmex) :
|
||||||
bool FGOutputFile::InitModel(void)
|
bool FGOutputFile::InitModel(void)
|
||||||
{
|
{
|
||||||
if (FGOutputType::InitModel()) {
|
if (FGOutputType::InitModel()) {
|
||||||
if (Filename.empty()) {
|
if (Filename.isNull()) {
|
||||||
Filename = Name;
|
Filename = SGPath(Name);
|
||||||
runID_postfix = 0;
|
runID_postfix = 0;
|
||||||
}
|
}
|
||||||
return OpenFile();
|
return OpenFile();
|
||||||
|
@ -87,7 +87,7 @@ void FGOutputFile::SetStartNewOutput(void)
|
||||||
} else {
|
} else {
|
||||||
buf << Name << '_' << runID_postfix++;
|
buf << Name << '_' << runID_postfix++;
|
||||||
}
|
}
|
||||||
Filename = buf.str();
|
Filename = SGPath(buf.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseFile();
|
CloseFile();
|
||||||
|
|
|
@ -45,7 +45,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -106,9 +106,9 @@ public:
|
||||||
the next call to SetStartNewOutput().
|
the next call to SetStartNewOutput().
|
||||||
@param name new name */
|
@param name new name */
|
||||||
void SetOutputName(const std::string& fname) {
|
void SetOutputName(const std::string& fname) {
|
||||||
Name = FDMExec->GetRootDir() + fname;
|
Name = (FDMExec->GetRootDir()/fname).utf8Str();
|
||||||
runID_postfix = -1;
|
runID_postfix = -1;
|
||||||
Filename = std::string();
|
Filename = SGPath();
|
||||||
}
|
}
|
||||||
/** Generate the output. This is a pure method so it must be implemented by
|
/** Generate the output. This is a pure method so it must be implemented by
|
||||||
the classes that inherits from FGOutputFile.
|
the classes that inherits from FGOutputFile.
|
||||||
|
@ -116,7 +116,7 @@ public:
|
||||||
void Print(void) = 0;
|
void Print(void) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string Filename;
|
SGPath Filename;
|
||||||
|
|
||||||
/// Opens the file
|
/// Opens the file
|
||||||
virtual bool OpenFile(void) = 0;
|
virtual bool OpenFile(void) = 0;
|
||||||
|
|
|
@ -64,7 +64,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
IDENT(IdHdr,ID_OUTPUTTEXTFILE);
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -96,7 +96,7 @@ bool FGOutputTextFile::Load(Element* el)
|
||||||
bool FGOutputTextFile::OpenFile(void)
|
bool FGOutputTextFile::OpenFile(void)
|
||||||
{
|
{
|
||||||
datafile.clear();
|
datafile.clear();
|
||||||
datafile.open(Filename.c_str());
|
datafile.open(Filename);
|
||||||
if (!datafile) {
|
if (!datafile) {
|
||||||
cerr << endl << fgred << highint << "ERROR: unable to open the file "
|
cerr << endl << fgred << highint << "ERROR: unable to open the file "
|
||||||
<< reset << Filename.c_str() << endl
|
<< reset << Filename.c_str() << endl
|
||||||
|
@ -261,9 +261,9 @@ bool FGOutputTextFile::OpenFile(void)
|
||||||
void FGOutputTextFile::Print(void)
|
void FGOutputTextFile::Print(void)
|
||||||
{
|
{
|
||||||
streambuf* buffer;
|
streambuf* buffer;
|
||||||
string scratch = "";
|
string scratch = Filename.utf8Str();
|
||||||
|
|
||||||
if (Filename == "COUT" || Filename == "cout") {
|
if (to_upper(scratch) == "COUT") {
|
||||||
buffer = cout.rdbuf();
|
buffer = cout.rdbuf();
|
||||||
} else {
|
} else {
|
||||||
buffer = datafile.rdbuf();
|
buffer = datafile.rdbuf();
|
||||||
|
|
|
@ -41,12 +41,13 @@ INCLUDES
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include "FGOutputFile.h"
|
#include "FGOutputFile.h"
|
||||||
|
#include "simgear/io/iostreams/sgstream.hxx"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -89,7 +90,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string delimeter;
|
std::string delimeter;
|
||||||
std::ofstream datafile;
|
sg_ofstream datafile;
|
||||||
|
|
||||||
virtual bool OpenFile(void);
|
virtual bool OpenFile(void);
|
||||||
virtual void CloseFile(void) { if (datafile.is_open()) datafile.close(); }
|
virtual void CloseFile(void) { if (datafile.is_open()) datafile.close(); }
|
||||||
|
|
|
@ -58,7 +58,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
IDENT(IdHdr,ID_FGSCRIPT);
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -96,10 +96,11 @@ FGScript::~FGScript()
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
bool FGScript::LoadScript(const string& script, double default_dT,
|
bool FGScript::LoadScript(const SGPath& script, double default_dT,
|
||||||
const string& initfile)
|
const SGPath& initfile)
|
||||||
{
|
{
|
||||||
string aircraft="", initialize="", prop_name="";
|
SGPath initialize;
|
||||||
|
string aircraft="", prop_name="";
|
||||||
string notifyPropertyName="";
|
string notifyPropertyName="";
|
||||||
Element *element=0, *run_element=0, *event_element=0;
|
Element *element=0, *run_element=0, *event_element=0;
|
||||||
Element *set_element=0;
|
Element *set_element=0;
|
||||||
|
@ -171,9 +172,9 @@ bool FGScript::LoadScript(const string& script, double default_dT,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initfile.empty()) {
|
initialize = SGPath::fromLocal8Bit(element->GetAttributeValue("initialize").c_str());
|
||||||
initialize = element->GetAttributeValue("initialize");
|
if (initfile.isNull()) {
|
||||||
if (initialize.empty()) {
|
if (initialize.isNull()) {
|
||||||
cerr << "Initialization file must be specified in use element." << endl;
|
cerr << "Initialization file must be specified in use element." << endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,12 +43,13 @@ INCLUDES
|
||||||
#include "FGJSBBase.h"
|
#include "FGJSBBase.h"
|
||||||
#include "FGPropertyReader.h"
|
#include "FGPropertyReader.h"
|
||||||
#include "input_output/FGPropertyManager.h"
|
#include "input_output/FGPropertyManager.h"
|
||||||
|
#include "simgear/misc/sg_path.hxx"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -161,7 +162,7 @@ CLASS DOCUMENTATION
|
||||||
comes the "run" section, where the conditions are
|
comes the "run" section, where the conditions are
|
||||||
described in "event" clauses.</p>
|
described in "event" clauses.</p>
|
||||||
@author Jon S. Berndt
|
@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
|
default. If a file name is passed in, it will override the
|
||||||
one present in the script.
|
one present in the script.
|
||||||
@return true if successful */
|
@return true if successful */
|
||||||
bool LoadScript(const std::string& script, double default_dT,
|
bool LoadScript(const SGPath& script, double default_dT,
|
||||||
const std::string& initfile);
|
const SGPath& initfile);
|
||||||
|
|
||||||
/** This function is called each pass through the executive Run() method IF
|
/** This function is called each pass through the executive Run() method IF
|
||||||
scripting is enabled.
|
scripting is enabled.
|
||||||
|
|
|
@ -45,7 +45,7 @@ FORWARD DECLARATIONS
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
IDENT(IdHdr,ID_XMLELEMENT);
|
||||||
|
|
||||||
bool Element::converterIsInitialized = false;
|
bool Element::converterIsInitialized = false;
|
||||||
|
@ -467,12 +467,14 @@ double Element::FindElementValueAsNumberConvertTo(const string& el, const string
|
||||||
|
|
||||||
// Sanity check for angular values
|
// Sanity check for angular values
|
||||||
if ((supplied_units == "RAD") && (fabs(value) > 2 * M_PI)) {
|
if ((supplied_units == "RAD") && (fabs(value) > 2 * M_PI)) {
|
||||||
cerr << element->ReadFrom() << "The value " << value
|
cerr << element->ReadFrom() << element->GetName() << " value "
|
||||||
<< " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]" << endl;
|
<< value << " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]"
|
||||||
|
<< endl;
|
||||||
}
|
}
|
||||||
if ((supplied_units == "DEG") && (fabs(value) > 360.0)) {
|
if ((supplied_units == "DEG") && (fabs(value) > 360.0)) {
|
||||||
cerr << element->ReadFrom() << "The value " << value
|
cerr << element->ReadFrom() << element->GetName() << " value "
|
||||||
<< " DEG is outside the range [ -360 DEG ; +360 DEG ]" << endl;
|
<< 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)) {
|
if ((target_units == "RAD") && (fabs(value) > 2 * M_PI)) {
|
||||||
cerr << element->ReadFrom() << "The value " << value
|
cerr << element->ReadFrom() << element->GetName() << " value "
|
||||||
<< " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]" << endl;
|
<< value << " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]"
|
||||||
|
<< endl;
|
||||||
}
|
}
|
||||||
if ((target_units == "DEG") && (fabs(value) > 360.0)) {
|
if ((target_units == "DEG") && (fabs(value) > 360.0)) {
|
||||||
cerr << element->ReadFrom() << "The value " << value
|
cerr << element->ReadFrom() << element->GetName() << " value "
|
||||||
<< " DEG is outside the range [ -360 DEG ; +360 DEG ]" << endl;
|
<< value << " DEG is outside the range [ -360 DEG ; +360 DEG ]"
|
||||||
|
<< endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = DisperseValue(element, value, supplied_units, target_units);
|
value = DisperseValue(element, value, supplied_units, target_units);
|
||||||
|
|
|
@ -35,15 +35,18 @@ SENTRY
|
||||||
INCLUDES
|
INCLUDES
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#include "input_output/FGXMLParse.h"
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "input_output/FGXMLParse.h"
|
||||||
|
#include "simgear/misc/sg_path.hxx"
|
||||||
|
#include "simgear/io/iostreams/sgstream.hxx"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -56,20 +59,23 @@ public:
|
||||||
FGXMLFileRead(void) {}
|
FGXMLFileRead(void) {}
|
||||||
~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);
|
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 (!filename.isNull()) {
|
||||||
if (XML_filename.find(".xml") == std::string::npos) XML_filename += ".xml";
|
if (filename.extension().empty())
|
||||||
infile.open(XML_filename.c_str());
|
filename.concat(".xml");
|
||||||
|
|
||||||
|
infile.open(filename);
|
||||||
if ( !infile.is_open()) {
|
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;
|
return 0L;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -77,7 +83,7 @@ public:
|
||||||
return 0L;
|
return 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
readXML(infile, fparse, XML_filename);
|
readXML(infile, fparse, filename.utf8Str());
|
||||||
Element* document = fparse.GetDocument();
|
Element* document = fparse.GetDocument();
|
||||||
infile.close();
|
infile.close();
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ using std::string;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
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;
|
cout << "Could not get host net address by name..." << endl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned int ip;
|
unsigned long ip;
|
||||||
ip = inet_addr(address.c_str());
|
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;
|
cout << "Could not get host net address by number..." << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,8 @@ bool FGAccelerations::InitModel(void)
|
||||||
vGravAccel.InitMatrix();
|
vGravAccel.InitMatrix();
|
||||||
vBodyAccel.InitMatrix();
|
vBodyAccel.InitMatrix();
|
||||||
|
|
||||||
|
maxiter = 50;
|
||||||
|
matrixSize = iter = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,6 +257,7 @@ void FGAccelerations::ResolveFrictionForces(double dt)
|
||||||
FGColumnVector3 vdot, wdot;
|
FGColumnVector3 vdot, wdot;
|
||||||
vector<LagrangeMultiplier*>& multipliers = *in.MultipliersList;
|
vector<LagrangeMultiplier*>& multipliers = *in.MultipliersList;
|
||||||
size_t n = multipliers.size();
|
size_t n = multipliers.size();
|
||||||
|
matrixSize = n;
|
||||||
|
|
||||||
vFrictionForces.InitMatrix();
|
vFrictionForces.InitMatrix();
|
||||||
vFrictionMoments.InitMatrix();
|
vFrictionMoments.InitMatrix();
|
||||||
|
@ -303,7 +306,7 @@ void FGAccelerations::ResolveFrictionForces(double dt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the Lagrange multipliers with the projected Gauss-Seidel method
|
// 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.;
|
double norm = 0.;
|
||||||
|
|
||||||
for (unsigned int i=0; i < n; i++) {
|
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/fbx-gear-lbs", this, eX, (PMF)&FGAccelerations::GetGroundForces);
|
||||||
PropertyManager->Tie("forces/fby-gear-lbs", this, eY, (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);
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -40,6 +40,7 @@ INCLUDES
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "simgear/props/propertyObject.hxx"
|
||||||
#include "models/FGModel.h"
|
#include "models/FGModel.h"
|
||||||
#include "math/FGColumnVector3.h"
|
#include "math/FGColumnVector3.h"
|
||||||
#include "math/LagrangeMultiplier.h"
|
#include "math/LagrangeMultiplier.h"
|
||||||
|
@ -391,6 +392,7 @@ private:
|
||||||
FGColumnVector3 vGravAccel;
|
FGColumnVector3 vGravAccel;
|
||||||
FGColumnVector3 vFrictionForces;
|
FGColumnVector3 vFrictionForces;
|
||||||
FGColumnVector3 vFrictionMoments;
|
FGColumnVector3 vFrictionMoments;
|
||||||
|
simgear::PropertyObject<int> iter, maxiter, matrixSize;
|
||||||
|
|
||||||
int gravType;
|
int gravType;
|
||||||
bool gravTorque;
|
bool gravTorque;
|
||||||
|
|
|
@ -70,7 +70,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
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);
|
return CheckPathName(FDMExec->GetSystemsPath(), path);
|
||||||
if (!name.empty()) return name;
|
|
||||||
|
|
||||||
return CheckFullPathName(FDMExec->GetSystemsPath(), sysfilename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -50,7 +50,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -168,7 +168,7 @@ CLASS DOCUMENTATION
|
||||||
@property gear/tailhook-pos-norm
|
@property gear/tailhook-pos-norm
|
||||||
|
|
||||||
@author Jon S. Berndt
|
@author Jon S. Berndt
|
||||||
@version $Revision: 1.53 $
|
@version $Revision: 1.55 $
|
||||||
@see FGActuator
|
@see FGActuator
|
||||||
@see FGDeadBand
|
@see FGDeadBand
|
||||||
@see FGFCSFunction
|
@see FGFCSFunction
|
||||||
|
@ -430,7 +430,7 @@ public:
|
||||||
|
|
||||||
/** Sets the propeller pitch command for the specified engine
|
/** Sets the propeller pitch command for the specified engine
|
||||||
@param engine engine ID number
|
@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);
|
void SetPropAdvanceCmd(int engine, double cmd);
|
||||||
|
|
||||||
/** Sets the propeller feather command for the specified engine
|
/** Sets the propeller feather command for the specified engine
|
||||||
|
@ -544,7 +544,7 @@ public:
|
||||||
@return true if succesful */
|
@return true if succesful */
|
||||||
bool Load(Element* el);
|
bool Load(Element* el);
|
||||||
|
|
||||||
std::string FindFullPathName(const std::string& system_filename) const;
|
SGPath FindFullPathName(const SGPath& path) const;
|
||||||
|
|
||||||
void AddThrottle(void);
|
void AddThrottle(void);
|
||||||
double GetDt(void) const;
|
double GetDt(void) const;
|
||||||
|
|
|
@ -50,7 +50,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
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;
|
FGXMLFileRead XMLFile;
|
||||||
Element* document = XMLFile.LoadXMLDocument(fname);
|
Element* document = XMLFile.LoadXMLDocument(fname);
|
||||||
|
|
|
@ -46,7 +46,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -81,7 +81,7 @@ CLASS DOCUMENTATION
|
||||||
|
|
||||||
The class FGInput is the manager of the inputs requested by the user. It
|
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.
|
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
|
@param fname the name of the file from which the ouput directives should
|
||||||
be read.
|
be read.
|
||||||
@return true if the execution succeeded. */
|
@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.
|
/// Enables the input generation for all input instances.
|
||||||
void Enable(void) { enabled = true; }
|
void Enable(void) { enabled = true; }
|
||||||
|
|
|
@ -61,7 +61,7 @@ DEFINITIONS
|
||||||
GLOBAL DATA
|
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);
|
IDENT(IdHdr,ID_LGEAR);
|
||||||
|
|
||||||
// Body To Structural (body frame is rotated 180 deg about Y and lengths are given in
|
// 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";
|
property_name = base_property_name + "/WOW";
|
||||||
PropertyManager->Tie( property_name.c_str(), &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";
|
property_name = base_property_name + "/z-position";
|
||||||
PropertyManager->Tie( property_name.c_str(), (FGForce*)this,
|
PropertyManager->Tie( property_name.c_str(), (FGForce*)this,
|
||||||
&FGForce::GetLocationZ, &FGForce::SetLocationZ);
|
&FGForce::GetLocationZ, &FGForce::SetLocationZ);
|
||||||
|
|
|
@ -49,7 +49,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -178,7 +178,7 @@ CLASS DOCUMENTATION
|
||||||
</contact>
|
</contact>
|
||||||
@endcode
|
@endcode
|
||||||
@author Jon S. Berndt
|
@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
|
@see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
|
||||||
NASA-Ames", NASA CR-2497, January 1975
|
NASA-Ames", NASA CR-2497, January 1975
|
||||||
@see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
|
@see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
|
||||||
|
@ -273,7 +273,9 @@ public:
|
||||||
/** Get the console touchdown reporting feature
|
/** Get the console touchdown reporting feature
|
||||||
@return true if reporting is turned on */
|
@return true if reporting is turned on */
|
||||||
bool GetReport(void) const { return ReportEnable; }
|
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); }
|
void SetSteerCmd(double cmd) { SetSteerAngleDeg(cmd * maxSteerAngle); }
|
||||||
double GetstaticFCoeff(void) const { return staticFCoeff; }
|
double GetstaticFCoeff(void) const { return staticFCoeff; }
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -41,12 +41,13 @@ INCLUDES
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "math/FGModelFunctions.h"
|
#include "math/FGModelFunctions.h"
|
||||||
|
#include "simgear/misc/sg_path.hxx"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -100,7 +101,7 @@ public:
|
||||||
FGFDMExec* GetExec(void) {return FDMExec;}
|
FGFDMExec* GetExec(void) {return FDMExec;}
|
||||||
|
|
||||||
void SetPropertyManager(FGPropertyManager *fgpm) { PropertyManager=fgpm;}
|
void SetPropertyManager(FGPropertyManager *fgpm) { PropertyManager=fgpm;}
|
||||||
virtual std::string FindFullPathName(const std::string& filename) const;
|
virtual SGPath FindFullPathName(const SGPath& path) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
unsigned int exe_ctr;
|
unsigned int exe_ctr;
|
||||||
|
@ -119,4 +120,3 @@ protected:
|
||||||
}
|
}
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
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;
|
FGXMLFileRead XMLFile;
|
||||||
Element* document = XMLFile.LoadXMLDocument(fname);
|
Element* document = XMLFile.LoadXMLDocument(fname);
|
||||||
|
|
|
@ -47,7 +47,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -121,7 +121,7 @@ CLASS DOCUMENTATION
|
||||||
|
|
||||||
The class FGOutput is the manager of the outputs requested by the user. It
|
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.
|
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
|
@param fname the name of the file from which the ouput directives should
|
||||||
be read.
|
be read.
|
||||||
@return true if the execution succeeded. */
|
@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.
|
/// Enables the output generation for all output instances.
|
||||||
void Enable(void) { enabled = true; }
|
void Enable(void) { enabled = true; }
|
||||||
/// Disables the output generation for all output instances.
|
/// Disables the output generation for all output instances.
|
||||||
|
|
|
@ -67,19 +67,19 @@ INCLUDES
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#include "initialization/FGInitialCondition.h"
|
#include "initialization/FGInitialCondition.h"
|
||||||
#include "FGPropagate.h"
|
#include "FGPropagate.h"
|
||||||
#include "FGGroundReactions.h"
|
#include "FGGroundReactions.h"
|
||||||
#include "FGFDMExec.h"
|
#include "FGFDMExec.h"
|
||||||
#include "input_output/FGPropertyManager.h"
|
#include "input_output/FGPropertyManager.h"
|
||||||
|
#include "simgear/io/iostreams/sgstream.hxx"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
IDENT(IdHdr,ID_PROPAGATE);
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -659,21 +659,21 @@ void FGPropagate::DumpState(void)
|
||||||
|
|
||||||
void FGPropagate::WriteStateFile(int num)
|
void FGPropagate::WriteStateFile(int num)
|
||||||
{
|
{
|
||||||
ofstream outfile;
|
sg_ofstream outfile;
|
||||||
|
|
||||||
if (num == 0) return;
|
if (num == 0) return;
|
||||||
|
|
||||||
string filename = FDMExec->GetFullAircraftPath();
|
SGPath path = FDMExec->GetFullAircraftPath();
|
||||||
|
|
||||||
if (filename.empty()) filename = "initfile.";
|
if (path.isNull()) path = SGPath("initfile.");
|
||||||
else filename.append("/initfile.");
|
else path.append("initfile.");
|
||||||
|
|
||||||
// Append sim time to the filename since there may be more than one created during a simulation run
|
// 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) {
|
switch(num) {
|
||||||
case 1:
|
case 1:
|
||||||
outfile.open(filename.c_str());
|
outfile.open(path);
|
||||||
if (outfile.is_open()) {
|
if (outfile.is_open()) {
|
||||||
outfile << "<?xml version=\"1.0\"?>" << endl;
|
outfile << "<?xml version=\"1.0\"?>" << endl;
|
||||||
outfile << "<initialize name=\"reset00\">" << endl;
|
outfile << "<initialize name=\"reset00\">" << endl;
|
||||||
|
@ -689,11 +689,12 @@ void FGPropagate::WriteStateFile(int num)
|
||||||
outfile << "</initialize>" << endl;
|
outfile << "</initialize>" << endl;
|
||||||
outfile.close();
|
outfile.close();
|
||||||
} else {
|
} 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;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
outfile.open(filename.c_str());
|
outfile.open(path);
|
||||||
if (outfile.is_open()) {
|
if (outfile.is_open()) {
|
||||||
outfile << "<?xml version=\"1.0\"?>" << endl;
|
outfile << "<?xml version=\"1.0\"?>" << endl;
|
||||||
outfile << "<initialize name=\"IC File\" version=\"2.0\">" << endl;
|
outfile << "<initialize name=\"IC File\" version=\"2.0\">" << endl;
|
||||||
|
@ -725,7 +726,8 @@ void FGPropagate::WriteStateFile(int num)
|
||||||
outfile << "</initialize>" << endl;
|
outfile << "</initialize>" << endl;
|
||||||
outfile.close();
|
outfile.close();
|
||||||
} else {
|
} 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;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -65,7 +65,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
IDENT(IdHdr,ID_PROPULSION);
|
||||||
|
|
||||||
extern short debug_lvl;
|
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);
|
SGPath name = CheckPathName(FDMExec->GetFullAircraftPath()/string("Engines"),
|
||||||
if (!name.empty()) return name;
|
path);
|
||||||
|
if (!name.isNull()) return name;
|
||||||
|
|
||||||
return CheckFullPathName(FDMExec->GetEnginePath(), filename);
|
return CheckPathName(FDMExec->GetEnginePath(), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -50,7 +50,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -93,7 +93,7 @@ CLASS DOCUMENTATION
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
@author Jon S. Berndt
|
@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
|
@see
|
||||||
FGEngine
|
FGEngine
|
||||||
FGTank
|
FGTank
|
||||||
|
@ -180,7 +180,7 @@ public:
|
||||||
const FGColumnVector3& GetTanksMoment(void);
|
const FGColumnVector3& GetTanksMoment(void);
|
||||||
double GetTanksWeight(void) const;
|
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 int GetActiveEngine(void) const {return ActiveEngine;}
|
||||||
inline bool GetFuelFreeze(void) const {return FuelFreeze;}
|
inline bool GetFuelFreeze(void) const {return FuelFreeze;}
|
||||||
|
|
||||||
|
|
0
src/FDM/JSBSim/models/flight_control/FGAngles.cpp
Executable file → Normal file
0
src/FDM/JSBSim/models/flight_control/FGAngles.cpp
Executable file → Normal file
|
@ -53,7 +53,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
IDENT(IdHdr,ID_ENGINE);
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -158,7 +158,7 @@ void FGEngine::LoadThrusterInputs()
|
||||||
{
|
{
|
||||||
Thruster->in.TotalDeltaT = in.TotalDeltaT;
|
Thruster->in.TotalDeltaT = in.TotalDeltaT;
|
||||||
Thruster->in.H_agl = in.H_agl;
|
Thruster->in.H_agl = in.H_agl;
|
||||||
Thruster->in.PQR = in.PQR;
|
Thruster->in.PQRi = in.PQRi;
|
||||||
Thruster->in.AeroPQR = in.AeroPQR;
|
Thruster->in.AeroPQR = in.AeroPQR;
|
||||||
Thruster->in.AeroUVW = in.AeroUVW;
|
Thruster->in.AeroUVW = in.AeroUVW;
|
||||||
Thruster->in.Density = in.Density;
|
Thruster->in.Density = in.Density;
|
||||||
|
|
|
@ -53,7 +53,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -111,7 +111,7 @@ CLASS DOCUMENTATION
|
||||||
documentation for engine and thruster classes.
|
documentation for engine and thruster classes.
|
||||||
</pre>
|
</pre>
|
||||||
@author Jon S. Berndt
|
@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;
|
double H_agl;
|
||||||
FGColumnVector3 AeroUVW;
|
FGColumnVector3 AeroUVW;
|
||||||
FGColumnVector3 AeroPQR;
|
FGColumnVector3 AeroPQR;
|
||||||
FGColumnVector3 PQR;
|
FGColumnVector3 PQRi;
|
||||||
std::vector <double> ThrottleCmd;
|
std::vector <double> ThrottleCmd;
|
||||||
std::vector <double> MixtureCmd;
|
std::vector <double> MixtureCmd;
|
||||||
std::vector <double> ThrottlePos;
|
std::vector <double> ThrottlePos;
|
||||||
|
|
|
@ -45,7 +45,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
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);
|
Ixx = max(prop_element->FindElementValueAsNumberConvertTo("ixx", "SLUG*FT2"), 0.001);
|
||||||
|
|
||||||
Sense_multiplier = 1.0;
|
Sense_multiplier = 1.0;
|
||||||
if (prop_element->HasAttribute("version"))
|
if (prop_element->HasAttribute("version")
|
||||||
if (prop_element->GetAttributeValueAsNumber("version") > 1.0)
|
&& prop_element->GetAttributeValueAsNumber("version") > 1.0)
|
||||||
Sense_multiplier = -1.0;
|
Sense_multiplier = -1.0;
|
||||||
|
|
||||||
if (prop_element->FindElement("diameter"))
|
if (prop_element->FindElement("diameter"))
|
||||||
|
@ -146,6 +146,7 @@ FGPropeller::FGPropeller(FGFDMExec* exec, Element* prop_element, int num)
|
||||||
Type = ttPropeller;
|
Type = ttPropeller;
|
||||||
RPM = 0;
|
RPM = 0;
|
||||||
vTorque.InitMatrix();
|
vTorque.InitMatrix();
|
||||||
|
vH.InitMatrix();
|
||||||
D4 = Diameter*Diameter*Diameter*Diameter;
|
D4 = Diameter*Diameter*Diameter*Diameter;
|
||||||
D5 = D4*Diameter;
|
D5 = D4*Diameter;
|
||||||
Pitch = MinPitch;
|
Pitch = MinPitch;
|
||||||
|
@ -186,6 +187,14 @@ FGPropeller::~FGPropeller()
|
||||||
Debug(1);
|
Debug(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGPropeller::ResetToIC(void)
|
||||||
|
{
|
||||||
|
FGThruster::ResetToIC();
|
||||||
|
Vinduced = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
//
|
//
|
||||||
// We must be getting the aerodynamic velocity here, NOT the inertial velocity.
|
// 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;
|
double Vtip = RPS * Diameter * M_PI;
|
||||||
HelicalTipMach = sqrt(Vtip*Vtip + Vel*Vel) / in.Soundspeed;
|
HelicalTipMach = sqrt(Vtip*Vtip + Vel*Vel) / in.Soundspeed;
|
||||||
|
|
||||||
PowerAvailable = EnginePower - GetPowerRequired();
|
|
||||||
|
|
||||||
if (RPS > 0.0) J = Vel / (Diameter * RPS); // Calculate J normally
|
if (RPS > 0.0) J = Vel / (Diameter * RPS); // Calculate J normally
|
||||||
else J = Vel / Diameter;
|
else J = Vel / Diameter;
|
||||||
|
|
||||||
|
PowerAvailable = EnginePower - GetPowerRequired();
|
||||||
|
|
||||||
if (MaxPitch == MinPitch) { // Fixed pitch prop
|
if (MaxPitch == MinPitch) { // Fixed pitch prop
|
||||||
ThrustCoeff = cThrust->GetValue(J);
|
ThrustCoeff = cThrust->GetValue(J);
|
||||||
} else { // Variable pitch prop
|
} else { // Variable pitch prop
|
||||||
|
@ -265,8 +274,6 @@ double FGPropeller::Calculate(double EnginePower)
|
||||||
// FGForce::GetBodyForces() function.
|
// FGForce::GetBodyForces() function.
|
||||||
|
|
||||||
vH(eX) = Ixx*omega*Sense*Sense_multiplier;
|
vH(eX) = Ixx*omega*Sense*Sense_multiplier;
|
||||||
vH(eY) = 0.0;
|
|
||||||
vH(eZ) = 0.0;
|
|
||||||
|
|
||||||
if (omega > 0.0) ExcessTorque = PowerAvailable / omega;
|
if (omega > 0.0) ExcessTorque = PowerAvailable / omega;
|
||||||
else ExcessTorque = PowerAvailable / 1.0;
|
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
|
// Transform Torque and momentum first, as PQR is used in this
|
||||||
// equation and cannot be transformed itself.
|
// 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
|
return Thrust; // return thrust in pounds
|
||||||
}
|
}
|
||||||
|
@ -286,13 +293,7 @@ double FGPropeller::Calculate(double EnginePower)
|
||||||
|
|
||||||
double FGPropeller::GetPowerRequired(void)
|
double FGPropeller::GetPowerRequired(void)
|
||||||
{
|
{
|
||||||
double cPReq, J;
|
double cPReq;
|
||||||
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;
|
|
||||||
|
|
||||||
if (MaxPitch == MinPitch) { // Fixed pitch prop
|
if (MaxPitch == MinPitch) { // Fixed pitch prop
|
||||||
cPReq = cPower->GetValue(J);
|
cPReq = cPower->GetValue(J);
|
||||||
|
@ -303,7 +304,7 @@ double FGPropeller::GetPowerRequired(void)
|
||||||
|
|
||||||
// do normal calculation when propeller is neither feathered nor reversed
|
// do normal calculation when propeller is neither feathered nor reversed
|
||||||
// Note: This method of feathering and reversing was added to support the
|
// 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.
|
// now feathering and reversing should be done in Manual Pitch Mode.
|
||||||
if (!Feathered) {
|
if (!Feathered) {
|
||||||
if (!Reversed) {
|
if (!Reversed) {
|
||||||
|
@ -349,9 +350,10 @@ double FGPropeller::GetPowerRequired(void)
|
||||||
// Apply optional Mach effects from CP_MACH table
|
// Apply optional Mach effects from CP_MACH table
|
||||||
if (CpMach) cPReq *= CpMach->GetValue(HelicalTipMach);
|
if (CpMach) cPReq *= CpMach->GetValue(HelicalTipMach);
|
||||||
|
|
||||||
|
double RPS = RPM / 60.0;
|
||||||
double local_RPS = RPS < 0.01 ? 0.01 : RPS;
|
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);
|
vTorque(eX) = -Sense*PowerRequired / (local_RPS*2.0*M_PI);
|
||||||
|
|
||||||
return PowerRequired;
|
return PowerRequired;
|
||||||
|
|
|
@ -45,7 +45,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -57,13 +57,14 @@ namespace JSBSim {
|
||||||
CLASS DOCUMENTATION
|
CLASS DOCUMENTATION
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
/** FGPropeller models a propeller given the tabular data for Ct and Cp,
|
/** FGPropeller models a propeller given the tabular data for Ct (thrust) and
|
||||||
indexed by the advance ratio "J".
|
Cp (power), indexed by the advance ratio "J".
|
||||||
|
|
||||||
<h3>Configuration File Format:</h3>
|
### Configuration File Format
|
||||||
@code
|
|
||||||
|
~~~{.xml}
|
||||||
<sense> {1 | -1} </sense>
|
<sense> {1 | -1} </sense>
|
||||||
<propeller name="{string}">
|
<propeller name="{string}" version="{string}">
|
||||||
<ixx> {number} </ixx>
|
<ixx> {number} </ixx>
|
||||||
<diameter unit="IN"> {number} </diameter>
|
<diameter unit="IN"> {number} </diameter>
|
||||||
<numblades> {number} </numblades>
|
<numblades> {number} </numblades>
|
||||||
|
@ -102,11 +103,11 @@ CLASS DOCUMENTATION
|
||||||
</tableData>
|
</tableData>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
</propeller>
|
</propeller>
|
||||||
@endcode
|
~~~
|
||||||
|
|
||||||
|
### Configuration Parameters
|
||||||
|
|
||||||
<h3>Configuration Parameters:</h3>
|
|
||||||
<pre>
|
<pre>
|
||||||
\<ixx> - Propeller rotational inertia.
|
\<ixx> - Propeller rotational inertia.
|
||||||
\<diameter> - Propeller disk diameter.
|
\<diameter> - Propeller disk diameter.
|
||||||
|
@ -126,25 +127,40 @@ CLASS DOCUMENTATION
|
||||||
\<cp_factor> - A multiplier for the coefficients of power.
|
\<cp_factor> - A multiplier for the coefficients of power.
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Two tables are needed. One for coefficient of thrust (Ct) and one for
|
Two tables are needed. One for coefficient of thrust (Ct) and one for
|
||||||
coefficient of power (Cp).
|
coefficient of power (Cp).
|
||||||
|
|
||||||
Two tables are optional. They apply a factor to Ct and Cp based on the
|
Two tables are optional. They apply a factor to Ct and Cp based on the
|
||||||
helical tip Mach.
|
helical tip Mach.
|
||||||
<br>
|
|
||||||
|
|
||||||
Several references were helpful, here:<ul>
|
In addition to thrust, the propeller applies two moments to the aircraft:
|
||||||
<li>Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
|
- The torque that tends to roll the aircraft in the direction opposite to the
|
||||||
Wiley & Sons, 1979 ISBN 0-471-03032-5</li>
|
propeller rotation,
|
||||||
<li>Edwin Hartman, David Biermann, "The Aerodynamic Characteristics of
|
- and the gyroscopic moment.
|
||||||
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>
|
It should be noted that historically the gyroscopic moment had an incorrect
|
||||||
<li>Various NACA Technical Notes and Reports</li>
|
sign. The correct sign can be obtained by specifying a **version** attribute
|
||||||
</ul>
|
higher than 1.0 to the propeller definition
|
||||||
@author Jon S. Berndt
|
~~~.xml
|
||||||
@version $Id: FGPropeller.h,v 1.26 2016/01/02 17:42:53 bcoconni Exp $
|
<propeller name="a_prop" version="1.1">
|
||||||
@see FGEngine
|
<!-- propeller definition -->
|
||||||
@see FGThruster
|
</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
|
/// Destructor for FGPropeller - deletes the FGTable objects
|
||||||
~FGPropeller();
|
~FGPropeller();
|
||||||
|
|
||||||
|
/// Reset the initial conditions.
|
||||||
|
void ResetToIC(void);
|
||||||
|
|
||||||
/** Sets the Revolutions Per Minute for the propeller. Normally the propeller
|
/** Sets the Revolutions Per Minute for the propeller. Normally the propeller
|
||||||
instance will calculate its own rotational velocity, given the Torque
|
instance will calculate its own rotational velocity, given the Torque
|
||||||
produced by the engine and integrating over time using the standard
|
produced by the engine and integrating over time using the standard
|
||||||
equation for rotational acceleration "a": a = Q/I , where Q is Torque and
|
equation for rotational acceleration \f$a\f$: \f$a = Q/I\f$ , where
|
||||||
I is moment of inertia for the propeller.
|
\f$Q\f$ is Torque and \f$I\f$ is moment of inertia for the propeller.
|
||||||
@param rpm the rotational velocity of the propeller */
|
@param rpm the rotational velocity of the propeller */
|
||||||
void SetRPM(double rpm) {RPM = rpm;}
|
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;}
|
void SetEngineRPM(double rpm) {RPM = rpm/GearRatio;}
|
||||||
|
|
||||||
/// Returns true of this propeller is variable pitch
|
/// Returns true of this propeller is variable pitch
|
||||||
|
@ -186,6 +206,9 @@ public:
|
||||||
@param pitch the pitch of the blade in degrees. */
|
@param pitch the pitch of the blade in degrees. */
|
||||||
void SetPitch(double pitch) {Pitch = pitch;}
|
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;}
|
void SetAdvance(double advance) {Advance = advance;}
|
||||||
|
|
||||||
/// Sets the P-Factor constant
|
/// Sets the P-Factor constant
|
||||||
|
@ -255,20 +278,35 @@ public:
|
||||||
would be slowed.
|
would be slowed.
|
||||||
@return the thrust in pounds */
|
@return the thrust in pounds */
|
||||||
double Calculate(double EnginePower);
|
double Calculate(double EnginePower);
|
||||||
|
/// Retrieves the P-Factor constant
|
||||||
FGColumnVector3 GetPFactor(void) const;
|
FGColumnVector3 GetPFactor(void) const;
|
||||||
|
/// Generate the labels for the thruster standard CSV output
|
||||||
std::string GetThrusterLabels(int id, const std::string& delimeter);
|
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);
|
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; }
|
void SetReverseCoef (double c) { Reverse_coef = c; }
|
||||||
|
/// Retrieves the reverse pitch command.
|
||||||
double GetReverseCoef (void) const { return Reverse_coef; }
|
double GetReverseCoef (void) const { return Reverse_coef; }
|
||||||
|
/// If true, sets the propeller in reversed position.
|
||||||
void SetReverse (bool r) { Reversed = r; }
|
void SetReverse (bool r) { Reversed = r; }
|
||||||
|
/// Returns true if the propeller is in reverse position.
|
||||||
bool GetReverse (void) const { return Reversed; }
|
bool GetReverse (void) const { return Reversed; }
|
||||||
|
/// If true, sets the propeller in feathered position.
|
||||||
void SetFeather (bool f) { Feathered = f; }
|
void SetFeather (bool f) { Feathered = f; }
|
||||||
|
/// Returns true if the propeller is in feathered position.
|
||||||
bool GetFeather (void) const { return Feathered; }
|
bool GetFeather (void) const { return Feathered; }
|
||||||
|
/// Retrieves the thrust coefficient
|
||||||
double GetThrustCoefficient(void) const {return ThrustCoeff;}
|
double GetThrustCoefficient(void) const {return ThrustCoeff;}
|
||||||
|
/// Retrieves the Mach number at the propeller tips.
|
||||||
double GetHelicalTipMach(void) const {return HelicalTipMach;}
|
double GetHelicalTipMach(void) const {return HelicalTipMach;}
|
||||||
|
/// Returns a non-zero value if the propeller is constant speed.
|
||||||
int GetConstantSpeed(void) const {return ConstantSpeed;}
|
int GetConstantSpeed(void) const {return ConstantSpeed;}
|
||||||
|
/// Set the propeller induced velocity
|
||||||
void SetInducedVelocity(double Vi) {Vinduced = Vi;}
|
void SetInducedVelocity(double Vi) {Vinduced = Vi;}
|
||||||
|
/// Get the propeller induced velocity.
|
||||||
double GetInducedVelocity(void) const {return Vinduced;}
|
double GetInducedVelocity(void) const {return Vinduced;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -48,7 +48,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
IDENT(IdHdr,ID_TANK);
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -465,6 +465,14 @@ void FGTank::bind(FGPropertyManager* PropertyManager)
|
||||||
PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetIyy);
|
PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetIyy);
|
||||||
property_name = base_property_name + "/local-izz-slug_ft2";
|
property_name = base_property_name + "/local-izz-slug_ft2";
|
||||||
PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetIzz);
|
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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -53,7 +53,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -283,6 +283,13 @@ public:
|
||||||
double GetIyy(void) const {return Iyy;}
|
double GetIyy(void) const {return Iyy;}
|
||||||
double GetIzz(void) const {return Izz;}
|
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;}
|
double GetStandpipe(void) const {return Standpipe;}
|
||||||
|
|
||||||
int GetPriority(void) const {return Priority;}
|
int GetPriority(void) const {return Priority;}
|
||||||
|
|
|
@ -46,7 +46,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
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
|
FORWARD DECLARATIONS
|
||||||
|
@ -74,7 +74,7 @@ CLASS DOCUMENTATION
|
||||||
1.57 (pi/2) results in no thrust at all.
|
1.57 (pi/2) results in no thrust at all.
|
||||||
|
|
||||||
@author Jon Berndt
|
@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 {
|
struct Inputs {
|
||||||
double TotalDeltaT;
|
double TotalDeltaT;
|
||||||
double H_agl;
|
double H_agl;
|
||||||
FGColumnVector3 PQR;
|
FGColumnVector3 PQRi;
|
||||||
FGColumnVector3 AeroPQR;
|
FGColumnVector3 AeroPQR;
|
||||||
FGColumnVector3 AeroUVW;
|
FGColumnVector3 AeroUVW;
|
||||||
double Density;
|
double Density;
|
||||||
|
|
11
src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp
Executable file → Normal file
11
src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp
Executable file → Normal file
|
@ -55,7 +55,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
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);
|
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.
|
// ToDo: Need to make sure units are properly accounted for below.
|
||||||
|
|
||||||
if (el->FindElement("milthrust"))
|
|
||||||
MilThrust = el->FindElementValueAsNumberConvertTo("milthrust","LBS");
|
|
||||||
if (el->FindElement("idlen1"))
|
if (el->FindElement("idlen1"))
|
||||||
IdleN1 = el->FindElementValueAsNumber("idlen1");
|
IdleN1 = el->FindElementValueAsNumber("idlen1");
|
||||||
if (el->FindElement("maxn1"))
|
if (el->FindElement("maxn1"))
|
||||||
|
@ -197,7 +195,8 @@ void FGTurboProp::Calculate(void)
|
||||||
|
|
||||||
ThrottlePos = in.ThrottlePos[EngineNumber];
|
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();
|
RPM = Thruster->GetEngineRPM();
|
||||||
if (thrusterType == FGThruster::ttPropeller) {
|
if (thrusterType == FGThruster::ttPropeller) {
|
||||||
((FGPropeller*)Thruster)->SetAdvance(in.PropAdvance[EngineNumber]);
|
((FGPropeller*)Thruster)->SetAdvance(in.PropAdvance[EngineNumber]);
|
||||||
|
@ -320,7 +319,6 @@ double FGTurboProp::Off(void)
|
||||||
|
|
||||||
double FGTurboProp::Run(void)
|
double FGTurboProp::Run(void)
|
||||||
{
|
{
|
||||||
double thrust = 0.0;
|
|
||||||
double EngPower_HP;
|
double EngPower_HP;
|
||||||
|
|
||||||
Running = true; Starter = false; EngStarting = false;
|
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
|
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);
|
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;
|
N1 = 0.0;
|
||||||
HP = 0.0;
|
HP = 0.0;
|
||||||
Type = etTurboprop;
|
Type = etTurboprop;
|
||||||
MilThrust = 10000.0;
|
|
||||||
IdleN1 = 30.0;
|
IdleN1 = 30.0;
|
||||||
MaxN1 = 100.0;
|
MaxN1 = 100.0;
|
||||||
Reversed = false;
|
Reversed = false;
|
||||||
|
@ -590,7 +586,6 @@ void FGTurboProp::Debug(int from)
|
||||||
if (from == 2) { // called from Load()
|
if (from == 2) { // called from Load()
|
||||||
cout << "\n ****MUJ MOTOR TURBOPROP****\n";
|
cout << "\n ****MUJ MOTOR TURBOPROP****\n";
|
||||||
cout << "\n Engine Name: " << Name << endl;
|
cout << "\n Engine Name: " << Name << endl;
|
||||||
cout << " MilThrust: " << MilThrust << endl;
|
|
||||||
cout << " IdleN1: " << IdleN1 << endl;
|
cout << " IdleN1: " << IdleN1 << endl;
|
||||||
cout << " MaxN1: " << MaxN1 << endl;
|
cout << " MaxN1: " << MaxN1 << endl;
|
||||||
|
|
||||||
|
|
6
src/FDM/JSBSim/models/propulsion/FGTurboProp.h
Executable file → Normal file
6
src/FDM/JSBSim/models/propulsion/FGTurboProp.h
Executable file → Normal file
|
@ -46,7 +46,7 @@ INCLUDES
|
||||||
#include "FGEngine.h"
|
#include "FGEngine.h"
|
||||||
#include "math/FGTable.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
|
FORWARD DECLARATIONS
|
||||||
|
@ -121,7 +121,6 @@ public:
|
||||||
bool GetCutoff(void) const { return Cutoff; }
|
bool GetCutoff(void) const { return Cutoff; }
|
||||||
|
|
||||||
double GetN1(void) const {return N1;}
|
double GetN1(void) const {return N1;}
|
||||||
double GetEPR(void) const {return EPR;}
|
|
||||||
double GetITT(void) const {return Eng_ITT_degC;}
|
double GetITT(void) const {return Eng_ITT_degC;}
|
||||||
double GetEngStarting(void) const { return EngStarting; }
|
double GetEngStarting(void) const { return EngStarting; }
|
||||||
|
|
||||||
|
@ -132,7 +131,6 @@ public:
|
||||||
inline int GetCondition(void) const { return Condition; }
|
inline int GetCondition(void) const { return Condition; }
|
||||||
|
|
||||||
void SetPhase( phaseType p ) { phase = p; }
|
void SetPhase( phaseType p ) { phase = p; }
|
||||||
void SetEPR(double epr) {EPR = epr;}
|
|
||||||
void SetReverse(bool reversed) { Reversed = reversed; }
|
void SetReverse(bool reversed) { Reversed = reversed; }
|
||||||
void SetCutoff(bool cutoff) { Cutoff = cutoff; }
|
void SetCutoff(bool cutoff) { Cutoff = cutoff; }
|
||||||
|
|
||||||
|
@ -145,7 +143,6 @@ public:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
phaseType phase; ///< Operating mode, or "phase"
|
phaseType phase; ///< Operating mode, or "phase"
|
||||||
double MilThrust; ///< Maximum Unaugmented Thrust, static @ S.L. (lbf)
|
|
||||||
double IdleN1; ///< Idle N1
|
double IdleN1; ///< Idle N1
|
||||||
double N1; ///< N1
|
double N1; ///< N1
|
||||||
double MaxN1; ///< N1 at 100% throttle
|
double MaxN1; ///< N1 at 100% throttle
|
||||||
|
@ -155,7 +152,6 @@ private:
|
||||||
bool Reversed;
|
bool Reversed;
|
||||||
bool Cutoff;
|
bool Cutoff;
|
||||||
|
|
||||||
double EPR;
|
|
||||||
double OilPressure_psi;
|
double OilPressure_psi;
|
||||||
double OilTemp_degK;
|
double OilTemp_degK;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
|
||||||
// gadgets
|
// gadgets
|
||||||
inline float norm(float f) { return f<1 ? 1/f : f; }
|
|
||||||
inline float abs(float f) { return f<0 ? -f : f; }
|
inline float abs(float f) { return f<0 ? -f : f; }
|
||||||
|
|
||||||
// Solver threshold. How close to the solution are we trying
|
// Solver threshold. How close to the solution are we trying
|
||||||
|
@ -57,6 +56,9 @@ Airplane::Airplane()
|
||||||
_tailIncidence = 0;
|
_tailIncidence = 0;
|
||||||
|
|
||||||
_failureMsg = 0;
|
_failureMsg = 0;
|
||||||
|
_wingsN = 0;
|
||||||
|
_cgMaxX = -1e6;
|
||||||
|
_cgMinX = 1e6;
|
||||||
}
|
}
|
||||||
|
|
||||||
Airplane::~Airplane()
|
Airplane::~Airplane()
|
||||||
|
@ -113,16 +115,6 @@ void Airplane::calcFuelWeights()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlMap* Airplane::getControlMap()
|
|
||||||
{
|
|
||||||
return &_controls;
|
|
||||||
}
|
|
||||||
|
|
||||||
Model* Airplane::getModel()
|
|
||||||
{
|
|
||||||
return &_model;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Airplane::getPilotAccel(float* out)
|
void Airplane::getPilotAccel(float* out)
|
||||||
{
|
{
|
||||||
State* s = _model.getState();
|
State* s = _model.getState();
|
||||||
|
@ -145,43 +137,6 @@ void Airplane::getPilotAccel(float* out)
|
||||||
// FIXME: rotational & centripetal acceleration needed
|
// 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()
|
void Airplane::updateGearState()
|
||||||
{
|
{
|
||||||
for(int i=0; i<_gears.size(); i++) {
|
for(int i=0; i<_gears.size(); i++) {
|
||||||
|
@ -247,51 +202,6 @@ void Airplane::addSolutionWeight(bool approach, int idx, float wgt)
|
||||||
_solveWeights.add(w);
|
_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,
|
void Airplane::addFuselage(float* front, float* back, float width,
|
||||||
float taper, float mid,
|
float taper, float mid,
|
||||||
float cx, float cy, float cz, float idrag)
|
float cx, float cy, float cz, float idrag)
|
||||||
|
@ -330,21 +240,10 @@ void Airplane::addGear(Gear* gear)
|
||||||
g->gear = gear;
|
g->gear = gear;
|
||||||
g->surf = 0;
|
g->surf = 0;
|
||||||
_gears.add(g);
|
_gears.add(g);
|
||||||
}
|
float pos[3];
|
||||||
|
g->gear->getPosition(pos);
|
||||||
void Airplane::addHook(Hook* hook)
|
if (pos[0] > _cgMaxX) _cgMaxX = pos[0];
|
||||||
{
|
if (pos[0] < _cgMinX) _cgMinX = pos[0];
|
||||||
_model.addHook(hook);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Airplane::addHitch(Hitch* hitch)
|
|
||||||
{
|
|
||||||
_model.addHitch(hitch);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Airplane::addLaunchbar(Launchbar* launchbar)
|
|
||||||
{
|
|
||||||
_model.addLaunchbar(launchbar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Airplane::addThruster(Thruster* thruster, float mass, float* cg)
|
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);
|
_thrusters.add(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Use ballast to redistribute mass, this is NOT added to empty weight.
|
||||||
void Airplane::addBallast(float* pos, float mass)
|
void Airplane::addBallast(float* pos, float mass)
|
||||||
{
|
{
|
||||||
_model.getBody()->addMass(mass, pos);
|
_model.getBody()->addMass(mass, pos, true);
|
||||||
_ballast += mass;
|
_ballast += mass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Masses configurable at runtime, e.g. cargo, pax
|
||||||
int Airplane::addWeight(float* pos, float size)
|
int Airplane::addWeight(float* pos, float size)
|
||||||
{
|
{
|
||||||
WeightRec* wr = new WeightRec();
|
WeightRec* wr = new WeightRec();
|
||||||
|
@ -377,6 +278,7 @@ int Airplane::addWeight(float* pos, float size)
|
||||||
return _weights.add(wr);
|
return _weights.add(wr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change weight of a previously added mass point
|
||||||
void Airplane::setWeight(int handle, float mass)
|
void Airplane::setWeight(int handle, float mass)
|
||||||
{
|
{
|
||||||
WeightRec* wr = (WeightRec*)_weights.get(handle);
|
WeightRec* wr = (WeightRec*)_weights.get(handle);
|
||||||
|
@ -398,45 +300,14 @@ void Airplane::setWeight(int handle, float mass)
|
||||||
|
|
||||||
void Airplane::setFuelFraction(float frac)
|
void Airplane::setFuelFraction(float frac)
|
||||||
{
|
{
|
||||||
int i;
|
for(int i=0; i<_tanks.size(); i++) {
|
||||||
for(i=0; i<_tanks.size(); i++) {
|
|
||||||
Tank* t = (Tank*)_tanks.get(i);
|
Tank* t = (Tank*)_tanks.get(i);
|
||||||
t->fill = frac * t->cap;
|
t->fill = frac * t->cap;
|
||||||
_model.getBody()->setMass(t->handle, t->cap * frac);
|
_model.getBody()->setMass(t->handle, t->cap * frac);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float Airplane::getDragCoefficient()
|
void Airplane::setupState(const float aoa, const float speed, const float gla, State* s)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
float cosAoA = Math::cos(aoa);
|
float cosAoA = Math::cos(aoa);
|
||||||
float sinAoA = Math::sin(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[3] = 0; s->orient[4] = 1; s->orient[5] = 0;
|
||||||
s->orient[6] = -sinAoA; s->orient[7] = 0; s->orient[8] = cosAoA;
|
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;
|
s->v[0] = speed*Math::cos(gla); s->v[1] = -speed*Math::sin(gla); s->v[2] = 0;
|
||||||
|
|
||||||
int i;
|
for(int i=0; i<3; i++)
|
||||||
for(i=0; i<3; i++)
|
|
||||||
s->pos[i] = s->rot[i] = s->acc[i] = s->racc[i] = 0;
|
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
|
// 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;
|
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)
|
void Airplane::addContactPoint(float* pos)
|
||||||
{
|
{
|
||||||
ContactRec* c = new ContactRec;
|
ContactRec* c = new ContactRec;
|
||||||
c->gear = 0;
|
c->gear = 0;
|
||||||
c->p[0] = pos[0];
|
Math::set3(pos, c->p);
|
||||||
c->p[1] = pos[1];
|
|
||||||
c->p[2] = pos[2];
|
|
||||||
_contacts.add(c);
|
_contacts.add(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Airplane::compileWing(Wing* w)
|
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
|
// Make sure it's initialized. The surfaces will pop out with
|
||||||
// total drag coefficients equal to their areas, which is what we
|
// total drag coefficients equal to their areas, which is what we
|
||||||
// want.
|
// want.
|
||||||
w->compile();
|
w->compile();
|
||||||
|
|
||||||
float wgt = 0;
|
// The tip of the wing is a contact point
|
||||||
int i;
|
float tip[3];
|
||||||
for(i=0; i<w->numSurfaces(); i++) {
|
// need compile() before getTip()!
|
||||||
Surface* s = (Surface*)w->getSurface(i);
|
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();
|
float td = s->getTotalDrag();
|
||||||
s->setTotalDrag(td);
|
int sid = s->getID();
|
||||||
|
|
||||||
_model.addSurface(s);
|
_model.addSurface(s);
|
||||||
|
|
||||||
|
@ -495,8 +386,18 @@ float Airplane::compileWing(Wing* w)
|
||||||
mass = mass * Math::sqrt(mass);
|
mass = mass * Math::sqrt(mass);
|
||||||
float pos[3];
|
float pos[3];
|
||||||
s->getPosition(pos);
|
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;
|
wgt += mass;
|
||||||
|
dragSum += td;
|
||||||
|
}
|
||||||
|
if (_wingsN != 0) {
|
||||||
|
_wingsN->getNode("weight", true)->setFloatValue(wgt);
|
||||||
|
_wingsN->getNode("drag", true)->setFloatValue(dragSum);
|
||||||
}
|
}
|
||||||
return wgt;
|
return wgt;
|
||||||
}
|
}
|
||||||
|
@ -547,7 +448,7 @@ float Airplane::compileFuselage(Fuselage* f)
|
||||||
|
|
||||||
// _Mass_ weighting goes as surface area^(3/2)
|
// _Mass_ weighting goes as surface area^(3/2)
|
||||||
float mass = scale*segWgt * Math::sqrt(scale*segWgt);
|
float mass = scale*segWgt * Math::sqrt(scale*segWgt);
|
||||||
_model.getBody()->addMass(mass, pos);
|
_model.getBody()->addMass(mass, pos, true);
|
||||||
wgt += mass;
|
wgt += mass;
|
||||||
|
|
||||||
// Make a Surface too
|
// Make a Surface too
|
||||||
|
@ -635,6 +536,13 @@ void Airplane::compileGear(GearRec* gr)
|
||||||
_surfs.add(s);
|
_surfs.add(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief add "fake gear" per contact point
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
void Airplane::compileContactPoints()
|
void Airplane::compileContactPoints()
|
||||||
{
|
{
|
||||||
// Figure it will compress by 20cm
|
// Figure it will compress by 20cm
|
||||||
|
@ -648,8 +556,7 @@ void Airplane::compileContactPoints()
|
||||||
float spring = (1/DIST) * 9.8f * 10.0f * mass;
|
float spring = (1/DIST) * 9.8f * 10.0f * mass;
|
||||||
float damp = 2 * Math::sqrt(spring * mass);
|
float damp = 2 * Math::sqrt(spring * mass);
|
||||||
|
|
||||||
int i;
|
for(int i=0; i<_contacts.size(); i++) {
|
||||||
for(i=0; i<_contacts.size(); i++) {
|
|
||||||
ContactRec* c = (ContactRec*)_contacts.get(i);
|
ContactRec* c = (ContactRec*)_contacts.get(i);
|
||||||
|
|
||||||
Gear* g = new Gear();
|
Gear* g = new Gear();
|
||||||
|
@ -674,6 +581,8 @@ void Airplane::compile()
|
||||||
{
|
{
|
||||||
RigidBody* body = _model.getBody();
|
RigidBody* body = _model.getBody();
|
||||||
int firstMass = body->numMasses();
|
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
|
// Generate the point masses for the plane. Just use unitless
|
||||||
// numbers for a first pass, then go back through and rescale to
|
// numbers for a first pass, then go back through and rescale to
|
||||||
|
@ -682,13 +591,21 @@ void Airplane::compile()
|
||||||
|
|
||||||
// The Wing objects
|
// The Wing objects
|
||||||
if (_wing)
|
if (_wing)
|
||||||
|
{
|
||||||
|
if (baseN != 0) _wingsN = baseN->getChild("wing", 0, true);
|
||||||
aeroWgt += compileWing(_wing);
|
aeroWgt += compileWing(_wing);
|
||||||
|
}
|
||||||
if (_tail)
|
if (_tail)
|
||||||
|
{
|
||||||
|
if (baseN != 0) _wingsN = baseN->getChild("tail", 0, true);
|
||||||
aeroWgt += compileWing(_tail);
|
aeroWgt += compileWing(_tail);
|
||||||
|
}
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<_vstabs.size(); i++)
|
for(i=0; i<_vstabs.size(); i++)
|
||||||
|
{
|
||||||
|
if (baseN != 0) _wingsN = baseN->getChild("stab", i, true);
|
||||||
aeroWgt += compileWing((Wing*)_vstabs.get(i));
|
aeroWgt += compileWing((Wing*)_vstabs.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
// The fuselage(s)
|
// The fuselage(s)
|
||||||
for(i=0; i<_fuselages.size(); i++)
|
for(i=0; i<_fuselages.size(); i++)
|
||||||
|
@ -707,7 +624,7 @@ void Airplane::compile()
|
||||||
// Add the thruster masses
|
// Add the thruster masses
|
||||||
for(i=0; i<_thrusters.size(); i++) {
|
for(i=0; i<_thrusters.size(); i++) {
|
||||||
ThrustRec* t = (ThrustRec*)_thrusters.get(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.
|
// Add the tanks, empty for now.
|
||||||
|
@ -733,10 +650,23 @@ void Airplane::compile()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ground effect
|
// Ground effect
|
||||||
|
// If a double tapered wing is modelled with wing and mstab, wing must
|
||||||
|
// be outboard to get correct wingspan.
|
||||||
if(_wing) {
|
if(_wing) {
|
||||||
float gepos[3];
|
float gepos[3];
|
||||||
float gespan = 0;
|
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);
|
_model.setGroundEffect(gepos, gespan, 0.15f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -822,11 +752,11 @@ void Airplane::initEngines()
|
||||||
|
|
||||||
void Airplane::stabilizeThrust()
|
void Airplane::stabilizeThrust()
|
||||||
{
|
{
|
||||||
int i;
|
for(int i=0; i<_thrusters.size(); i++)
|
||||||
for(i=0; i<_thrusters.size(); i++)
|
|
||||||
_model.getThruster(i)->stabilize();
|
_model.getThruster(i)->stabilize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Setup weights for cruise or approach during solve.
|
||||||
void Airplane::setupWeights(bool isApproach)
|
void Airplane::setupWeights(bool isApproach)
|
||||||
{
|
{
|
||||||
int i;
|
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()
|
void Airplane::runCruise()
|
||||||
{
|
{
|
||||||
setupState(_cruiseAoA, _cruiseSpeed,_cruiseGlideAngle, &_cruiseState);
|
setupState(_cruiseAoA, _cruiseSpeed,_cruiseGlideAngle, &_cruiseState);
|
||||||
|
@ -847,13 +789,7 @@ void Airplane::runCruise()
|
||||||
Atmosphere::calcStdDensity(_cruiseP, _cruiseT));
|
Atmosphere::calcStdDensity(_cruiseP, _cruiseT));
|
||||||
|
|
||||||
// The control configuration
|
// The control configuration
|
||||||
_controls.reset();
|
loadCruiseControls();
|
||||||
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
|
|
||||||
|
|
||||||
// The local wind
|
// The local wind
|
||||||
float wind[3];
|
float wind[3];
|
||||||
|
@ -865,7 +801,7 @@ void Airplane::runCruise()
|
||||||
|
|
||||||
// Set up the thruster parameters and iterate until the thrust
|
// Set up the thruster parameters and iterate until the thrust
|
||||||
// stabilizes.
|
// stabilizes.
|
||||||
for(i=0; i<_thrusters.size(); i++) {
|
for(int i=0; i<_thrusters.size(); i++) {
|
||||||
Thruster* t = ((ThrustRec*)_thrusters.get(i))->thruster;
|
Thruster* t = ((ThrustRec*)_thrusters.get(i))->thruster;
|
||||||
t->setWind(wind);
|
t->setWind(wind);
|
||||||
t->setAir(_cruiseP, _cruiseT,
|
t->setAir(_cruiseP, _cruiseT,
|
||||||
|
@ -882,6 +818,18 @@ void Airplane::runCruise()
|
||||||
_model.calcForces(&_cruiseState);
|
_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()
|
void Airplane::runApproach()
|
||||||
{
|
{
|
||||||
setupState(_approachAoA, _approachSpeed,_approachGlideAngle, &_approachState);
|
setupState(_approachAoA, _approachSpeed,_approachGlideAngle, &_approachState);
|
||||||
|
@ -890,13 +838,7 @@ void Airplane::runApproach()
|
||||||
Atmosphere::calcStdDensity(_approachP, _approachT));
|
Atmosphere::calcStdDensity(_approachP, _approachT));
|
||||||
|
|
||||||
// The control configuration
|
// The control configuration
|
||||||
_controls.reset();
|
loadApproachControls();
|
||||||
int i;
|
|
||||||
for(i=0; i<_approachControls.size(); i++) {
|
|
||||||
Control* c = (Control*)_approachControls.get(i);
|
|
||||||
_controls.setInput(c->control, c->val);
|
|
||||||
}
|
|
||||||
_controls.applyControls(1000000);
|
|
||||||
|
|
||||||
// The local wind
|
// The local wind
|
||||||
float wind[3];
|
float wind[3];
|
||||||
|
@ -909,7 +851,7 @@ void Airplane::runApproach()
|
||||||
|
|
||||||
// Run the thrusters until they get to a stable setting. FIXME:
|
// Run the thrusters until they get to a stable setting. FIXME:
|
||||||
// this is lots of wasted work.
|
// 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;
|
Thruster* t = ((ThrustRec*)_thrusters.get(i))->thruster;
|
||||||
t->setWind(wind);
|
t->setWind(wind);
|
||||||
t->setAir(_approachP, _approachT,
|
t->setAir(_approachP, _approachT,
|
||||||
|
@ -926,6 +868,7 @@ void Airplane::runApproach()
|
||||||
_model.calcForces(&_approachState);
|
_model.calcForces(&_approachState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used only in Airplane::solve() and solveHelicopter(), not at runtime
|
||||||
void Airplane::applyDragFactor(float factor)
|
void Airplane::applyDragFactor(float factor)
|
||||||
{
|
{
|
||||||
float applied = Math::pow(factor, SOLVE_TWEAK);
|
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)
|
void Airplane::applyLiftRatio(float factor)
|
||||||
{
|
{
|
||||||
float applied = Math::pow(factor, SOLVE_TWEAK);
|
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)
|
/// Helper for solve()
|
||||||
{
|
|
||||||
if(val < min) return min;
|
|
||||||
if(val > max) return max;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
float Airplane::normFactor(float f)
|
float Airplane::normFactor(float f)
|
||||||
{
|
{
|
||||||
if(f < 0) f = -f;
|
if(f < 0) f = -f;
|
||||||
|
@ -1102,8 +1040,8 @@ void Airplane::solve()
|
||||||
_cruiseAoA += SOLVE_TWEAK*aoaDelta;
|
_cruiseAoA += SOLVE_TWEAK*aoaDelta;
|
||||||
_tailIncidence += SOLVE_TWEAK*tailDelta;
|
_tailIncidence += SOLVE_TWEAK*tailDelta;
|
||||||
|
|
||||||
_cruiseAoA = clamp(_cruiseAoA, -0.175f, 0.175f);
|
_cruiseAoA = Math::clamp(_cruiseAoA, -0.175f, 0.175f);
|
||||||
_tailIncidence = clamp(_tailIncidence, -0.175f, 0.175f);
|
_tailIncidence = Math::clamp(_tailIncidence, -0.175f, 0.175f);
|
||||||
|
|
||||||
if(abs(xforce/_cruiseWeight) < STHRESH*0.0001 &&
|
if(abs(xforce/_cruiseWeight) < STHRESH*0.0001 &&
|
||||||
abs(alift/_approachWeight) < STHRESH*0.0001 &&
|
abs(alift/_approachWeight) < STHRESH*0.0001 &&
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "Rotor.hpp"
|
#include "Rotor.hpp"
|
||||||
#include "Vector.hpp"
|
#include "Vector.hpp"
|
||||||
#include "Version.hpp"
|
#include "Version.hpp"
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
|
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
|
||||||
|
@ -16,7 +17,9 @@ class Launchbar;
|
||||||
class Thruster;
|
class Thruster;
|
||||||
class Hitch;
|
class Hitch;
|
||||||
|
|
||||||
|
/// The Airplane class ties together the different components
|
||||||
class Airplane : public Version {
|
class Airplane : public Version {
|
||||||
|
SGPropertyNode_ptr _wingsN;
|
||||||
public:
|
public:
|
||||||
Airplane();
|
Airplane();
|
||||||
~Airplane();
|
~Airplane();
|
||||||
|
@ -24,30 +27,30 @@ public:
|
||||||
void iterate(float dt);
|
void iterate(float dt);
|
||||||
void calcFuelWeights();
|
void calcFuelWeights();
|
||||||
|
|
||||||
ControlMap* getControlMap();
|
ControlMap* getControlMap() { return &_controls; }
|
||||||
Model* getModel();
|
Model* getModel() { return &_model; }
|
||||||
|
|
||||||
void setPilotPos(float* pos);
|
void setPilotPos(float* pos) { Math::set3(pos, _pilotPos); }
|
||||||
void getPilotPos(float* out);
|
void getPilotPos(float* out) { Math::set3(_pilotPos, out); }
|
||||||
|
|
||||||
void getPilotAccel(float* out);
|
void getPilotAccel(float* out);
|
||||||
|
|
||||||
void setWeight(float weight);
|
void setEmptyWeight(float weight) { _emptyWeight = weight; }
|
||||||
|
|
||||||
void setWing(Wing* wing);
|
void setWing(Wing* wing) { _wing = wing; }
|
||||||
void setTail(Wing* tail);
|
void setTail(Wing* tail) { _tail = tail; }
|
||||||
void addVStab(Wing* vstab);
|
void addVStab(Wing* vstab) { _vstabs.add(vstab); }
|
||||||
|
|
||||||
void addFuselage(float* front, float* back, float width,
|
void addFuselage(float* front, float* back, float width,
|
||||||
float taper=1, float mid=0.5,
|
float taper=1, float mid=0.5,
|
||||||
float cx=1, float cy=1, float cz=1, float idrag=1);
|
float cx=1, float cy=1, float cz=1, float idrag=1);
|
||||||
int addTank(float* pos, float cap, float fuelDensity);
|
int addTank(float* pos, float cap, float fuelDensity);
|
||||||
void addGear(Gear* g);
|
void addGear(Gear* g);
|
||||||
void addHook(Hook* h);
|
void addHook(Hook* h) { _model.addHook(h); }
|
||||||
void addLaunchbar(Launchbar* l);
|
void addLaunchbar(Launchbar* l) { _model.addLaunchbar(l); }
|
||||||
void addThruster(Thruster* t, float mass, float* cg);
|
void addThruster(Thruster* t, float mass, float* cg);
|
||||||
void addBallast(float* pos, float mass);
|
void addBallast(float* pos, float mass);
|
||||||
void addHitch(Hitch* h);
|
void addHitch(Hitch* h) { _model.addHitch(h); }
|
||||||
|
|
||||||
int addWeight(float* pos, float size);
|
int addWeight(float* pos, float size);
|
||||||
void setWeight(int handle, float mass);
|
void setWeight(int handle, float mass);
|
||||||
|
@ -61,39 +64,47 @@ public:
|
||||||
|
|
||||||
void addSolutionWeight(bool approach, int idx, float wgt);
|
void addSolutionWeight(bool approach, int idx, float wgt);
|
||||||
|
|
||||||
int numGear();
|
int numGear() { return _gears.size(); }
|
||||||
Gear* getGear(int g);
|
Gear* getGear(int g) { return ((GearRec*)_gears.get(g))->gear; }
|
||||||
Hook* getHook();
|
Hook* getHook() { return _model.getHook(); }
|
||||||
int numHitches() { return _hitches.size(); }
|
int numHitches() { return _hitches.size(); }
|
||||||
Hitch* getHitch(int h);
|
Hitch* getHitch(int h);
|
||||||
Rotorgear* getRotorgear();
|
Rotorgear* getRotorgear() { return _model.getRotorgear(); }
|
||||||
Launchbar* getLaunchbar();
|
Launchbar* getLaunchbar() { return _model.getLaunchbar(); }
|
||||||
|
|
||||||
int numThrusters() { return _thrusters.size(); }
|
int numThrusters() { return _thrusters.size(); }
|
||||||
Thruster* getThruster(int n) {
|
Thruster* getThruster(int n) {
|
||||||
return ((ThrustRec*)_thrusters.get(n))->thruster; }
|
return ((ThrustRec*)_thrusters.get(n))->thruster; }
|
||||||
|
|
||||||
int numTanks();
|
int numTanks() { return _tanks.size(); }
|
||||||
void setFuelFraction(float frac); // 0-1, total amount of fuel
|
void setFuelFraction(float frac); // 0-1, total amount of fuel
|
||||||
float getFuel(int tank); // in kg!
|
// get fuel in kg
|
||||||
float setFuel(int tank, float fuel); // in kg!
|
float getFuel(int tank) { return ((Tank*)_tanks.get(tank))->fill; }
|
||||||
float getFuelDensity(int tank); // kg/m^3
|
// set fuel in kg
|
||||||
float getTankCapacity(int tank);
|
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 compile(); // generate point masses & such, then solve
|
||||||
void initEngines();
|
void initEngines();
|
||||||
void stabilizeThrust();
|
void stabilizeThrust();
|
||||||
|
|
||||||
// Solution output values
|
// Solution output values
|
||||||
int getSolutionIterations();
|
int getSolutionIterations() { return _solutionIterations; }
|
||||||
float getDragCoefficient();
|
float getDragCoefficient() { return _dragFactor; }
|
||||||
float getLiftRatio();
|
float getLiftRatio() { return _liftRatio; }
|
||||||
float getCruiseAoA();
|
float getCruiseAoA() { return _cruiseAoA; }
|
||||||
float getTailIncidence();
|
float getTailIncidence() { return _tailIncidence; }
|
||||||
float getApproachElevator() { return _approachElevator.val; }
|
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:
|
private:
|
||||||
struct Tank { float pos[3]; float cap; float fill;
|
struct Tank { float pos[3]; float cap; float fill;
|
||||||
|
@ -119,7 +130,6 @@ private:
|
||||||
void compileGear(GearRec* gr);
|
void compileGear(GearRec* gr);
|
||||||
void applyDragFactor(float factor);
|
void applyDragFactor(float factor);
|
||||||
void applyLiftRatio(float factor);
|
void applyLiftRatio(float factor);
|
||||||
float clamp(float val, float min, float max);
|
|
||||||
void addContactPoint(float* pos);
|
void addContactPoint(float* pos);
|
||||||
void compileContactPoints();
|
void compileContactPoints();
|
||||||
float normFactor(float f);
|
float normFactor(float f);
|
||||||
|
@ -175,6 +185,10 @@ private:
|
||||||
float _tailIncidence;
|
float _tailIncidence;
|
||||||
Control _approachElevator;
|
Control _approachElevator;
|
||||||
const char* _failureMsg;
|
const char* _failureMsg;
|
||||||
|
|
||||||
|
// hard limits for cg from gear positions
|
||||||
|
float _cgMaxX;
|
||||||
|
float _cgMinX;
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace yasim
|
}; // namespace yasim
|
||||||
|
|
|
@ -32,14 +32,18 @@ ControlMap::~ControlMap()
|
||||||
|
|
||||||
for(i=0; i<_outputs.size(); i++)
|
for(i=0; i<_outputs.size(); i++)
|
||||||
delete (OutRec*)_outputs.get(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()
|
/**
|
||||||
{
|
input : index to _inputs
|
||||||
Vector* v = new Vector();
|
type: identifier (see enum OutputType)
|
||||||
return _inputs.add(v);
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
void ControlMap::addMapping(int input, int type, void* object, int options,
|
void ControlMap::addMapping(int input, int type, void* object, int options,
|
||||||
float src0, float src1, float dst0, float dst1)
|
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;
|
m->dst1 = dst1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
input : index to _inputs
|
||||||
|
type: identifier (see enum OutputType)
|
||||||
|
*/
|
||||||
void ControlMap::addMapping(int input, int type, void* object, int options)
|
void ControlMap::addMapping(int input, int type, void* object, int options)
|
||||||
{
|
{
|
||||||
// See if the output object already exists
|
// See if the output object already exists
|
||||||
|
@ -210,12 +218,12 @@ void ControlMap::applyControls(float dt)
|
||||||
case LEXTEND: ((Launchbar*)obj)->setExtension(lval); break;
|
case LEXTEND: ((Launchbar*)obj)->setExtension(lval); break;
|
||||||
case LACCEL: ((Launchbar*)obj)->setAcceleration(lval); break;
|
case LACCEL: ((Launchbar*)obj)->setAcceleration(lval); break;
|
||||||
case CASTERING:((Gear*)obj)->setCastering(lval != 0); break;
|
case CASTERING:((Gear*)obj)->setCastering(lval != 0); break;
|
||||||
case SLAT: ((Wing*)obj)->setSlat(lval); break;
|
case SLAT: ((Wing*)obj)->setSlatPos(lval); break;
|
||||||
case FLAP0: ((Wing*)obj)->setFlap0(lval, rval); break;
|
case FLAP0: ((Wing*)obj)->setFlap0Pos(lval, rval); break;
|
||||||
case FLAP0EFFECTIVENESS: ((Wing*)obj)->setFlap0Effectiveness(lval); 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 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 COLLECTIVE: ((Rotor*)obj)->setCollective(lval); break;
|
||||||
case CYCLICAIL: ((Rotor*)obj)->setCyclicail(lval,rval); break;
|
case CYCLICAIL: ((Rotor*)obj)->setCyclicail(lval,rval); break;
|
||||||
case CYCLICELE: ((Rotor*)obj)->setCyclicele(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
|
} // namespace yasim
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef _CONTROL_MAP_HPP
|
#ifndef _CONTROL_MAP_HPP
|
||||||
#define _CONTROL_MAP_HPP
|
#define _CONTROL_MAP_HPP
|
||||||
|
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
#include "Vector.hpp"
|
#include "Vector.hpp"
|
||||||
|
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
@ -26,9 +27,7 @@ public:
|
||||||
OPT_INVERT = 0x02,
|
OPT_INVERT = 0x02,
|
||||||
OPT_SQUARE = 0x04 };
|
OPT_SQUARE = 0x04 };
|
||||||
|
|
||||||
// Returns a new, not-yet-used "input handle" for addMapping and
|
struct PropHandle { char* name; int handle; };
|
||||||
// setInput. This typically corresponds to one user axis.
|
|
||||||
int newInput();
|
|
||||||
|
|
||||||
// Adds a mapping to between input handle and a particular setting
|
// Adds a mapping to between input handle and a particular setting
|
||||||
// on an output object. The value of output MUST match the type
|
// on an output object. The value of output MUST match the type
|
||||||
|
@ -45,12 +44,13 @@ public:
|
||||||
// setInput() invokations.
|
// setInput() invokations.
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
// Sets the specified input (as returned by newInput) to the
|
// Sets the specified input (as returned by propertyHandle) to the
|
||||||
// specified value.
|
// specified value.
|
||||||
void setInput(int input, float value);
|
void setInput(int propHandle, float value);
|
||||||
|
|
||||||
// Calculates and applies the settings received since the last reset().
|
/// Calculates and applies the settings received since the last reset().
|
||||||
void applyControls(float dt);
|
/// dt defaults to a large value used at solve time.
|
||||||
|
void applyControls(float dt=1e6);
|
||||||
|
|
||||||
// Returns the input/output range appropriate for the given
|
// Returns the input/output range appropriate for the given
|
||||||
// control. Ailerons go from -1 to 1, while throttles are never
|
// control. Ailerons go from -1 to 1, while throttles are never
|
||||||
|
@ -72,6 +72,15 @@ public:
|
||||||
float getOutput(int handle);
|
float getOutput(int handle);
|
||||||
float getOutputR(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:
|
private:
|
||||||
struct OutRec { int type; void* object; Vector maps;
|
struct OutRec { int type; void* object; Vector maps;
|
||||||
float oldL, oldR, time; };
|
float oldL, oldR, time; };
|
||||||
|
@ -84,6 +93,8 @@ private:
|
||||||
|
|
||||||
// An unordered list of output settings.
|
// An unordered list of output settings.
|
||||||
Vector _outputs;
|
Vector _outputs;
|
||||||
|
// control properties
|
||||||
|
Vector _properties;
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace yasim
|
}; // namespace yasim
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "Rotor.hpp"
|
#include "Rotor.hpp"
|
||||||
#include "Rotorpart.hpp"
|
#include "Rotorpart.hpp"
|
||||||
#include "Hitch.hpp"
|
#include "Hitch.hpp"
|
||||||
|
#include "Surface.hpp"
|
||||||
|
|
||||||
#include "FGFDM.hpp"
|
#include "FGFDM.hpp"
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ namespace yasim {
|
||||||
|
|
||||||
// Some conversion factors
|
// Some conversion factors
|
||||||
static const float KTS2MPS = 0.514444444444;
|
static const float KTS2MPS = 0.514444444444;
|
||||||
|
static const float KMH2MPS = 1/3.6;
|
||||||
static const float FT2M = 0.3048;
|
static const float FT2M = 0.3048;
|
||||||
static const float DEG2RAD = 0.0174532925199;
|
static const float DEG2RAD = 0.0174532925199;
|
||||||
static const float RPM2RAD = 0.10471975512;
|
static const float RPM2RAD = 0.10471975512;
|
||||||
|
@ -59,7 +61,7 @@ FGFDM::FGFDM()
|
||||||
// Map /controls/flight/elevator to the approach elevator control. This
|
// Map /controls/flight/elevator to the approach elevator control. This
|
||||||
// should probably be settable, but there are very few aircraft
|
// should probably be settable, but there are very few aircraft
|
||||||
// who trim their approaches using things other than elevator.
|
// 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?
|
// FIXME: read seed from somewhere?
|
||||||
int seed = 0;
|
int seed = 0;
|
||||||
|
@ -68,12 +70,6 @@ FGFDM::FGFDM()
|
||||||
|
|
||||||
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++) {
|
for(int i=0; i<_thrusters.size(); i++) {
|
||||||
EngRec* er = (EngRec*)_thrusters.get(i);
|
EngRec* er = (EngRec*)_thrusters.get(i);
|
||||||
delete[] er->prefix;
|
delete[] er->prefix;
|
||||||
|
@ -124,18 +120,38 @@ Airplane* FGFDM::getAirplane()
|
||||||
|
|
||||||
void FGFDM::init()
|
void FGFDM::init()
|
||||||
{
|
{
|
||||||
|
//reset id generator, needed on simulator reset/re-init
|
||||||
|
Surface::resetIDgen();
|
||||||
_turb_magnitude_norm = fgGetNode("/environment/turbulence/magnitude-norm", true);
|
_turb_magnitude_norm = fgGetNode("/environment/turbulence/magnitude-norm", true);
|
||||||
_turb_rate_hz = fgGetNode("/environment/turbulence/rate-hz", true);
|
_turb_rate_hz = fgGetNode("/environment/turbulence/rate-hz", true);
|
||||||
|
|
||||||
SGPropertyNode_ptr yasimNode = fgGetNode("/fdm/yasim", true);
|
_yasimN = fgGetNode("/fdm/yasim", true);
|
||||||
_gross_weight_lbs = yasimNode->getNode("gross-weight-lbs", true);
|
_gross_weight_lbs = _yasimN->getNode("gross-weight-lbs", true);
|
||||||
|
|
||||||
// alias to older name
|
// alias to older name
|
||||||
fgGetNode("/yasim/gross-weight-lbs", true)->alias(_gross_weight_lbs);
|
fgGetNode("/yasim/gross-weight-lbs", true)->alias(_gross_weight_lbs);
|
||||||
|
|
||||||
_cg_x = yasimNode->getNode("cg-x-m", true);
|
// write some compile time information to property tree
|
||||||
_cg_y = yasimNode->getNode("cg-y-m", true);
|
_yasimN->getNode("config-version",true)->setIntValue(_airplane.getVersion());
|
||||||
_cg_z = yasimNode->getNode("cg-z-m", true);
|
_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
|
// Allows the user to start with something other than full fuel
|
||||||
_airplane.setFuelFraction(fgGetFloat("/sim/fuel-fraction", 1));
|
_airplane.setFuelFraction(fgGetFloat("/sim/fuel-fraction", 1));
|
||||||
|
@ -225,34 +241,64 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
|
||||||
XMLAttributes* a = (XMLAttributes*)&atts;
|
XMLAttributes* a = (XMLAttributes*)&atts;
|
||||||
float v[3];
|
float v[3];
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
float f = 0;
|
||||||
|
|
||||||
if(eq(name, "airplane")) {
|
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")) {
|
if(a->hasAttribute("version")) {
|
||||||
_airplane.setVersion( a->getValue("version") );
|
_airplane.setVersion( a->getValue("version") );
|
||||||
}
|
}
|
||||||
#if defined(ENABLE_DEV_WARNINGS)
|
|
||||||
if( !_airplane.isVersionOrNewer( Version::YASIM_VERSION_CURRENT ) ) {
|
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")) {
|
} else if(eq(name, "approach")) {
|
||||||
float spd = attrf(a, "speed") * KTS2MPS;
|
float spd, alt = 0;
|
||||||
float alt = attrf(a, "alt", 0) * FT2M;
|
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 aoa = attrf(a, "aoa", 0) * DEG2RAD;
|
||||||
float gla = attrf(a, "glide-angle", 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;
|
_cruiseCurr = false;
|
||||||
} else if(eq(name, "cruise")) {
|
} else if(eq(name, "cruise")) {
|
||||||
float spd = attrf(a, "speed") * KTS2MPS;
|
float spd, alt = 0;
|
||||||
float alt = attrf(a, "alt") * FT2M;
|
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;
|
float gla = attrf(a, "glide-angle", 0) * DEG2RAD;
|
||||||
_airplane.setCruise(spd, alt, attrf(a, "fuel", 0.5),gla);
|
_airplane.setCruise(spd, alt, attrf(a, "fuel", 0.5),gla);
|
||||||
_cruiseCurr = true;
|
_cruiseCurr = true;
|
||||||
} else if(eq(name, "solve-weight")) {
|
} else if(eq(name, "solve-weight")) {
|
||||||
int idx = attri(a, "idx");
|
int idx = attri(a, "idx");
|
||||||
float wgt = attrf(a, "weight") * LBS2KG;
|
if(a->hasAttribute("weight")) { f = attrf(a, "weight") * LBS2KG; }
|
||||||
_airplane.addSolutionWeight(!_cruiseCurr, idx, wgt);
|
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")) {
|
} else if(eq(name, "cockpit")) {
|
||||||
v[0] = attrf(a, "x");
|
v[0] = attrf(a, "x");
|
||||||
v[1] = attrf(a, "y");
|
v[1] = attrf(a, "y");
|
||||||
|
@ -302,7 +348,14 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
|
||||||
v[0] = attrf(a, "x");
|
v[0] = attrf(a, "x");
|
||||||
v[1] = attrf(a, "y");
|
v[1] = attrf(a, "y");
|
||||||
v[2] = attrf(a, "z");
|
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,
|
j->setMaxThrust(attrf(a, "thrust") * LBS2N,
|
||||||
attrf(a, "afterburner", 0) * LBS2N);
|
attrf(a, "afterburner", 0) * LBS2N);
|
||||||
j->setVectorAngle(attrf(a, "rotate", 0) * DEG2RAD);
|
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
|
float density = 6.0; // gasoline, in lbs/gal
|
||||||
if(a->hasAttribute("jet")) density = 6.72;
|
if(a->hasAttribute("jet")) density = 6.72;
|
||||||
density *= LBS2KG*CM2GALS;
|
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")) {
|
} else if(eq(name, "ballast")) {
|
||||||
v[0] = attrf(a, "x");
|
v[0] = attrf(a, "x");
|
||||||
v[1] = attrf(a, "y");
|
v[1] = attrf(a, "y");
|
||||||
v[2] = attrf(a, "z");
|
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")) {
|
} else if(eq(name, "weight")) {
|
||||||
parseWeight(a);
|
parseWeight(a);
|
||||||
} else if(eq(name, "stall")) {
|
} 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->setStallWidth(attrf(a, "width", 2) * DEG2RAD);
|
||||||
w->setStallPeak(attrf(a, "peak", 1.5));
|
w->setStallPeak(attrf(a, "peak", 1.5));
|
||||||
} else if(eq(name, "flap0")) {
|
} 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"));
|
attrf(a, "lift"), attrf(a, "drag"));
|
||||||
} else if(eq(name, "flap1")) {
|
} 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"));
|
attrf(a, "lift"), attrf(a, "drag"));
|
||||||
} else if(eq(name, "slat")) {
|
} 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"));
|
attrf(a, "aoa"), attrf(a, "drag"));
|
||||||
} else if(eq(name, "spoiler")) {
|
} 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"));
|
attrf(a, "lift"), attrf(a, "drag"));
|
||||||
/* } else if(eq(name, "collective")) {
|
/* } else if(eq(name, "collective")) {
|
||||||
((Rotor*)_currObj)->setcollective(attrf(a, "min"), attrf(a, "max"));
|
((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
|
// A cruise or approach control setting
|
||||||
const char* axis = a->getValue("axis");
|
const char* axis = a->getValue("axis");
|
||||||
float value = attrf(a, "value", 0);
|
float value = attrf(a, "value", 0);
|
||||||
|
ControlMap* cm = _airplane.getControlMap();
|
||||||
if(_cruiseCurr)
|
if(_cruiseCurr)
|
||||||
_airplane.addCruiseControl(parseAxis(axis), value);
|
_airplane.addCruiseControl(cm->propertyHandle(axis), value);
|
||||||
else
|
else
|
||||||
_airplane.addApproachControl(parseAxis(axis), value);
|
_airplane.addApproachControl(cm->propertyHandle(axis), value);
|
||||||
} else if(eq(name, "control-input")) {
|
} else if(eq(name, "control-input")) {
|
||||||
|
ControlMap* cm = _airplane.getControlMap();
|
||||||
// A mapping of input property to a control
|
// 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 control = parseOutput(a->getValue("control"));
|
||||||
int opt = 0;
|
int opt = 0;
|
||||||
opt |= a->hasAttribute("split") ? ControlMap::OPT_SPLIT : 0;
|
opt |= a->hasAttribute("split") ? ControlMap::OPT_SPLIT : 0;
|
||||||
opt |= a->hasAttribute("invert") ? ControlMap::OPT_INVERT : 0;
|
opt |= a->hasAttribute("invert") ? ControlMap::OPT_INVERT : 0;
|
||||||
opt |= a->hasAttribute("square") ? ControlMap::OPT_SQUARE : 0;
|
opt |= a->hasAttribute("square") ? ControlMap::OPT_SQUARE : 0;
|
||||||
|
|
||||||
ControlMap* cm = _airplane.getControlMap();
|
|
||||||
if(a->hasAttribute("src0")) {
|
if(a->hasAttribute("src0")) {
|
||||||
cm->addMapping(axis, control, _currObj, opt,
|
cm->addMapping(axis, control, _currObj, opt,
|
||||||
attrf(a, "src0"), attrf(a, "src1"),
|
attrf(a, "src0"), attrf(a, "src1"),
|
||||||
|
@ -577,10 +644,10 @@ void FGFDM::getExternalInput(float dt)
|
||||||
ControlMap* cm = _airplane.getControlMap();
|
ControlMap* cm = _airplane.getControlMap();
|
||||||
cm->reset();
|
cm->reset();
|
||||||
|
|
||||||
for(int i=0; i<_axes.size(); i++) {
|
for(int i=0; i < cm->numProperties(); i++) {
|
||||||
AxisRec* a = (AxisRec*)_axes.get(i);
|
ControlMap::PropHandle *p = cm->getProperty(i);
|
||||||
float val = fgGetFloat(a->name, 0);
|
float val = fgGetFloat(p->name, 0);
|
||||||
cm->setInput(a->handle, val);
|
cm->setInput(p->handle, val);
|
||||||
}
|
}
|
||||||
cm->applyControls(dt);
|
cm->applyControls(dt);
|
||||||
|
|
||||||
|
@ -625,6 +692,26 @@ void FGFDM::setOutputProperties(float dt)
|
||||||
_cg_y->setFloatValue(cg[1]);
|
_cg_y->setFloatValue(cg[1]);
|
||||||
_cg_z->setFloatValue(cg[2]);
|
_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();
|
ControlMap* cm = _airplane.getControlMap();
|
||||||
for(int i=0; i<_controlProps.size(); i++) {
|
for(int i=0; i<_controlProps.size(); i++) {
|
||||||
PropOut* p = (PropOut*)_controlProps.get(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->setSweep(attrf(a, "sweep", 0) * DEG2RAD);
|
||||||
w->setTaper(attrf(a, "taper", 1));
|
w->setTaper(attrf(a, "taper", 1));
|
||||||
w->setDihedral(attrf(a, "dihedral", defDihed) * DEG2RAD);
|
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
|
// These come in with positive indicating positive AoA, but the
|
||||||
// internals expect a rotation about the left-pointing Y axis, so
|
// internals expect a rotation about the left-pointing Y axis, so
|
||||||
|
@ -1007,26 +1099,7 @@ void FGFDM::parsePropeller(XMLAttributes* a)
|
||||||
_currObj = thruster;
|
_currObj = thruster;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turns a string axis name into an integer for use by the
|
/// map identifier (string) to int (enum in ControlMap)
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FGFDM::parseOutput(const char* name)
|
int FGFDM::parseOutput(const char* name)
|
||||||
{
|
{
|
||||||
if(eq(name, "THROTTLE")) return ControlMap::THROTTLE;
|
if(eq(name, "THROTTLE")) return ControlMap::THROTTLE;
|
||||||
|
|
|
@ -31,7 +31,6 @@ public:
|
||||||
float getVehicleRadius(void) const { return _vehicle_radius; }
|
float getVehicleRadius(void) const { return _vehicle_radius; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct AxisRec { char* name; int handle; };
|
|
||||||
struct EngRec { char* prefix; Thruster* eng; };
|
struct EngRec { char* prefix; Thruster* eng; };
|
||||||
struct WeightRec { char* prop; float size; int handle; };
|
struct WeightRec { char* prop; float size; int handle; };
|
||||||
struct PropOut { SGPropertyNode* prop; int handle, type; bool left;
|
struct PropOut { SGPropertyNode* prop; int handle, type; bool left;
|
||||||
|
@ -41,7 +40,6 @@ private:
|
||||||
|
|
||||||
Rotor* parseRotor(XMLAttributes* a, const char* name);
|
Rotor* parseRotor(XMLAttributes* a, const char* name);
|
||||||
Wing* parseWing(XMLAttributes* a, const char* name, Version * version);
|
Wing* parseWing(XMLAttributes* a, const char* name, Version * version);
|
||||||
int parseAxis(const char* name);
|
|
||||||
int parseOutput(const char* name);
|
int parseOutput(const char* name);
|
||||||
void parseWeight(XMLAttributes* a);
|
void parseWeight(XMLAttributes* a);
|
||||||
void parseTurbineEngine(XMLAttributes* a);
|
void parseTurbineEngine(XMLAttributes* a);
|
||||||
|
@ -64,10 +62,6 @@ private:
|
||||||
// Aerodynamic turbulence model
|
// Aerodynamic turbulence model
|
||||||
Turbulence* _turb;
|
Turbulence* _turb;
|
||||||
|
|
||||||
// The list of "axes" that we expect to find as input. These are
|
|
||||||
// typically property names.
|
|
||||||
Vector _axes;
|
|
||||||
|
|
||||||
// Settable weights
|
// Settable weights
|
||||||
Vector _weights;
|
Vector _weights;
|
||||||
|
|
||||||
|
@ -107,9 +101,23 @@ private:
|
||||||
SGPropertyNode_ptr _cg_x;
|
SGPropertyNode_ptr _cg_x;
|
||||||
SGPropertyNode_ptr _cg_y;
|
SGPropertyNode_ptr _cg_y;
|
||||||
SGPropertyNode_ptr _cg_z;
|
SGPropertyNode_ptr _cg_z;
|
||||||
|
SGPropertyNode_ptr _yasimN;
|
||||||
|
|
||||||
std::vector<SGPropertyNode_ptr> _tank_level_lbs;
|
std::vector<SGPropertyNode_ptr> _tank_level_lbs;
|
||||||
std::vector<ThrusterProps> _thrust_props;
|
std::vector<ThrusterProps> _thrust_props;
|
||||||
std::vector<FuelProps> _fuel_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
|
}; // namespace yasim
|
||||||
|
|
|
@ -53,98 +53,6 @@ Gear::Gear()
|
||||||
_global_ground[3] = -1e3;
|
_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,
|
void Gear::setGlobalGround(double *global_ground, float* global_vel,
|
||||||
double globalX, double globalY,
|
double globalX, double globalY,
|
||||||
const simgear::BVHMaterial *material)
|
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)
|
void Gear::getGlobalGround(double* global_ground)
|
||||||
{
|
{
|
||||||
int i;
|
for(int i=0; i<4; i++) global_ground[i] = _global_ground[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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gear::getForce(float* force, float* contact)
|
void Gear::getForce(float* force, float* contact)
|
||||||
|
@ -242,25 +102,6 @@ void Gear::getForce(float* force, float* contact)
|
||||||
Math::set3(_contact, 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()
|
float Gear::getBumpAltitude()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#ifndef _GEAR_HPP
|
#ifndef _GEAR_HPP
|
||||||
#define _GEAR_HPP
|
#define _GEAR_HPP
|
||||||
|
#include "Math.hpp"
|
||||||
|
|
||||||
namespace simgear {
|
namespace simgear {
|
||||||
class BVHMaterial;
|
class BVHMaterial;
|
||||||
|
@ -33,42 +34,43 @@ public:
|
||||||
Gear();
|
Gear();
|
||||||
|
|
||||||
// Externally set values
|
// Externally set values
|
||||||
void setPosition(float* position);
|
void setPosition(float* position) { Math::set3(position, _pos); }
|
||||||
void setCompression(float* compression);
|
void getPosition(float* out) { Math::set3(_pos, out); }
|
||||||
void setSpring(float spring);
|
void setCompression(float* compression) { Math::set3(compression, _cmpr); }
|
||||||
void setDamping(float damping);
|
void getCompression(float* out) { Math::set3(_cmpr, out); }
|
||||||
void setStaticFriction(float sfric);
|
void setSpring(float spring) { _spring = spring; }
|
||||||
void setDynamicFriction(float dfric);
|
float getSpring() { return _spring; }
|
||||||
void setBrake(float brake);
|
void setDamping(float damping) { _damp = damping; }
|
||||||
void setRotation(float rotation);
|
float getDamping() {return _damp; }
|
||||||
void setExtension(float extension);
|
void setStaticFriction(float sfric) { _sfric = sfric; }
|
||||||
void setCastering(bool castering);
|
float getStaticFriction() { return _sfric; }
|
||||||
void setOnWater(bool c);
|
void setDynamicFriction(float dfric) { _dfric = dfric; }
|
||||||
void setOnSolid(bool c);
|
float getDynamicFriction() { return _dfric; }
|
||||||
void setSpringFactorNotPlaning(float f);
|
void setBrake(float brake) { _brake = Math::clamp(brake, 0, 1); }
|
||||||
void setSpeedPlaning(float s);
|
float getBrake() { return _brake; }
|
||||||
void setReduceFrictionByExtension(float s);
|
void setRotation(float rotation) { _rot = rotation; }
|
||||||
void setInitialLoad(float l);
|
float getRotation() { return _rot; }
|
||||||
void setIgnoreWhileSolving(bool c);
|
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,
|
void setGlobalGround(double* global_ground, float* global_vel,
|
||||||
double globalX, double globalY,
|
double globalX, double globalY,
|
||||||
const simgear::BVHMaterial *material);
|
const simgear::BVHMaterial *material);
|
||||||
void getPosition(float* out);
|
|
||||||
void getCompression(float* out);
|
|
||||||
void getGlobalGround(double* global_ground);
|
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 getCasterAngle() { return _casterAngle; }
|
||||||
float getRollSpeed() { return _rollSpeed; }
|
float getRollSpeed() { return _rollSpeed; }
|
||||||
float getBumpAltitude();
|
float getBumpAltitude();
|
||||||
bool getGroundIsSolid();
|
bool getGroundIsSolid() { return _ground_isSolid; }
|
||||||
float getGroundFrictionFactor() { return (float)_ground_frictionFactor; }
|
float getGroundFrictionFactor() { return (float)_ground_frictionFactor; }
|
||||||
void integrate(float dt);
|
void integrate(float dt);
|
||||||
|
|
||||||
|
@ -81,12 +83,12 @@ public:
|
||||||
// Computed values: total force, weight-on-wheels (force normal to
|
// Computed values: total force, weight-on-wheels (force normal to
|
||||||
// ground) and compression fraction.
|
// ground) and compression fraction.
|
||||||
void getForce(float* force, float* contact);
|
void getForce(float* force, float* contact);
|
||||||
float getWoW();
|
float getWoW() { return _wow; }
|
||||||
float getCompressFraction();
|
float getCompressFraction() { return _frac; }
|
||||||
float getCompressDist() { return _compressDist; }
|
float getCompressDist() { return _compressDist; }
|
||||||
bool getSubmergable() {return (!_ground_isSolid)&&(!_isContactPoint); }
|
bool getSubmergable() {return (!_ground_isSolid)&&(!_isContactPoint); }
|
||||||
bool getIgnoreWhileSolving() {return _ignoreWhileSolving; }
|
bool getIgnoreWhileSolving() {return _ignoreWhileSolving; }
|
||||||
void setContactPoint(bool c);
|
void setContactPoint(bool c) { _isContactPoint=c; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float calcFriction(float wgt, float v);
|
float calcFriction(float wgt, float v);
|
||||||
|
|
|
@ -44,17 +44,17 @@ public:
|
||||||
|
|
||||||
// Some 3D vector stuff. In all cases, it is permissible for the
|
// Some 3D vector stuff. In all cases, it is permissible for the
|
||||||
// "out" vector to be the same as one of the inputs.
|
// "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[0] = v[0];
|
||||||
out[1] = v[1];
|
out[1] = v[1];
|
||||||
out[2] = v[2];
|
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];
|
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 ax=a[0], ay=a[1], az=a[2];
|
||||||
float bx=b[0], by=b[1], bz=b[2];
|
float bx=b[0], by=b[1], bz=b[2];
|
||||||
out[0] = ay*bz - by*az;
|
out[0] = ay*bz - by*az;
|
||||||
|
@ -62,30 +62,30 @@ public:
|
||||||
out[2] = ax*by - bx*ay;
|
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[0] = scalar * v[0];
|
||||||
out[1] = scalar * v[1];
|
out[1] = scalar * v[1];
|
||||||
out[2] = scalar * v[2];
|
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[0] = a[0] + b[0];
|
||||||
out[1] = a[1] + b[1];
|
out[1] = a[1] + b[1];
|
||||||
out[2] = a[2] + b[2];
|
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[0] = a[0] - b[0];
|
||||||
out[1] = a[1] - b[1];
|
out[1] = a[1] - b[1];
|
||||||
out[2] = a[2] - b[2];
|
out[2] = a[2] - b[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline float mag3(float* v) {
|
static inline float mag3(const float* v) {
|
||||||
return sqrt(dot3(v, 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);
|
float imag = 1/mag3(v);
|
||||||
mul3(imag, v, out);
|
mul3(imag, v, out);
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ public:
|
||||||
// 6 7 8
|
// 6 7 8
|
||||||
|
|
||||||
// Multiply two matrices
|
// 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];
|
float tmp[9];
|
||||||
tmp[0] = a[0]*b[0] + a[1]*b[3] + a[2]*b[6];
|
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];
|
tmp[3] = a[3]*b[0] + a[4]*b[3] + a[5]*b[6];
|
||||||
|
@ -114,7 +114,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiply by vector
|
// 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];
|
float x = v[0], y = v[1], z = v[2];
|
||||||
out[0] = x*m[0] + y*m[1] + z*m[2];
|
out[0] = x*m[0] + y*m[1] + z*m[2];
|
||||||
out[1] = x*m[3] + y*m[4] + z*m[5];
|
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
|
// Multiply the vector by the matrix transpose. Or pre-multiply the
|
||||||
// matrix by v as a row vector. Same thing.
|
// 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];
|
float x = v[0], y = v[1], z = v[2];
|
||||||
out[0] = x*m[0] + y*m[3] + z*m[6];
|
out[0] = x*m[0] + y*m[3] + z*m[6];
|
||||||
out[1] = x*m[1] + y*m[4] + z*m[7];
|
out[1] = x*m[1] + y*m[4] + z*m[7];
|
||||||
out[2] = x*m[2] + y*m[5] + z*m[8];
|
out[2] = x*m[2] + y*m[5] + z*m[8];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invert matrix
|
/// Invert symmetric matrix; ~1/3 less calculations due to symmetry
|
||||||
static void invert33(float* m, float* out) {
|
static void invert33_sym(const float* m, float* out) {
|
||||||
// Compute the inverse as the adjoint matrix times 1/(det M).
|
// Compute the inverse as the adjoint matrix times 1/(det M).
|
||||||
// A, B ... I are the cofactors of a b c
|
// A, B ... I are the cofactors of a b c
|
||||||
// d e f
|
// d e f
|
||||||
// g h i
|
// g h i
|
||||||
|
// symetric: d=b, g=c, h=f
|
||||||
float a=m[0], b=m[1], c=m[2];
|
float a=m[0], b=m[1], c=m[2];
|
||||||
float d=m[3], e=m[4], f=m[5];
|
float e=m[4], f=m[5];
|
||||||
float g=m[6], h=m[7], i=m[8];
|
float i=m[8];
|
||||||
|
|
||||||
float A = (e*i - h*f);
|
float A = (e*i - f*f);
|
||||||
float B = -(d*i - g*f);
|
float B = -(b*i - c*f);
|
||||||
float C = (d*h - g*e);
|
float C = (b*f - c*e);
|
||||||
float D = -(b*i - h*c);
|
float E = (a*i - c*c);
|
||||||
float E = (a*i - g*c);
|
float F = -(a*f - c*b);
|
||||||
float F = -(a*h - g*b);
|
float I = (a*e - b*b);
|
||||||
float G = (b*f - e*c);
|
|
||||||
float H = -(a*f - d*c);
|
|
||||||
float I = (a*e - d*b);
|
|
||||||
|
|
||||||
float id = 1/(a*A + b*B + c*C);
|
float id = 1/(a*A + b*B + c*C);
|
||||||
|
|
||||||
out[0] = id*A; out[1] = id*D; out[2] = id*G;
|
out[0] = id*A; out[1] = id*B; out[2] = id*C;
|
||||||
out[3] = id*B; out[4] = id*E; out[5] = id*H;
|
out[3] = out[1]; out[4] = id*E; out[5] = id*F;
|
||||||
out[6] = id*C; out[7] = id*F; out[8] = id*I;
|
out[6] = out[2]; out[7] = out[5]; out[8] = id*I;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transpose matrix (for an orthonormal orientation matrix, this
|
// Transpose matrix (for an orthonormal orientation matrix, this
|
||||||
// is the same as the inverse).
|
// 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
|
// 0 1 2 Elements 0, 4, and 8 are the same
|
||||||
// 3 4 5 Swap elements 1/3, 2/6, and 5/7
|
// 3 4 5 Swap elements 1/3, 2/6, and 5/7
|
||||||
// 6 7 8
|
// 6 7 8
|
||||||
|
@ -184,7 +182,7 @@ public:
|
||||||
// xOut becomes the unit vector in the direction of x
|
// xOut becomes the unit vector in the direction of x
|
||||||
// yOut is perpendicular to xOut in the x/y plane
|
// yOut is perpendicular to xOut in the x/y plane
|
||||||
// zOut becomes the unit vector: (xOut cross yOut)
|
// 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* xOut, float* yOut, float* zOut) {
|
||||||
float x0[3], y0[3];
|
float x0[3], y0[3];
|
||||||
set3(x, x0);
|
set3(x, x0);
|
||||||
|
|
|
@ -66,13 +66,20 @@ Model::Model()
|
||||||
_hook = 0;
|
_hook = 0;
|
||||||
_launchbar = 0;
|
_launchbar = 0;
|
||||||
|
|
||||||
_groundEffectSpan = 0;
|
_wingSpan = 0;
|
||||||
_groundEffect = 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[0] = 0; _global_ground[1] = 0; _global_ground[2] = 1;
|
||||||
_global_ground[3] = -100000;
|
_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()
|
Model::~Model()
|
||||||
|
@ -175,106 +182,12 @@ void Model::iterate()
|
||||||
_integrator.calcNewInterval();
|
_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)
|
void Model::setState(State* s)
|
||||||
{
|
{
|
||||||
_integrator.setState(s);
|
_integrator.setState(s);
|
||||||
_s = _integrator.getState();
|
_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)
|
void Model::setGroundCallback(Ground* ground_cb)
|
||||||
{
|
{
|
||||||
|
@ -282,30 +195,20 @@ void Model::setGroundCallback(Ground* ground_cb)
|
||||||
_ground_cb = 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;
|
Math::set3(pos, _geRefPoint);
|
||||||
}
|
_wingSpan = span;
|
||||||
|
|
||||||
void Model::setGroundEffect(float* pos, float span, float mul)
|
|
||||||
{
|
|
||||||
Math::set3(pos, _wingCenter);
|
|
||||||
_groundEffectSpan = span;
|
|
||||||
_groundEffect = mul;
|
_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;
|
_pressure = pressure;
|
||||||
_temp = temp;
|
_temp = temp;
|
||||||
_rho = density;
|
_rho = density;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::setWind(float* wind)
|
|
||||||
{
|
|
||||||
Math::set3(wind, _wind);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Model::updateGround(State* s)
|
void Model::updateGround(State* s)
|
||||||
{
|
{
|
||||||
float dummy[3];
|
float dummy[3];
|
||||||
|
@ -431,6 +334,12 @@ void Model::calcForces(State* s)
|
||||||
_body.addForce(pos, force);
|
_body.addForce(pos, force);
|
||||||
_body.addTorque(torque);
|
_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++)
|
for (j=0; j<_rotorgear.getRotors()->size();j++)
|
||||||
{
|
{
|
||||||
Rotor* r = (Rotor *)_rotorgear.getRotors()->get(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
|
// Account for ground effect by multiplying the vertical force
|
||||||
// component by an amount linear with the fraction of the wingspan
|
// component by an amount linear with the fraction of the wingspan
|
||||||
// above the ground.
|
// above the ground.
|
||||||
if ((_groundEffectSpan != 0) && (_groundEffect != 0 ))
|
if ((_wingSpan != 0) && (_groundEffect != 0 ))
|
||||||
{
|
{
|
||||||
float dist = ground[3] - Math::dot3(ground, _wingCenter);
|
// distance between ground and wing ref. point
|
||||||
if(dist > 0 && dist < _groundEffectSpan) {
|
float dist = ground[3] - Math::dot3(ground, _geRefPoint);
|
||||||
float fz = Math::dot3(faero, ground);
|
float fz = 0;
|
||||||
fz *= (_groundEffectSpan - dist) / _groundEffectSpan;
|
float geForce[3];
|
||||||
|
if(dist > 0 && dist < _wingSpan) {
|
||||||
|
fz = Math::dot3(faero, ground);
|
||||||
|
fz *= (_wingSpan - dist) / _wingSpan;
|
||||||
fz *= _groundEffect;
|
fz *= _groundEffect;
|
||||||
Math::mul3(fz, ground, faero);
|
Math::mul3(fz, ground, geForce);
|
||||||
_body.addForce(faero);
|
_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
|
// Convert the velocity and rotation vectors to local coordinates
|
||||||
float lrot[3], lv[3];
|
float lrot[3], lv[3];
|
||||||
Math::vmul33(s->orient, s->rot, lrot);
|
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
|
// Calculates the airflow direction at the given point and for the
|
||||||
// specified aircraft velocity.
|
// 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];
|
float tmp[3], lwind[3], lrot[3], lv[3];
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "Vector.hpp"
|
#include "Vector.hpp"
|
||||||
#include "Turbulence.hpp"
|
#include "Turbulence.hpp"
|
||||||
#include "Rotor.hpp"
|
#include "Rotor.hpp"
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
|
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
|
||||||
|
@ -26,49 +27,49 @@ public:
|
||||||
Model();
|
Model();
|
||||||
virtual ~Model();
|
virtual ~Model();
|
||||||
|
|
||||||
RigidBody* getBody();
|
RigidBody* getBody() { return &_body; }
|
||||||
Integrator* getIntegrator();
|
Integrator* getIntegrator() { return &_integrator; }
|
||||||
|
|
||||||
void setTurbulence(Turbulence* turb) { _turb = turb; }
|
void setTurbulence(Turbulence* turb) { _turb = turb; }
|
||||||
|
|
||||||
State* getState();
|
State* getState() { return _s; }
|
||||||
void setState(State* s);
|
void setState(State* s);
|
||||||
|
|
||||||
bool isCrashed();
|
bool isCrashed() { return _crashed; }
|
||||||
void setCrashed(bool crashed);
|
void setCrashed(bool crashed) { _crashed = crashed; }
|
||||||
float getAGL();
|
float getAGL() { return _agl; }
|
||||||
|
|
||||||
void iterate();
|
void iterate();
|
||||||
|
|
||||||
// Externally-managed subcomponents
|
// Externally-managed subcomponents
|
||||||
int addThruster(Thruster* t);
|
int addThruster(Thruster* t) { return _thrusters.add(t); }
|
||||||
int addSurface(Surface* surf);
|
int addSurface(Surface* surf) { return _surfaces.add(surf); }
|
||||||
int addGear(Gear* gear);
|
int addGear(Gear* gear) { return _gears.add(gear); }
|
||||||
void addHook(Hook* hook);
|
void addHook(Hook* hook) { _hook = hook; }
|
||||||
void addLaunchbar(Launchbar* launchbar);
|
void addLaunchbar(Launchbar* launchbar) { _launchbar = launchbar; }
|
||||||
Surface* getSurface(int handle);
|
Surface* getSurface(int handle) { return (Surface*)_surfaces.get(handle); }
|
||||||
Rotorgear* getRotorgear(void);
|
Rotorgear* getRotorgear(void) { return &_rotorgear; }
|
||||||
Gear* getGear(int handle);
|
Gear* getGear(int handle);
|
||||||
Hook* getHook(void);
|
Hook* getHook(void) { return _hook; }
|
||||||
int addHitch(Hitch* hitch);
|
int addHitch(Hitch* hitch) { return _hitches.add(hitch); }
|
||||||
Launchbar* getLaunchbar(void);
|
Launchbar* getLaunchbar(void) { return _launchbar; }
|
||||||
|
|
||||||
// Semi-private methods for use by the Airplane solver.
|
// Semi-private methods for use by the Airplane solver.
|
||||||
int numThrusters();
|
int numThrusters() { return _thrusters.size(); }
|
||||||
Thruster* getThruster(int handle);
|
Thruster* getThruster(int handle) { return (Thruster*)_thrusters.get(handle); }
|
||||||
void setThruster(int handle, Thruster* t);
|
void setThruster(int handle, Thruster* t) { _thrusters.set(handle, t); }
|
||||||
void initIteration();
|
void initIteration();
|
||||||
void getThrust(float* out);
|
void getThrust(float* out);
|
||||||
|
|
||||||
void setGroundCallback(Ground* ground_cb);
|
void setGroundCallback(Ground* ground_cb);
|
||||||
Ground* getGroundCallback(void);
|
Ground* getGroundCallback(void) { return _ground_cb; }
|
||||||
|
|
||||||
//
|
//
|
||||||
// Per-iteration settables
|
// Per-iteration settables
|
||||||
//
|
//
|
||||||
void setGroundEffect(float* pos, float span, float mul);
|
void setGroundEffect(const float* pos, const float span, const float mul);
|
||||||
void setWind(float* wind);
|
void setWind(float* wind) { Math::set3(wind, _wind); }
|
||||||
void setAir(float pressure, float temp, float density);
|
void setAir(const float pressure, const float temp, const float density);
|
||||||
|
|
||||||
void updateGround(State* s);
|
void updateGround(State* s);
|
||||||
|
|
||||||
|
@ -80,8 +81,7 @@ private:
|
||||||
void initRotorIteration();
|
void initRotorIteration();
|
||||||
void calcGearForce(Gear* g, float* v, float* rot, float* ground);
|
void calcGearForce(Gear* g, float* v, float* rot, float* ground);
|
||||||
float gearFriction(float wgt, float v, Gear* g);
|
float gearFriction(float wgt, float v, Gear* g);
|
||||||
void localWind(float* pos, State* s, float* out, float alt,
|
void localWind(const float* pos, State* s, float* out, float alt, bool is_rotor = false);
|
||||||
bool is_rotor = false);
|
|
||||||
|
|
||||||
Integrator _integrator;
|
Integrator _integrator;
|
||||||
RigidBody _body;
|
RigidBody _body;
|
||||||
|
@ -96,9 +96,9 @@ private:
|
||||||
Launchbar* _launchbar;
|
Launchbar* _launchbar;
|
||||||
Vector _hitches;
|
Vector _hitches;
|
||||||
|
|
||||||
float _groundEffectSpan;
|
float _wingSpan;
|
||||||
float _groundEffect;
|
float _groundEffect;
|
||||||
float _wingCenter[3];
|
float _geRefPoint[3];
|
||||||
|
|
||||||
Ground* _ground_cb;
|
Ground* _ground_cb;
|
||||||
double _global_ground[4];
|
double _global_ground[4];
|
||||||
|
@ -114,6 +114,14 @@ private:
|
||||||
State* _s;
|
State* _s;
|
||||||
bool _crashed;
|
bool _crashed;
|
||||||
float _agl;
|
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
|
}; // namespace yasim
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "Math.hpp"
|
#include <Main/fg_props.hxx>
|
||||||
#include "RigidBody.hpp"
|
#include "RigidBody.hpp"
|
||||||
|
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
|
||||||
RigidBody::RigidBody()
|
RigidBody::RigidBody()
|
||||||
|
@ -11,6 +12,7 @@ RigidBody::RigidBody()
|
||||||
_masses = new Mass[_massesAlloced];
|
_masses = new Mass[_massesAlloced];
|
||||||
_gyro[0] = _gyro[1] = _gyro[2] = 0;
|
_gyro[0] = _gyro[1] = _gyro[2] = 0;
|
||||||
_spin[0] = _spin[1] = _spin[2] = 0;
|
_spin[0] = _spin[1] = _spin[2] = 0;
|
||||||
|
_bodyN = fgGetNode("/fdm/yasim/model/masses", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
RigidBody::~RigidBody()
|
RigidBody::~RigidBody()
|
||||||
|
@ -18,7 +20,9 @@ RigidBody::~RigidBody()
|
||||||
delete[] _masses;
|
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 out of space, reallocate twice as much
|
||||||
if(_nMasses == _massesAlloced) {
|
if(_nMasses == _massesAlloced) {
|
||||||
|
@ -30,31 +34,37 @@ int RigidBody::addMass(float mass, float* pos)
|
||||||
delete[] _masses;
|
delete[] _masses;
|
||||||
_masses = m2;
|
_masses = m2;
|
||||||
}
|
}
|
||||||
|
setMass(_nMasses, mass, pos, isStatic);
|
||||||
_masses[_nMasses].m = mass;
|
|
||||||
Math::set3(pos, _masses[_nMasses].p);
|
|
||||||
return _nMasses++;
|
return _nMasses++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// change mass
|
||||||
|
/// handle: returned by addMass
|
||||||
void RigidBody::setMass(int handle, float mass)
|
void RigidBody::setMass(int handle, float mass)
|
||||||
{
|
{
|
||||||
|
if (_masses[handle].m == mass)
|
||||||
|
return;
|
||||||
_masses[handle].m = mass;
|
_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);
|
Math::set3(pos, _masses[handle].p);
|
||||||
}
|
setMass(handle, mass);
|
||||||
|
if (_bodyN != 0) {
|
||||||
int RigidBody::numMasses()
|
SGPropertyNode_ptr n = _bodyN->getChild("mass", handle, true);
|
||||||
{
|
n->getNode("isStatic", true)->setValue(isStatic);
|
||||||
return _nMasses;
|
n->getNode("pos-x", true)->setFloatValue(pos[0]);
|
||||||
}
|
n->getNode("pos-y", true)->setFloatValue(pos[1]);
|
||||||
|
n->getNode("pos-z", true)->setFloatValue(pos[2]);
|
||||||
float RigidBody::getMass(int handle)
|
}
|
||||||
{
|
|
||||||
return _masses[handle].m;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RigidBody::getMassPosition(int handle, float* out)
|
void RigidBody::getMassPosition(int handle, float* out)
|
||||||
|
@ -64,60 +74,129 @@ void RigidBody::getMassPosition(int handle, float* out)
|
||||||
out[2] = _masses[handle].p[2];
|
out[2] = _masses[handle].p[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
float RigidBody::getTotalMass()
|
|
||||||
{
|
|
||||||
return _totalMass;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calcualtes the rotational velocity of a particular point. All
|
// Calcualtes the rotational velocity of a particular point. All
|
||||||
// coordinates are local!
|
// 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::sub3(pos, _cg, out); // out = pos-cg
|
||||||
Math::cross3(rot, out, out); // = rot cross (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()
|
void RigidBody::recalc()
|
||||||
{
|
{
|
||||||
// Calculate the c.g and total mass:
|
//aggregate static masses into one mass
|
||||||
_totalMass = 0;
|
if (_staticMass.m == 0) _recalcStatic();
|
||||||
_cg[0] = _cg[1] = _cg[2] = 0;
|
|
||||||
|
// 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;
|
int i;
|
||||||
for(i=0; i<_nMasses; i++) {
|
for(i=0; i<_nMasses; i++) {
|
||||||
|
// only masses we did not aggregate
|
||||||
|
if (!_masses[i].isStatic) {
|
||||||
float m = _masses[i].m;
|
float m = _masses[i].m;
|
||||||
_totalMass += m;
|
_totalMass += m;
|
||||||
_cg[0] += m * _masses[i].p[0];
|
_cg[0] += m * _masses[i].p[0];
|
||||||
_cg[1] += m * _masses[i].p[1];
|
_cg[1] += m * _masses[i].p[1];
|
||||||
_cg[2] += m * _masses[i].p[2];
|
_cg[2] += m * _masses[i].p[2];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Math::mul3(1/_totalMass, _cg, _cg);
|
Math::mul3(1/_totalMass, _cg, _cg);
|
||||||
|
|
||||||
// Now the inertia tensor:
|
// Now the inertia tensor:
|
||||||
for(i=0; i<9; i++)
|
for(i=0; i<9; i++)
|
||||||
_tI[i] = 0;
|
_tI[i] = _tI_static[i];
|
||||||
|
|
||||||
for(i=0; i<_nMasses; i++) {
|
for(i=0; i<_nMasses; i++) {
|
||||||
|
if (!_masses[i].isStatic) {
|
||||||
float m = _masses[i].m;
|
float m = _masses[i].m;
|
||||||
|
|
||||||
float x = _masses[i].p[0] - _cg[0];
|
float x = _masses[i].p[0] - _cg[0];
|
||||||
float y = _masses[i].p[1] - _cg[1];
|
float y = _masses[i].p[1] - _cg[1];
|
||||||
float z = _masses[i].p[2] - _cg[2];
|
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 xy = mx*y; float yz = my*z; float zx = mz*x;
|
||||||
float x2 = m*x*x; float y2 = m*y*y; float z2 = m*z*z;
|
float x2 = mx*x; float y2 = my*y; float z2 = mz*z;
|
||||||
|
|
||||||
_tI[0] += y2+z2; _tI[1] -= xy; _tI[2] -= zx;
|
_tI[0] += y2+z2; _tI[1] -= xy; _tI[2] -= zx;
|
||||||
_tI[3] -= xy; _tI[4] += x2+z2; _tI[5] -= yz;
|
_tI[4] += x2+z2; _tI[5] -= yz;
|
||||||
_tI[6] -= zx; _tI[7] -= yz; _tI[8] += x2+y2;
|
_tI[8] += x2+y2;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// copy symmetric elements
|
||||||
|
_tI[3] = _tI[1];
|
||||||
|
_tI[6] = _tI[2];
|
||||||
|
_tI[7] = _tI[5];
|
||||||
|
|
||||||
// And its inverse
|
//calculate inverse
|
||||||
Math::invert33(_tI, _invI);
|
Math::invert33_sym(_tI, _invI);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RigidBody::reset()
|
void RigidBody::reset()
|
||||||
|
@ -126,17 +205,7 @@ void RigidBody::reset()
|
||||||
_force[0] = _force[1] = _force[2] = 0;
|
_force[0] = _force[1] = _force[2] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RigidBody::addForce(float* force)
|
void RigidBody::addForce(const float* pos, const float* force)
|
||||||
{
|
|
||||||
Math::add3(_force, force, _force);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RigidBody::addTorque(float* torque)
|
|
||||||
{
|
|
||||||
Math::add3(_torque, torque, _torque);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RigidBody::addForce(float* pos, float* force)
|
|
||||||
{
|
{
|
||||||
addForce(force);
|
addForce(force);
|
||||||
|
|
||||||
|
@ -148,21 +217,6 @@ void RigidBody::addForce(float* pos, float* force)
|
||||||
addTorque(t);
|
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)
|
void RigidBody::getAccel(float* pos, float* accelOut)
|
||||||
{
|
{
|
||||||
getAccel(accelOut);
|
getAccel(accelOut);
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#ifndef _RIGIDBODY_HPP
|
#ifndef _RIGIDBODY_HPP
|
||||||
#define _RIGIDBODY_HPP
|
#define _RIGIDBODY_HPP
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
|
#include "Vector.hpp"
|
||||||
|
#include "Math.hpp"
|
||||||
|
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
|
||||||
|
@ -20,27 +23,28 @@ namespace yasim {
|
||||||
//
|
//
|
||||||
class RigidBody
|
class RigidBody
|
||||||
{
|
{
|
||||||
|
SGPropertyNode_ptr _bodyN;
|
||||||
public:
|
public:
|
||||||
RigidBody();
|
RigidBody();
|
||||||
~RigidBody();
|
~RigidBody();
|
||||||
|
|
||||||
// Adds a point mass to the system. Returns a handle so the gyro
|
// Adds a point mass to the system. Returns a handle so the gyro
|
||||||
// can be later modified via setMass().
|
// 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,
|
// Modifies a previously-added point mass (fuel tank running dry,
|
||||||
// gear going up, swing wing swinging, pilot bailing out, etc...)
|
// gear going up, swing wing swinging, pilot bailing out, etc...)
|
||||||
void setMass(int handle, float mass);
|
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();
|
int numMasses() { return _nMasses; }
|
||||||
float getMass(int handle);
|
float getMass(int handle) { return _masses[handle].m; }
|
||||||
void getMassPosition(int handle, float* out);
|
void getMassPosition(int handle, float* out);
|
||||||
float getTotalMass();
|
float getTotalMass() { return _totalMass; }
|
||||||
|
|
||||||
// The velocity, in local coordinates, of the specified point on a
|
// The velocity, in local coordinates, of the specified point on a
|
||||||
// body rotating about its c.g. with velocity rot.
|
// 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
|
// Sets the "gyroscope" for the body. This is the total
|
||||||
// "intrinsic" angular momentum of the body; that is, rotations of
|
// "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
|
// frame. Because angular momentum is additive in this way, we
|
||||||
// don't need to specify specific gyro objects; just add all their
|
// don't need to specify specific gyro objects; just add all their
|
||||||
// momenta together and set it here.
|
// 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
|
// When masses are moved or changed, this object needs to
|
||||||
// regenerate its internal tables. This step is expensive, so
|
// regenerate its internal tables. This step is expensive, so
|
||||||
// it's exposed to the client who can amortize the call across
|
// it's exposed to the client who can amortize the call across
|
||||||
// multiple changes.
|
// multiple changes. see also _recalcStatic()
|
||||||
void recalc();
|
void recalc();
|
||||||
|
|
||||||
// Resets the current force/torque parameters to zero.
|
// Resets the current force/torque parameters to zero.
|
||||||
void reset();
|
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.
|
// Applies a force at the specified position.
|
||||||
void addForce(float* pos, float* force);
|
void addForce(const float* pos, const float* force);
|
||||||
|
|
||||||
// Applies a force at the center of gravity.
|
|
||||||
void addForce(float* force);
|
|
||||||
|
|
||||||
// Adds a torque with the specified axis and magnitude
|
// 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
|
// Sets the rotation rate of the body (about its c.g.) within the
|
||||||
// surrounding environment. This is needed to compute torque on
|
// surrounding environment. This is needed to compute torque on
|
||||||
|
@ -76,17 +79,15 @@ public:
|
||||||
// rotation. NOTE: the rotation vector, like all other
|
// rotation. NOTE: the rotation vector, like all other
|
||||||
// coordinates used here, is specified IN THE LOCAL COORDINATE
|
// coordinates used here, is specified IN THE LOCAL COORDINATE
|
||||||
// SYSTEM.
|
// 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
|
// Returns the center of gravity of the masses, in the body
|
||||||
// coordinate system.
|
// coordinate system. valid only after recalc()
|
||||||
void getCG(float* cgOut);
|
void getCG(float* cgOut) { Math::set3(_cg, cgOut); }
|
||||||
|
|
||||||
// Returns the acceleration of the body's c.g. relative to the
|
// Returns the acceleration of the body's c.g. relative to the
|
||||||
// rest of the world, specified in local coordinates.
|
// 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
|
// Returns the acceleration of a specific location in local
|
||||||
// coordinates. If the body is rotating, this will be different
|
// coordinates. If the body is rotating, this will be different
|
||||||
|
@ -102,17 +103,24 @@ public:
|
||||||
void getInertiaMatrix(float* inertiaOut);
|
void getInertiaMatrix(float* inertiaOut);
|
||||||
|
|
||||||
private:
|
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 _totalMass;
|
||||||
float _cg[3];
|
float _cg[3];
|
||||||
float _gyro[3];
|
float _gyro[3];
|
||||||
|
|
||||||
// Inertia tensor, and its inverse. Computed from the above.
|
// Inertia tensor, and its inverse. Computed from the above.
|
||||||
|
float _tI_static[9];
|
||||||
float _tI[9];
|
float _tI[9];
|
||||||
float _invI[9];
|
float _invI[9];
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#include "Math.hpp"
|
#include "Math.hpp"
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include "Surface.hpp"
|
//#include "Surface.hpp"
|
||||||
#include "Rotorpart.hpp"
|
#include "Rotorpart.hpp"
|
||||||
#include "Glue.hpp"
|
#include "Glue.hpp"
|
||||||
#include "Ground.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];
|
float pos2rotor[3],tmp[3];
|
||||||
Math::sub3(_base,pos,pos2rotor);
|
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];
|
float tmp[3];
|
||||||
downwash[0]=downwash[1]=downwash[2]=0;
|
downwash[0]=downwash[1]=downwash[2]=0;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
|
||||||
class Surface;
|
//class Surface;
|
||||||
class Rotorpart;
|
class Rotorpart;
|
||||||
class Ground;
|
class Ground;
|
||||||
const float rho_null=1.184f; //25DegC, 101325Pa
|
const float rho_null=1.184f; //25DegC, 101325Pa
|
||||||
|
@ -107,7 +107,7 @@ public:
|
||||||
void updateDirectionsAndPositions(float *rot);
|
void updateDirectionsAndPositions(float *rot);
|
||||||
void getTip(float* tip);
|
void getTip(float* tip);
|
||||||
void calcLiftFactor(float* v, float rho, State *s);
|
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;}
|
int getNumberOfBlades(){return _number_of_blades;}
|
||||||
void setDownwashFactor(float value);
|
void setDownwashFactor(float value);
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ public:
|
||||||
float getEnginePropFactor() {return _engine_prop_factor;}
|
float getEnginePropFactor() {return _engine_prop_factor;}
|
||||||
Vector* getRotors() { return &_rotors;}
|
Vector* getRotors() { return &_rotors;}
|
||||||
void initRotorIteration(float *lrot,float dt);
|
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);
|
int getValueforFGSet(int j,char *b,float *f);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
#include "Math.hpp"
|
#include <Main/fg_props.hxx>
|
||||||
#include "Surface.hpp"
|
#include "Surface.hpp"
|
||||||
|
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
int Surface::s_idGenerator = 0;
|
||||||
|
|
||||||
Surface::Surface( Version * version ) :
|
Surface::Surface( Version * version ) :
|
||||||
_version(version)
|
_version(version)
|
||||||
{
|
{
|
||||||
|
// create id for surface
|
||||||
|
_id = s_idGenerator++;
|
||||||
// Start in a "sane" mode, so unset stuff doesn't freak us out
|
// Start in a "sane" mode, so unset stuff doesn't freak us out
|
||||||
_c0 = 1;
|
_c0 = 1;
|
||||||
_cx = _cy = _cz = 1;
|
_cx = _cy = _cz = 1;
|
||||||
|
@ -30,91 +34,40 @@ Surface::Surface( Version * version ) :
|
||||||
_slatAlpha = 0;
|
_slatAlpha = 0;
|
||||||
_spoilerLift = 1;
|
_spoilerLift = 1;
|
||||||
_inducedDrag = 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;
|
int i;
|
||||||
for(i=0; i<3; i++) _pos[i] = p[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(int i=0; i<9; i++) _orient[i] = o[i];
|
||||||
for(i=0; i<3; i++) out[i] = _pos[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)
|
void Surface::setSlatParams(float stallDelta, float dragPenalty)
|
||||||
{
|
{
|
||||||
|
@ -134,42 +87,39 @@ void Surface::setSpoilerParams(float liftPenalty, float dragPenalty)
|
||||||
_spoilerDrag = dragPenalty;
|
_spoilerDrag = dragPenalty;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Surface::setFlap(float pos)
|
void Surface::setFlapPos(float pos)
|
||||||
{
|
{
|
||||||
|
if (_flapPos != pos) {
|
||||||
_flapPos = pos;
|
_flapPos = pos;
|
||||||
|
if (_surfN != 0) _flapN->setFloatValue(pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Surface::setFlapEffectiveness(float effectiveness)
|
void Surface::setSlatPos(float pos)
|
||||||
{
|
|
||||||
_flapEffectiveness = effectiveness;
|
|
||||||
}
|
|
||||||
|
|
||||||
double Surface::getFlapEffectiveness()
|
|
||||||
{
|
|
||||||
return _flapEffectiveness;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Surface::setSlat(float pos)
|
|
||||||
{
|
{
|
||||||
|
if (_slatPos != pos) {
|
||||||
_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;
|
_spoilerPos = pos;
|
||||||
|
if (_surfN != 0) _spoilerN->setFloatValue(pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the aerodynamic force given a wind vector v (in the
|
// Calculate the aerodynamic force given a wind vector v (in the
|
||||||
// aircraft's "local" coordinates) and an air density rho. Returns a
|
// aircraft's "local" coordinates) and an air density rho. Returns a
|
||||||
// torque about the Y axis, too.
|
// 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:
|
// Split v into magnitude and direction:
|
||||||
float vel = Math::mag3(v);
|
float vel = Math::mag3(v);
|
||||||
|
|
||||||
// Handle the blowup condition. Zero velocity means zero force by
|
// Zero velocity means zero force by definition (also prevents div0).
|
||||||
// definition.
|
|
||||||
if(vel == 0) {
|
if(vel == 0) {
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<3; i++) out[i] = torque[i] = 0;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normalize wind and convert to the surface's coordinates
|
||||||
Math::mul3(1/vel, v, out);
|
Math::mul3(1/vel, v, out);
|
||||||
|
|
||||||
// Convert to the surface's coordinates
|
|
||||||
Math::vmul33(_orient, out, out);
|
Math::vmul33(_orient, out, out);
|
||||||
|
|
||||||
// "Rotate" by the incidence angle. Assume small angles, so we
|
// "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;
|
float scale = 0.5f*rho*vel*vel*_c0;
|
||||||
Math::mul3(scale, out, out);
|
Math::mul3(scale, out, out);
|
||||||
Math::mul3(scale, torque, torque);
|
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
|
#if 0
|
||||||
|
@ -257,9 +215,9 @@ void Surface::test()
|
||||||
float rho = Atmosphere::getStdDensity(0);
|
float rho = Atmosphere::getStdDensity(0);
|
||||||
float spd = 30;
|
float spd = 30;
|
||||||
|
|
||||||
setFlap(0);
|
setFlapPos(0);
|
||||||
setSlat(0);
|
setSlatPos(0);
|
||||||
setSpoiler(0);
|
setSpoilerPos(0);
|
||||||
|
|
||||||
for(float angle = -90; angle<90; angle += 0.01) {
|
for(float angle = -90; angle<90; angle += 0.01) {
|
||||||
float rad = angle * DEG2RAD;
|
float rad = angle * DEG2RAD;
|
||||||
|
@ -281,39 +239,40 @@ float Surface::stallFunc(float* v)
|
||||||
// Sanity check to treat FPU psychopathology
|
// Sanity check to treat FPU psychopathology
|
||||||
if(v[0] == 0) return 1;
|
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.
|
// Wacky use of indexing, see setStall*() methods.
|
||||||
int fwdBak = v[0] > 0; // set if this is "backward motion"
|
int fwdBak = v[0] > 0; // set if this is "backward motion"
|
||||||
int posNeg = v[2] < 0; // set if the airflow is toward -z
|
int posNeg = v[2] < 0; // set if the airflow is toward -z
|
||||||
int i = (fwdBak<<1) | posNeg;
|
int i = (fwdBak<<1) | posNeg;
|
||||||
|
|
||||||
float stallAlpha = _stalls[i];
|
_stallAlpha = _stalls[i];
|
||||||
if(stallAlpha == 0)
|
if(_stallAlpha == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
// consider slat position, moves the stall aoa some degrees
|
||||||
if(i == 0) {
|
if(i == 0) {
|
||||||
if( _version->isVersionOrNewer( Version::YASIM_VERSION_32 )) {
|
if( _version->isVersionOrNewer( Version::YASIM_VERSION_32 )) {
|
||||||
stallAlpha += _slatPos * _slatAlpha;
|
_stallAlpha += _slatPos * _slatAlpha;
|
||||||
} else {
|
} else {
|
||||||
stallAlpha += _slatAlpha;
|
_stallAlpha += _slatAlpha;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Beyond the stall
|
// Beyond the stall
|
||||||
if(alpha > stallAlpha+_widths[i])
|
if(_alpha > _stallAlpha+_widths[i])
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// (note mask: we want to use the "positive" stall angle here)
|
// (note mask: we want to use the "positive" stall angle here)
|
||||||
float scale = 0.5f*_peaks[fwdBak]/_stalls[i&2];
|
float scale = 0.5f*_peaks[fwdBak]/_stalls[i&2];
|
||||||
|
|
||||||
// Before the stall
|
// Before the stall
|
||||||
if(alpha <= stallAlpha)
|
if(_alpha <= _stallAlpha)
|
||||||
return scale;
|
return scale;
|
||||||
|
|
||||||
// Inside the stall. Compute a cubic interpolation between the
|
// Inside the stall. Compute a cubic interpolation between the
|
||||||
// pre-stall "scale" value and the post-stall unity.
|
// 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);
|
frac = frac*frac*(3-2*frac);
|
||||||
|
|
||||||
return scale*(1-frac) + frac;
|
return scale*(1-frac) + frac;
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#ifndef _SURFACE_HPP
|
#ifndef _SURFACE_HPP
|
||||||
#define _SURFACE_HPP
|
#define _SURFACE_HPP
|
||||||
|
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
#include "Version.hpp"
|
#include "Version.hpp"
|
||||||
|
#include "Math.hpp"
|
||||||
|
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
|
||||||
|
@ -10,15 +12,21 @@ namespace yasim {
|
||||||
// front, and flaps act (in both lift and drag) toward the back.
|
// front, and flaps act (in both lift and drag) toward the back.
|
||||||
class Surface
|
class Surface
|
||||||
{
|
{
|
||||||
|
static int s_idGenerator;
|
||||||
|
int _id; //index for property tree
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Surface( Version * version );
|
Surface( Version * version );
|
||||||
|
|
||||||
|
int getID() { return _id; };
|
||||||
|
static void resetIDgen() { s_idGenerator = 0; };
|
||||||
|
|
||||||
// Position of this surface in local coords
|
// Position of this surface in local coords
|
||||||
void setPosition(float* p);
|
void setPosition(const float* p);
|
||||||
void getPosition(float* out);
|
void getPosition(float* out) { Math::set3(_pos, out); }
|
||||||
|
|
||||||
// Distance scale along the X axis
|
// 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
|
// Slats act to move the stall peak by the specified angle, and
|
||||||
// increase drag by the multiplier specified.
|
// increase drag by the multiplier specified.
|
||||||
|
@ -32,49 +40,54 @@ public:
|
||||||
|
|
||||||
// Positions for the controls, in the range [0:1]. [-1:1] for
|
// Positions for the controls, in the range [0:1]. [-1:1] for
|
||||||
// flaps, with positive meaning "force goes towards positive Z"
|
// flaps, with positive meaning "force goes towards positive Z"
|
||||||
void setFlap(float pos);
|
void setFlapPos(float pos);
|
||||||
void setSlat(float pos);
|
void setSlatPos(float pos);
|
||||||
void setSpoiler(float pos);
|
void setSpoilerPos(float pos);
|
||||||
|
|
||||||
// Modifier for flap lift coefficient, useful for simulating flap blowing etc.
|
// Modifier for flap lift coefficient, useful for simulating flap blowing etc.
|
||||||
void setFlapEffectiveness(float effectiveness);
|
void setFlapEffectiveness(float effectiveness) { _flapEffectiveness = effectiveness; }
|
||||||
double getFlapEffectiveness();
|
double getFlapEffectiveness() { return _flapEffectiveness; }
|
||||||
|
|
||||||
// local -> Surface coords
|
// local -> Surface coords
|
||||||
void setOrientation(float* o);
|
void setOrientation(const float* o);
|
||||||
|
|
||||||
// For variable-incidence control surfaces. The angle is a
|
// For variable-incidence control surfaces. The angle is a
|
||||||
// negative rotation about the surface's Y axis, in radians, so
|
// negative rotation about the surface's Y axis, in radians, so
|
||||||
// positive is "up" (i.e. "positive AoA")
|
// 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.
|
// The offset from base incidence for this surface.
|
||||||
void setTwist(float angle);
|
void setTwist(float angle) { _twist = angle; }
|
||||||
|
|
||||||
void setTotalDrag(float c0);
|
void setTotalDrag(float c0) { _c0 = c0; }
|
||||||
float getTotalDrag();
|
float getTotalDrag() { return _c0; }
|
||||||
|
|
||||||
void setXDrag(float cx);
|
void setXDrag(float cx) { _cx = cx; }
|
||||||
void setYDrag(float cy);
|
void setYDrag(float cy) { _cy = cy; }
|
||||||
void setZDrag(float cz);
|
void setZDrag(float cz) { _cz = cz; }
|
||||||
float getXDrag();
|
float getXDrag() { return _cx; }
|
||||||
|
|
||||||
// zero-alpha Z drag ("camber") specified as a fraction of cz
|
// 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
|
// 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
|
// i: 0 == fwd/+z, 1 == fwd/-z, 2 == rev/+z, 3 == rev/-z
|
||||||
void setStall(int i, float alpha);
|
void setStall(int i, float alpha) { _stalls[i] = alpha; }
|
||||||
void setStallWidth(int i, float width);
|
void setStallWidth(int i, float width) { _widths[i] = width; }
|
||||||
|
|
||||||
// Induced drag multiplier
|
// Induced drag multiplier
|
||||||
void setInducedDrag(float mul) { _inducedDrag = mul; }
|
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:
|
private:
|
||||||
|
SGPropertyNode_ptr _surfN;
|
||||||
|
|
||||||
float stallFunc(float* v);
|
float stallFunc(float* v);
|
||||||
float flapLift(float alpha);
|
float flapLift(float alpha);
|
||||||
float controlDrag(float lift, float drag);
|
float controlDrag(float lift, float drag);
|
||||||
|
@ -106,7 +119,20 @@ private:
|
||||||
float _twist;
|
float _twist;
|
||||||
float _inducedDrag;
|
float _inducedDrag;
|
||||||
|
|
||||||
|
// used during calculations
|
||||||
|
float _stallAlpha;
|
||||||
|
float _alpha;
|
||||||
|
|
||||||
Version * _version;
|
Version * _version;
|
||||||
|
SGPropertyNode* _fxN;
|
||||||
|
SGPropertyNode* _fyN;
|
||||||
|
SGPropertyNode* _fzN;
|
||||||
|
SGPropertyNode* _stallAlphaN;
|
||||||
|
SGPropertyNode* _alphaN;
|
||||||
|
SGPropertyNode* _flapN;
|
||||||
|
SGPropertyNode* _slatN;
|
||||||
|
SGPropertyNode* _spoilerN;
|
||||||
|
SGPropertyNode* _fabsN;
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace yasim
|
}; // namespace yasim
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "Version.hpp"
|
#include "Version.hpp"
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
void Version::setVersion( const char * version )
|
void Version::setVersion( const char * version )
|
||||||
|
@ -15,11 +16,15 @@ void Version::setVersion( const char * version )
|
||||||
_version = YASIM_VERSION_ORIGINAL;
|
_version = YASIM_VERSION_ORIGINAL;
|
||||||
} else if( v == "YASIM_VERSION_32" ) {
|
} else if( v == "YASIM_VERSION_32" ) {
|
||||||
_version = YASIM_VERSION_32;
|
_version = YASIM_VERSION_32;
|
||||||
|
} else if( v == "2017.2" ) {
|
||||||
|
_version = YASIM_VERSION_2017_2;
|
||||||
} else if( v == "YASIM_VERSION_CURRENT" ) {
|
} else if( v == "YASIM_VERSION_CURRENT" ) {
|
||||||
_version = YASIM_VERSION_CURRENT;
|
_version = YASIM_VERSION_CURRENT;
|
||||||
} else {
|
} else {
|
||||||
SG_LOG(SG_FLIGHT,SG_ALERT,"unknown yasim version '" << version << "' ignored, using YASIM_VERSION_ORIGINAL");
|
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
|
} // namespace yasim
|
||||||
|
|
|
@ -11,10 +11,12 @@ public:
|
||||||
typedef enum {
|
typedef enum {
|
||||||
YASIM_VERSION_ORIGINAL = 0,
|
YASIM_VERSION_ORIGINAL = 0,
|
||||||
YASIM_VERSION_32,
|
YASIM_VERSION_32,
|
||||||
YASIM_VERSION_CURRENT = YASIM_VERSION_32
|
YASIM_VERSION_2017_2,
|
||||||
|
YASIM_VERSION_CURRENT = YASIM_VERSION_2017_2
|
||||||
} YASIM_VERSION;
|
} YASIM_VERSION;
|
||||||
|
|
||||||
void setVersion( const char * version );
|
void setVersion( const char * version );
|
||||||
|
int getVersion() { return _version; }
|
||||||
bool isVersion( YASIM_VERSION version );
|
bool isVersion( YASIM_VERSION version );
|
||||||
bool isVersionOrNewer( YASIM_VERSION version );
|
bool isVersionOrNewer( YASIM_VERSION version );
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#include "Math.hpp"
|
|
||||||
#include "Surface.hpp"
|
#include "Surface.hpp"
|
||||||
#include "Wing.hpp"
|
#include "Wing.hpp"
|
||||||
|
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
static const float RAD2DEG = 57.2957795131;
|
||||||
|
|
||||||
Wing::Wing( Version * version ) :
|
Wing::Wing( Version * version ) :
|
||||||
_version(version)
|
_version(version)
|
||||||
|
@ -39,6 +39,9 @@ Wing::Wing( Version * version ) :
|
||||||
_slatEnd = 0;
|
_slatEnd = 0;
|
||||||
_slatAoA = 0;
|
_slatAoA = 0;
|
||||||
_slatDrag = 0;
|
_slatDrag = 0;
|
||||||
|
_meanChord = 0;
|
||||||
|
_wingspan = 0;
|
||||||
|
_aspectRatio = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Wing::~Wing()
|
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)
|
void Wing::setIncidence(float incidence)
|
||||||
{
|
{
|
||||||
_incidence = incidence;
|
_incidence = incidence;
|
||||||
|
@ -135,7 +62,7 @@ void Wing::setIncidence(float incidence)
|
||||||
((SurfRec*)_surfs.get(i))->surface->setIncidence(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;
|
_flap0Start = start;
|
||||||
_flap0End = end;
|
_flap0End = end;
|
||||||
|
@ -143,7 +70,7 @@ void Wing::setFlap0(float start, float end, float lift, float drag)
|
||||||
_flap0Drag = 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;
|
_flap1Start = start;
|
||||||
_flap1End = end;
|
_flap1End = end;
|
||||||
|
@ -151,7 +78,7 @@ void Wing::setFlap1(float start, float end, float lift, float drag)
|
||||||
_flap1Drag = 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;
|
_slatStart = start;
|
||||||
_slatEnd = end;
|
_slatEnd = end;
|
||||||
|
@ -159,7 +86,7 @@ void Wing::setSlat(float start, float end, float aoa, float drag)
|
||||||
_slatDrag = 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;
|
_spoilerStart = start;
|
||||||
_spoilerEnd = end;
|
_spoilerEnd = end;
|
||||||
|
@ -167,14 +94,14 @@ void Wing::setSpoiler(float start, float end, float lift, float drag)
|
||||||
_spoilerDrag = drag;
|
_spoilerDrag = drag;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wing::setFlap0(float lval, float rval)
|
void Wing::setFlap0Pos(float lval, float rval)
|
||||||
{
|
{
|
||||||
lval = Math::clamp(lval, -1, 1);
|
lval = Math::clamp(lval, -1, 1);
|
||||||
rval = Math::clamp(rval, -1, 1);
|
rval = Math::clamp(rval, -1, 1);
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<_flap0Surfs.size(); i++) {
|
for(i=0; i<_flap0Surfs.size(); i++) {
|
||||||
((Surface*)_flap0Surfs.get(i))->setFlap(lval);
|
((Surface*)_flap0Surfs.get(i))->setFlapPos(lval);
|
||||||
if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlap(rval);
|
if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlapPos(rval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,18 +111,17 @@ void Wing::setFlap0Effectiveness(float lval)
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<_flap0Surfs.size(); i++) {
|
for(i=0; i<_flap0Surfs.size(); i++) {
|
||||||
((Surface*)_flap0Surfs.get(i))->setFlapEffectiveness(lval);
|
((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);
|
lval = Math::clamp(lval, -1, 1);
|
||||||
rval = Math::clamp(rval, -1, 1);
|
rval = Math::clamp(rval, -1, 1);
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<_flap1Surfs.size(); i++) {
|
for(i=0; i<_flap1Surfs.size(); i++) {
|
||||||
((Surface*)_flap1Surfs.get(i))->setFlap(lval);
|
((Surface*)_flap1Surfs.get(i))->setFlapPos(lval);
|
||||||
if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlap(rval);
|
if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlapPos(rval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,51 +131,26 @@ void Wing::setFlap1Effectiveness(float lval)
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<_flap1Surfs.size(); i++) {
|
for(i=0; i<_flap1Surfs.size(); i++) {
|
||||||
((Surface*)_flap1Surfs.get(i))->setFlapEffectiveness(lval);
|
((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);
|
lval = Math::clamp(lval, 0, 1);
|
||||||
rval = Math::clamp(rval, 0, 1);
|
rval = Math::clamp(rval, 0, 1);
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<_spoilerSurfs.size(); i++) {
|
for(i=0; i<_spoilerSurfs.size(); i++) {
|
||||||
((Surface*)_spoilerSurfs.get(i))->setSpoiler(lval);
|
((Surface*)_spoilerSurfs.get(i))->setSpoilerPos(lval);
|
||||||
if(_mirror) ((Surface*)_spoilerSurfs.get(++i))->setSpoiler(rval);
|
if(_mirror) ((Surface*)_spoilerSurfs.get(++i))->setSpoilerPos(rval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wing::setSlat(float val)
|
void Wing::setSlatPos(float val)
|
||||||
{
|
{
|
||||||
val = Math::clamp(val, 0, 1);
|
val = Math::clamp(val, 0, 1);
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<_slatSurfs.size(); i++)
|
for(i=0; i<_slatSurfs.size(); i++)
|
||||||
((Surface*)_slatSurfs.get(i))->setSlat(val);
|
((Surface*)_slatSurfs.get(i))->setSlatPos(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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wing::compile()
|
void Wing::compile()
|
||||||
|
@ -294,9 +195,8 @@ void Wing::compile()
|
||||||
last = bounds[i];
|
last = bounds[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate a "nominal" segment length equal to an average chord,
|
// prepare wing coordinate system, ignoring incidence and twist for now
|
||||||
// normalized to lie within 0-1 over the length of the wing.
|
// (tail incidence is varied by the solver)
|
||||||
float segLen = _chord * (0.5f*(_taper+1)) / _length;
|
|
||||||
|
|
||||||
// Generating a unit vector pointing out the left wing.
|
// Generating a unit vector pointing out the left wing.
|
||||||
float left[3];
|
float left[3];
|
||||||
|
@ -306,11 +206,12 @@ void Wing::compile()
|
||||||
Math::unit3(left, left);
|
Math::unit3(left, left);
|
||||||
|
|
||||||
// Calculate coordinates for the root and tip of the wing
|
// Calculate coordinates for the root and tip of the wing
|
||||||
float root[3], tip[3];
|
Math::mul3(_length, left, _tip);
|
||||||
Math::set3(_base, root);
|
Math::add3(_base, _tip, _tip);
|
||||||
Math::set3(left, tip);
|
_meanChord = _chord*(_taper+1)*0.5f;
|
||||||
Math::mul3(_length, tip, tip);
|
// wingspan in y-direction (not for vstab)
|
||||||
Math::add3(root, tip, tip);
|
_wingspan = Math::abs(2*_tip[1]);
|
||||||
|
_aspectRatio = _wingspan / _meanChord;
|
||||||
|
|
||||||
// The wing's Y axis will be the "left" vector. The Z axis will
|
// 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
|
// 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];
|
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
|
// Now go through each boundary and make segments
|
||||||
for(i=0; i<(nbounds-1); i++) {
|
for(i=0; i<(nbounds-1); i++) {
|
||||||
float start = bounds[i];
|
float start = bounds[i];
|
||||||
|
@ -363,7 +268,7 @@ void Wing::compile()
|
||||||
for(j=0; j<nSegs; j++) {
|
for(j=0; j<nSegs; j++) {
|
||||||
float frac = start + (j+0.5f) * (end-start)/nSegs;
|
float frac = start + (j+0.5f) * (end-start)/nSegs;
|
||||||
float pos[3];
|
float pos[3];
|
||||||
interp(root, tip, frac, pos);
|
interp(_base, _tip, frac, pos);
|
||||||
|
|
||||||
float chord = _chord * (1 - (1-_taper)*frac);
|
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
|
// Last of all, re-set the incidence in case setIncidence() was
|
||||||
// called before we were compiled.
|
// called before we were compiled.
|
||||||
setIncidence(_incidence);
|
setIncidence(_incidence);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Wing::getDragScale()
|
|
||||||
{
|
|
||||||
return _dragScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Wing::setDragScale(float scale)
|
void Wing::setDragScale(float scale)
|
||||||
{
|
{
|
||||||
_dragScale = scale;
|
_dragScale = scale;
|
||||||
int i;
|
for(int i=0; i<_surfs.size(); i++) {
|
||||||
for(i=0; i<_surfs.size(); i++) {
|
|
||||||
SurfRec* s = (SurfRec*)_surfs.get(i);
|
SurfRec* s = (SurfRec*)_surfs.get(i);
|
||||||
s->surface->setTotalDrag(scale * s->weight);
|
s->surface->setTotalDrag(scale * s->weight);
|
||||||
}
|
}
|
||||||
|
@ -414,16 +313,10 @@ void Wing::setDragScale(float scale)
|
||||||
void Wing::setLiftRatio(float ratio)
|
void Wing::setLiftRatio(float ratio)
|
||||||
{
|
{
|
||||||
_liftRatio = ratio;
|
_liftRatio = ratio;
|
||||||
int i;
|
for(int i=0; i<_surfs.size(); i++)
|
||||||
for(i=0; i<_surfs.size(); i++)
|
|
||||||
((SurfRec*)_surfs.get(i))->surface->setZDrag(ratio);
|
((SurfRec*)_surfs.get(i))->surface->setZDrag(ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Wing::getLiftRatio()
|
|
||||||
{
|
|
||||||
return _liftRatio;
|
|
||||||
}
|
|
||||||
|
|
||||||
Surface* Wing::newSurface(float* pos, float* orient, float chord,
|
Surface* Wing::newSurface(float* pos, float* orient, float chord,
|
||||||
bool flap0, bool flap1, bool slat, bool spoiler)
|
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->setStallWidth(0, _stallWidth);
|
||||||
s->setStallPeak(0, _stallPeak);
|
s->setStallPeak(0, _stallPeak);
|
||||||
|
|
||||||
// The negative AoA stall is the same if we're using an uncambered
|
// The negative AoA stall is the same if we're using an symmetric
|
||||||
// airfoil, otherwise a "little badder".
|
// airfoil, otherwise a "little worse".
|
||||||
if(_camber > 0) {
|
if(_camber > 0) {
|
||||||
s->setStall(1, stallAoA * 0.8f);
|
s->setStall(1, stallAoA * 0.8f);
|
||||||
s->setStallWidth(1, _stallWidth * 0.5f);
|
s->setStallWidth(1, _stallWidth * 0.5f);
|
||||||
} else {
|
} else {
|
||||||
s->setStall(1, stallAoA);
|
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);
|
s->setStall(1, _stallWidth);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The "reverse" stalls are unmeasurable junk. Just use 13deg and
|
// The "reverse" stalls are unmeasurable junk. Just use 13deg and
|
||||||
// "sharp".
|
// "sharp".
|
||||||
|
@ -476,7 +375,7 @@ Surface* Wing::newSurface(float* pos, float* orient, float chord,
|
||||||
return s;
|
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[0] = v1[0] + frac*(v2[0]-v1[0]);
|
||||||
out[1] = v1[1] + frac*(v2[1]-v1[1]);
|
out[1] = v1[1] + frac*(v2[1]-v1[1]);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "Vector.hpp"
|
#include "Vector.hpp"
|
||||||
#include "Version.hpp"
|
#include "Version.hpp"
|
||||||
|
#include "Math.hpp"
|
||||||
|
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
|
||||||
|
@ -15,64 +16,81 @@ public:
|
||||||
~Wing();
|
~Wing();
|
||||||
|
|
||||||
// Do we mirror ourselves about the XZ plane?
|
// Do we mirror ourselves about the XZ plane?
|
||||||
void setMirror(bool mirror);
|
void setMirror(bool mirror) { _mirror = mirror; }
|
||||||
|
bool isMirrored() { return _mirror; };
|
||||||
|
|
||||||
// Wing geometry:
|
// Wing geometry in local coordinates:
|
||||||
void setBase(float* base); // in local coordinates
|
|
||||||
void setLength(float length); // dist. ALONG wing (not span!)
|
// base point of wing
|
||||||
void setChord(float chord); // at base, measured along X axis
|
void setBase(const float* base) { Math::set3(base, _base); }
|
||||||
void setTaper(float taper); // fraction, 0-1
|
void getBase(float* base) { Math::set3(_base, base); };
|
||||||
void setSweep(float sweep); // radians
|
// dist. ALONG wing (not span!)
|
||||||
void setDihedral(float dihedral); // radians, positive is "up"
|
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 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 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 setFlap0Params(float start, float end, float lift, float drag);
|
||||||
void setSpoiler(float start, float end, float lift, float drag);
|
void setFlap1Params(float start, float end, float lift, float drag);
|
||||||
void setSlat(float start, float end, float aoa, 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
|
// Set the control axes for the sub-surfaces
|
||||||
void setFlap0(float lval, float rval);
|
void setFlap0Pos(float lval, float rval);
|
||||||
void setFlap1(float lval, float rval);
|
void setFlap1Pos(float lval, float rval);
|
||||||
void setSpoiler(float lval, float rval);
|
void setSpoilerPos(float lval, float rval);
|
||||||
void setSlat(float val);
|
void setSlatPos(float val);
|
||||||
void setFlap0Effectiveness(float lval);
|
void setFlap0Effectiveness(float lval);
|
||||||
void setFlap1Effectiveness(float lval);
|
void setFlap1Effectiveness(float lval);
|
||||||
|
|
||||||
// Compile the thing into a bunch of Surface objects
|
// Compile the thing into a bunch of Surface objects
|
||||||
void compile();
|
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();
|
int numSurfaces() { return _surfs.size(); }
|
||||||
|
Surface* getSurface(int n) { return ((SurfRec*)_surfs.get(n))->surface; }
|
||||||
// Ground effect information
|
float getSurfaceWeight(int n) { return ((SurfRec*)_surfs.get(n))->weight; }
|
||||||
float getGroundEffect(float* posOut);
|
|
||||||
|
|
||||||
// Query the list of Surface objects
|
|
||||||
int numSurfaces();
|
|
||||||
Surface* getSurface(int n);
|
|
||||||
float getSurfaceWeight(int n);
|
|
||||||
|
|
||||||
// The overall drag coefficient for the wing as a whole. Units are
|
// The overall drag coefficient for the wing as a whole. Units are
|
||||||
// arbitrary.
|
// arbitrary.
|
||||||
void setDragScale(float scale);
|
void setDragScale(float scale);
|
||||||
float getDragScale();
|
float getDragScale() { return _dragScale; }
|
||||||
|
|
||||||
// The ratio of force along the Z (lift) direction of each wing
|
// The ratio of force along the Z (lift) direction of each wing
|
||||||
// segment to that along the X (drag) direction.
|
// segment to that along the X (drag) direction.
|
||||||
void setLiftRatio(float ratio);
|
void setLiftRatio(float ratio);
|
||||||
float getLiftRatio();
|
float getLiftRatio() { return _liftRatio; }
|
||||||
|
|
||||||
private:
|
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,
|
Surface* newSurface(float* pos, float* orient, float chord,
|
||||||
bool flap0, bool flap1, bool slat, bool spoiler);
|
bool flap0, bool flap1, bool slat, bool spoiler);
|
||||||
|
|
||||||
|
@ -93,6 +111,12 @@ private:
|
||||||
float _sweep;
|
float _sweep;
|
||||||
float _dihedral;
|
float _dihedral;
|
||||||
|
|
||||||
|
// calculated from above
|
||||||
|
float _tip[3];
|
||||||
|
float _meanChord; // std. mean chord
|
||||||
|
float _wingspan;
|
||||||
|
float _aspectRatio;
|
||||||
|
|
||||||
float _stall;
|
float _stall;
|
||||||
float _stallWidth;
|
float _stallWidth;
|
||||||
float _stallPeak;
|
float _stallPeak;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "FGFDM.hpp"
|
#include "FGFDM.hpp"
|
||||||
#include "Atmosphere.hpp"
|
#include "Atmosphere.hpp"
|
||||||
|
#include "RigidBody.hpp"
|
||||||
#include "Airplane.hpp"
|
#include "Airplane.hpp"
|
||||||
|
|
||||||
using namespace yasim;
|
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 RAD2DEG = 57.2957795131;
|
||||||
static const float DEG2RAD = 0.0174532925199;
|
static const float DEG2RAD = 0.0174532925199;
|
||||||
|
/// knots 2 meters per second
|
||||||
static const float KTS2MPS = 0.514444444444;
|
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
|
// 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
|
// speed and altitude. The result is a space-separated file of
|
||||||
// numbers: "aoa lift drag LD" (aoa in degrees, lift and drag in
|
// 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:3 with lines title 'drag', \
|
||||||
"dat" using 1:4 with lines title 'LD'
|
"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();
|
Model* m = a->getModel();
|
||||||
State s;
|
State s;
|
||||||
|
@ -48,9 +57,24 @@ void yasim_graph(Airplane* a, float alt, float kts)
|
||||||
m->setAir(Atmosphere::getStdPressure(alt),
|
m->setAir(Atmosphere::getStdPressure(alt),
|
||||||
Atmosphere::getStdTemperature(alt),
|
Atmosphere::getStdTemperature(alt),
|
||||||
Atmosphere::getStdDensity(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;
|
float aoa = deg * DEG2RAD;
|
||||||
Airplane::setupState(aoa, kts * KTS2MPS, 0 ,&s);
|
Airplane::setupState(aoa, kts * KTS2MPS, 0 ,&s);
|
||||||
m->getBody()->reset();
|
m->getBody()->reset();
|
||||||
|
@ -63,47 +87,161 @@ void yasim_graph(Airplane* a, float alt, float kts)
|
||||||
|
|
||||||
float drag = acc[0] * (-1/9.8);
|
float drag = acc[0] * (-1/9.8);
|
||||||
float lift = 1 + acc[2] * (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()
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
FGFDM* fdm = new FGFDM();
|
FGFDM* fdm = new FGFDM();
|
||||||
Airplane* a = fdm->getAirplane();
|
Airplane* a = fdm->getAirplane();
|
||||||
|
|
||||||
if(argc < 2) return usage();
|
if(argc < 2) return usage();
|
||||||
|
|
||||||
// Read
|
// Read
|
||||||
try {
|
try {
|
||||||
string file = argv[1];
|
string file = argv[1];
|
||||||
readXML(SGPath(file), *fdm);
|
readXML(SGPath(file), *fdm);
|
||||||
} catch (const sg_exception &e) {
|
}
|
||||||
printf("XML parse error: %s (%s)\n",
|
catch (const sg_exception &e) {
|
||||||
e.getFormattedMessage().c_str(), e.getOrigin());
|
printf("XML parse error: %s (%s)\n", e.getFormattedMessage().c_str(), e.getOrigin());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... and run
|
// ... and run
|
||||||
a->compile();
|
a->compile();
|
||||||
if(a->getFailureMsg())
|
if(a->getFailureMsg())
|
||||||
printf("SOLUTION FAILURE: %s\n", a->getFailureMsg());
|
printf("SOLUTION FAILURE: %s\n", a->getFailureMsg());
|
||||||
|
if(!a->getFailureMsg() && argc > 2 ) {
|
||||||
if(!a->getFailureMsg() && argc > 2 && strcmp(argv[2], "-g") == 0) {
|
if(strcmp(argv[2], "-g") == 0) {
|
||||||
float alt = 5000, kts = 100;
|
float alt = 5000, kts = 100;
|
||||||
|
int cfg = CONFIG_NONE;
|
||||||
for(int i=3; i<argc; i++) {
|
for(int i=3; i<argc; i++) {
|
||||||
if (std::strcmp(argv[i], "-a") == 0) alt = std::atof(argv[++i]);
|
if (std::strcmp(argv[i], "-a") == 0) {
|
||||||
else if(std::strcmp(argv[i], "-s") == 0) kts = std::atof(argv[++i]);
|
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();
|
else return usage();
|
||||||
}
|
}
|
||||||
yasim_graph(a, alt, kts);
|
yasim_graph(a, alt, kts, cfg);
|
||||||
} else {
|
}
|
||||||
|
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 aoa = a->getCruiseAoA() * RAD2DEG;
|
||||||
float tail = -1 * a->getTailIncidence() * RAD2DEG;
|
float tail = -1 * a->getTailIncidence() * RAD2DEG;
|
||||||
float drag = 1000 * a->getDragCoefficient();
|
float drag = 1000 * a->getDragCoefficient();
|
||||||
|
@ -114,7 +252,6 @@ int main(int argc, char** argv)
|
||||||
float SI_inertia[9];
|
float SI_inertia[9];
|
||||||
a->getModel()->getBody()->getInertiaMatrix(SI_inertia);
|
a->getModel()->getBody()->getInertiaMatrix(SI_inertia);
|
||||||
|
|
||||||
printf("Solution results:");
|
|
||||||
printf(" Iterations: %d\n", a->getSolutionIterations());
|
printf(" Iterations: %d\n", a->getSolutionIterations());
|
||||||
printf(" Drag Coefficient: %f\n", drag);
|
printf(" Drag Coefficient: %f\n", drag);
|
||||||
printf(" Lift Ratio: %f\n", a->getLiftRatio());
|
printf(" Lift Ratio: %f\n", a->getLiftRatio());
|
||||||
|
@ -122,9 +259,10 @@ int main(int argc, char** argv)
|
||||||
printf(" Tail Incidence: %f\n", tail);
|
printf(" Tail Incidence: %f\n", tail);
|
||||||
printf("Approach Elevator: %f\n", a->getApproachElevator());
|
printf("Approach Elevator: %f\n", a->getApproachElevator());
|
||||||
printf(" CG: x:%.3f, y:%.3f, z:%.3f\n\n", cg[0], cg[1], cg[2]);
|
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("Inertia tensor [kg*m^2], origo at CG:\n");
|
||||||
printf(" [kg*m^2] %.3f, %.3f, %.3f\n", SI_inertia[3], SI_inertia[4], SI_inertia[5]);
|
printf(" %7.3f, %7.3f, %7.3f\n", SI_inertia[0], SI_inertia[1], SI_inertia[2]);
|
||||||
printf(" Origo at CG %.3f, %.3f, %.3f\n", SI_inertia[6], SI_inertia[7], SI_inertia[8]);
|
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;
|
delete fdm;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -67,7 +67,6 @@
|
||||||
|
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Scenery/scenery.hxx>
|
#include <Scenery/scenery.hxx>
|
||||||
#include <Scenery/tilemgr.hxx>
|
|
||||||
|
|
||||||
#include "flight.hxx"
|
#include "flight.hxx"
|
||||||
|
|
||||||
|
@ -330,7 +329,7 @@ FGGroundCache::prepare_ground_cache(double startSimTime, double endSimTime,
|
||||||
SGGeod geodPt = SGGeod::fromCart(pt);
|
SGGeod geodPt = SGGeod::fromCart(pt);
|
||||||
// Don't blow away the cache ground_radius and stuff if there's no
|
// Don't blow away the cache ground_radius and stuff if there's no
|
||||||
// scenery
|
// 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 "
|
SG_LOG(SG_FLIGHT, SG_BULK, "prepare_ground_cache(): scenery_available "
|
||||||
"returns false at " << geodPt << " " << pt << " " << rad);
|
"returns false at " << geodPt << " " << pt << " " << rad);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -59,6 +59,12 @@ CatalogRef AddCatalogDialog::addedCatalog()
|
||||||
return m_result;
|
return m_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddCatalogDialog::setNonInteractiveMode()
|
||||||
|
{
|
||||||
|
m_nonInteractiveMode = true;
|
||||||
|
ui->buttonBox->hide();
|
||||||
|
}
|
||||||
|
|
||||||
void AddCatalogDialog::setUrlAndDownload(QUrl url)
|
void AddCatalogDialog::setUrlAndDownload(QUrl url)
|
||||||
{
|
{
|
||||||
m_catalogUrl = url;
|
m_catalogUrl = url;
|
||||||
|
@ -199,6 +205,10 @@ void AddCatalogDialog::onCatalogStatusChanged(Catalog* cat)
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->stack->setCurrentIndex(STATE_FINISHED);
|
ui->stack->setCurrentIndex(STATE_FINISHED);
|
||||||
|
if (m_nonInteractiveMode) {
|
||||||
|
QDialog::accept(); // we're done
|
||||||
|
}
|
||||||
|
|
||||||
updateUi();
|
updateUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,13 @@ public:
|
||||||
|
|
||||||
simgear::pkg::CatalogRef addedCatalog();
|
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);
|
void setUrlAndDownload(QUrl url);
|
||||||
private slots:
|
private slots:
|
||||||
virtual void reject();
|
virtual void reject();
|
||||||
|
@ -69,6 +76,7 @@ private:
|
||||||
simgear::pkg::RootRef m_packageRoot;
|
simgear::pkg::RootRef m_packageRoot;
|
||||||
QUrl m_catalogUrl;
|
QUrl m_catalogUrl;
|
||||||
simgear::pkg::CatalogRef m_result;
|
simgear::pkg::CatalogRef m_result;
|
||||||
|
bool m_nonInteractiveMode = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FG_GUI_ADDCATALOGDIALOG_HXX
|
#endif // FG_GUI_ADDCATALOGDIALOG_HXX
|
||||||
|
|
|
@ -46,6 +46,8 @@ AircraftItemDelegate::AircraftItemDelegate(QListView* view) :
|
||||||
|
|
||||||
m_leftArrowIcon.load(":/left-arrow-icon");
|
m_leftArrowIcon.load(":/left-arrow-icon");
|
||||||
m_rightArrowIcon.load(":/right-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,
|
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());
|
painter->drawLine(option.rect.topLeft(), option.rect.topRight());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// thumbnail
|
||||||
QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
|
QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
|
||||||
quint32 yPos = contentRect.center().y() - (thumbnail.height() / 2);
|
quint32 yPos = contentRect.center().y() - (thumbnail.height() / 2);
|
||||||
painter->drawPixmap(contentRect.left(), yPos, thumbnail);
|
painter->drawPixmap(contentRect.left(), yPos, thumbnail);
|
||||||
|
|
||||||
// draw 1px frame
|
// draw 1px frame
|
||||||
|
QRect thumbFrame(contentRect.left(), yPos, thumbnail.width(), thumbnail.height());
|
||||||
painter->setPen(QColor(0x7f, 0x7f, 0x7f));
|
painter->setPen(QColor(0x7f, 0x7f, 0x7f));
|
||||||
painter->setBrush(Qt::NoBrush);
|
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
|
// draw bottom dividing line
|
||||||
painter->drawLine(contentRect.left(), contentRect.bottom() + MARGIN,
|
painter->drawLine(contentRect.left(), contentRect.bottom() + MARGIN,
|
||||||
|
@ -337,6 +346,13 @@ bool AircraftItemDelegate::eventFilter( QObject*, QEvent* event )
|
||||||
|
|
||||||
return true;
|
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 ) {
|
} else if ( event->type() == QEvent::MouseMove ) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -381,6 +397,18 @@ QRect AircraftItemDelegate::packageButtonRect(const QRect& visualRect, const QMo
|
||||||
BUTTON_WIDTH, BUTTON_HEIGHT);
|
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
|
void AircraftItemDelegate::drawRating(QPainter* painter, QString label, const QRect& box, int value) const
|
||||||
{
|
{
|
||||||
QRect dotBox = box;
|
QRect dotBox = box;
|
||||||
|
|
|
@ -50,17 +50,23 @@ Q_SIGNALS:
|
||||||
void requestUninstall(const QModelIndex& index);
|
void requestUninstall(const QModelIndex& index);
|
||||||
|
|
||||||
void cancelDownload(const QModelIndex& index);
|
void cancelDownload(const QModelIndex& index);
|
||||||
|
|
||||||
|
void showPreviews(const QModelIndex& index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QRect leftCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const;
|
QRect leftCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const;
|
||||||
QRect rightCycleArrowRect(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 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;
|
void drawRating(QPainter* painter, QString label, const QRect& box, int value) const;
|
||||||
|
|
||||||
QListView* m_view;
|
QListView* m_view;
|
||||||
QPixmap m_leftArrowIcon,
|
QPixmap m_leftArrowIcon,
|
||||||
m_rightArrowIcon;
|
m_rightArrowIcon,
|
||||||
|
m_openPreviewsIcon;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -40,28 +40,18 @@
|
||||||
// FlightGear
|
// FlightGear
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
|
|
||||||
|
|
||||||
const int STANDARD_THUMBNAIL_HEIGHT = 128;
|
const int STANDARD_THUMBNAIL_HEIGHT = 128;
|
||||||
const int STANDARD_THUMBNAIL_WIDTH = 172;
|
const int STANDARD_THUMBNAIL_WIDTH = 172;
|
||||||
|
static quint32 CACHE_VERSION = 7;
|
||||||
|
|
||||||
using namespace simgear::pkg;
|
using namespace simgear::pkg;
|
||||||
|
|
||||||
AircraftItem::AircraftItem() :
|
AircraftItem::AircraftItem()
|
||||||
excluded(false),
|
|
||||||
usesHeliports(false),
|
|
||||||
usesSeaports(false)
|
|
||||||
{
|
{
|
||||||
// oh for C++11 initialisers
|
|
||||||
for (int i=0; i<4; ++i) ratings[i] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AircraftItem::AircraftItem(QDir dir, QString filePath) :
|
AircraftItem::AircraftItem(QDir dir, QString filePath)
|
||||||
excluded(false),
|
|
||||||
usesHeliports(false),
|
|
||||||
usesSeaports(false)
|
|
||||||
{
|
{
|
||||||
for (int i=0; i<4; ++i) ratings[i] = 0;
|
|
||||||
|
|
||||||
SGPropertyNode root;
|
SGPropertyNode root;
|
||||||
readProperties(filePath.toStdString(), &root);
|
readProperties(filePath.toStdString(), &root);
|
||||||
|
|
||||||
|
@ -97,6 +87,12 @@ AircraftItem::AircraftItem(QDir dir, QString filePath) :
|
||||||
|
|
||||||
if (sim->hasChild("variant-of")) {
|
if (sim->hasChild("variant-of")) {
|
||||||
variantOf = sim->getStringValue("variant-of");
|
variantOf = sim->getStringValue("variant-of");
|
||||||
|
} else {
|
||||||
|
isPrimary = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sim->hasChild("primary-set")) {
|
||||||
|
isPrimary = sim->getBoolValue("primary-set");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sim->hasChild("tags")) {
|
if (sim->hasChild("tags")) {
|
||||||
|
@ -113,6 +109,22 @@ AircraftItem::AircraftItem(QDir dir, QString filePath) :
|
||||||
}
|
}
|
||||||
} // of tags iteration
|
} // of tags iteration
|
||||||
} // of set-xml has tags
|
} // 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
|
QString AircraftItem::baseName() const
|
||||||
|
@ -129,8 +141,10 @@ void AircraftItem::fromDataStream(QDataStream& ds)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ds >> description >> longDescription >> authors >> variantOf;
|
ds >> description >> longDescription >> authors >> variantOf >> isPrimary;
|
||||||
for (int i=0; i<4; ++i) ds >> ratings[i];
|
for (int i=0; i<4; ++i) ds >> ratings[i];
|
||||||
|
ds >> previews;
|
||||||
|
ds >> thumbnailPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AircraftItem::toDataStream(QDataStream& ds) const
|
void AircraftItem::toDataStream(QDataStream& ds) const
|
||||||
|
@ -140,8 +154,10 @@ void AircraftItem::toDataStream(QDataStream& ds) const
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ds << description << longDescription << authors << variantOf;
|
ds << description << longDescription << authors << variantOf << isPrimary;
|
||||||
for (int i=0; i<4; ++i) ds << ratings[i];
|
for (int i=0; i<4; ++i) ds << ratings[i];
|
||||||
|
ds << previews;
|
||||||
|
ds << thumbnailPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap AircraftItem::thumbnail(bool loadIfRequired) const
|
QPixmap AircraftItem::thumbnail(bool loadIfRequired) const
|
||||||
|
@ -149,8 +165,8 @@ QPixmap AircraftItem::thumbnail(bool loadIfRequired) const
|
||||||
if (m_thumbnail.isNull() && loadIfRequired) {
|
if (m_thumbnail.isNull() && loadIfRequired) {
|
||||||
QFileInfo info(path);
|
QFileInfo info(path);
|
||||||
QDir dir = info.dir();
|
QDir dir = info.dir();
|
||||||
if (dir.exists("thumbnail.jpg")) {
|
if (dir.exists(thumbnailPath)) {
|
||||||
m_thumbnail.load(dir.filePath("thumbnail.jpg"));
|
m_thumbnail.load(dir.filePath(thumbnailPath));
|
||||||
// resize to the standard size
|
// resize to the standard size
|
||||||
if (m_thumbnail.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
if (m_thumbnail.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
||||||
m_thumbnail = m_thumbnail.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT, Qt::SmoothTransformation);
|
m_thumbnail = m_thumbnail.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT, Qt::SmoothTransformation);
|
||||||
|
@ -161,9 +177,6 @@ QPixmap AircraftItem::thumbnail(bool loadIfRequired) const
|
||||||
return m_thumbnail;
|
return m_thumbnail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static quint32 CACHE_VERSION = 5;
|
|
||||||
|
|
||||||
class AircraftScanThread : public QThread
|
class AircraftScanThread : public QThread
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -284,7 +297,7 @@ private:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->variantOf.isNull()) {
|
if (item->isPrimary) {
|
||||||
baseAircraft.insert(item->baseName(), item);
|
baseAircraft.insert(item->baseName(), item);
|
||||||
} else {
|
} else {
|
||||||
variants.append(item);
|
variants.append(item);
|
||||||
|
@ -402,14 +415,22 @@ protected:
|
||||||
if (pix.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
if (pix.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
||||||
pix = pix.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT, Qt::SmoothTransformation);
|
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
|
m_model->m_downloadedPixmapCache.insert(QString::fromStdString(aThumbnailUrl), pix);
|
||||||
// structure.
|
|
||||||
|
// notify any affected items. Linear scan here avoids another map/dict structure.
|
||||||
for (auto pkg : m_model->m_packages) {
|
for (auto pkg : m_model->m_packages) {
|
||||||
const string_list& urls(pkg->thumbnailUrls());
|
const int variantCount = pkg->variants().size();
|
||||||
auto cit = std::find(urls.begin(), urls.end(), aThumbnailUrl);
|
bool notifyChanged = false;
|
||||||
if (cit != urls.end()) {
|
|
||||||
|
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);
|
QModelIndex mi = indexForPackage(pkg);
|
||||||
m_model->dataChanged(mi, mi);
|
m_model->dataChanged(mi, mi);
|
||||||
}
|
}
|
||||||
|
@ -432,7 +453,7 @@ private:
|
||||||
AircraftItemModel* m_model;
|
AircraftItemModel* m_model;
|
||||||
};
|
};
|
||||||
|
|
||||||
AircraftItemModel::AircraftItemModel(QObject* pr ) :
|
AircraftItemModel::AircraftItemModel(QObject* pr) :
|
||||||
QAbstractListModel(pr)
|
QAbstractListModel(pr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -593,10 +614,6 @@ QVariant AircraftItemModel::data(const QModelIndex& index, int role) const
|
||||||
return m_delegateStates.at(row).variant;
|
return m_delegateStates.at(row).variant;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role == AircraftCurrentThumbnailRole) {
|
|
||||||
return m_delegateStates.at(row).thumbnail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (row >= m_items.size()) {
|
if (row >= m_items.size()) {
|
||||||
quint32 packageIndex = row - m_items.size();
|
quint32 packageIndex = row - m_items.size();
|
||||||
const PackageRef& pkg(m_packages[packageIndex]);
|
const PackageRef& pkg(m_packages[packageIndex]);
|
||||||
|
@ -623,20 +640,7 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
|
||||||
return item->variants.count();
|
return item->variants.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role == AircraftThumbnailCountRole) {
|
if (role >= AircraftVariantDescriptionRole) {
|
||||||
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)) {
|
|
||||||
int variantIndex = role - AircraftVariantDescriptionRole;
|
int variantIndex = role - AircraftVariantDescriptionRole;
|
||||||
return item->variants.at(variantIndex)->description;
|
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 (role == Qt::DisplayRole) {
|
||||||
if (item->description.isEmpty()) {
|
if (item->description.isEmpty()) {
|
||||||
return tr("Missing description for: %1").arg(item->baseName());
|
return tr("Missing description for: %1").arg(item->baseName());
|
||||||
|
@ -662,7 +674,13 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
|
||||||
return item->authors;
|
return item->authors;
|
||||||
} else if ((role >= AircraftRatingRole) && (role < AircraftVariantDescriptionRole)) {
|
} else if ((role >= AircraftRatingRole) && (role < AircraftVariantDescriptionRole)) {
|
||||||
return item->ratings[role - AircraftRatingRole];
|
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();
|
return item->thumbnail();
|
||||||
} else if (role == AircraftPackageIdRole) {
|
} else if (role == AircraftPackageIdRole) {
|
||||||
// can we fake an ID? otherwise fall through to a null variant
|
// 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
|
QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, const DelegateState& state, int role) const
|
||||||
{
|
{
|
||||||
if (role == Qt::DecorationRole) {
|
if (role == Qt::DecorationRole) {
|
||||||
role = AircraftThumbnailRole; // use first thumbnail
|
role = AircraftThumbnailRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((role >= AircraftVariantDescriptionRole) && (role < AircraftThumbnailRole)) {
|
if (role >= AircraftVariantDescriptionRole) {
|
||||||
int variantIndex = role - AircraftVariantDescriptionRole;
|
int variantIndex = role - AircraftVariantDescriptionRole;
|
||||||
QString desc = QString::fromStdString(item->nameForVariant(variantIndex));
|
QString desc = QString::fromStdString(item->nameForVariant(variantIndex));
|
||||||
if (desc.isEmpty()) {
|
if (desc.isEmpty()) {
|
||||||
|
@ -743,11 +761,10 @@ QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, const Delega
|
||||||
if (pm.isNull())
|
if (pm.isNull())
|
||||||
return QSize(STANDARD_THUMBNAIL_WIDTH, STANDARD_THUMBNAIL_HEIGHT);
|
return QSize(STANDARD_THUMBNAIL_WIDTH, STANDARD_THUMBNAIL_HEIGHT);
|
||||||
return pm.size();
|
return pm.size();
|
||||||
} else if (role >= AircraftThumbnailRole) {
|
} else if (role == AircraftThumbnailRole) {
|
||||||
DelegateState changedState(state);
|
return packageThumbnail(item, state);
|
||||||
// override the current thumbnail as required
|
} else if (role == AircraftPreviewsRole) {
|
||||||
changedState.thumbnail = (role - AircraftThumbnailRole);
|
return packagePreviews(item, state);
|
||||||
return packageThumbnail(item, changedState);
|
|
||||||
} else if (role == AircraftAuthorsRole) {
|
} else if (role == AircraftAuthorsRole) {
|
||||||
std::string authors = item->getLocalisedProp("author", state.variant);
|
std::string authors = item->getLocalisedProp("author", state.variant);
|
||||||
if (!authors.empty()) {
|
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
|
QVariant AircraftItemModel::packageThumbnail(PackageRef p, const DelegateState& ds, bool download) const
|
||||||
{
|
{
|
||||||
const string_list& thumbnails(p->thumbnailUrls());
|
const Package::Thumbnail& thumb(p->thumbnailForVariant(ds.variant));
|
||||||
if (ds.thumbnail >= static_cast<int>(thumbnails.size())) {
|
if (thumb.url.empty()) {
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string thumbnailUrl = thumbnails.at(ds.thumbnail);
|
QString urlQString(QString::fromStdString(thumb.url));
|
||||||
QString urlQString(QString::fromStdString(thumbnailUrl));
|
if (m_downloadedPixmapCache.contains(urlQString)) {
|
||||||
if (m_thumbnailPixmapCache.contains(urlQString)) {
|
|
||||||
// cache hit, easy
|
// 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
|
// check the on-disk store.
|
||||||
// results of thumbnailUrls and thumbnails corresponding
|
|
||||||
InstallRef ex = p->existingInstall();
|
InstallRef ex = p->existingInstall();
|
||||||
if (ex.valid()) {
|
if (ex.valid()) {
|
||||||
const string_list& thumbNames(p->thumbnails());
|
SGPath thumbPath = ex->path() / thumb.path;
|
||||||
if (!thumbNames.empty()) {
|
if (thumbPath.exists()) {
|
||||||
SGPath path(ex->path());
|
|
||||||
path.append(p->thumbnails()[ds.thumbnail]);
|
|
||||||
if (path.exists()) {
|
|
||||||
QPixmap pix;
|
QPixmap pix;
|
||||||
pix.load(QString::fromStdString(path.utf8Str()));
|
pix.load(QString::fromStdString(thumbPath.utf8Str()));
|
||||||
// resize to the standard size
|
// resize to the standard size
|
||||||
if (pix.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
if (pix.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
||||||
pix = pix.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT);
|
pix = pix.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT);
|
||||||
}
|
}
|
||||||
m_thumbnailPixmapCache[urlQString] = pix;
|
m_downloadedPixmapCache[urlQString] = pix;
|
||||||
return pix;
|
return pix;
|
||||||
}
|
}
|
||||||
} // of have thumbnail file names
|
|
||||||
} // of have existing install
|
} // of have existing install
|
||||||
|
|
||||||
if (download) {
|
if (download) {
|
||||||
m_packageRoot->requestThumbnailData(thumbnailUrl);
|
m_packageRoot->requestThumbnailData(thumb.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
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)
|
bool AircraftItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||||
{
|
{
|
||||||
int row = index.row();
|
int row = index.row();
|
||||||
|
@ -831,16 +871,6 @@ bool AircraftItemModel::setData(const QModelIndex &index, const QVariant &value,
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,6 @@ const int AircraftPathRole = Qt::UserRole + 1;
|
||||||
const int AircraftAuthorsRole = Qt::UserRole + 2;
|
const int AircraftAuthorsRole = Qt::UserRole + 2;
|
||||||
const int AircraftVariantRole = Qt::UserRole + 3;
|
const int AircraftVariantRole = Qt::UserRole + 3;
|
||||||
const int AircraftVariantCountRole = Qt::UserRole + 4;
|
const int AircraftVariantCountRole = Qt::UserRole + 4;
|
||||||
const int AircraftThumbnailCountRole = Qt::UserRole + 5;
|
|
||||||
const int AircraftPackageIdRole = Qt::UserRole + 6;
|
const int AircraftPackageIdRole = Qt::UserRole + 6;
|
||||||
const int AircraftPackageStatusRole = Qt::UserRole + 7;
|
const int AircraftPackageStatusRole = Qt::UserRole + 7;
|
||||||
const int AircraftPackageProgressRole = Qt::UserRole + 8;
|
const int AircraftPackageProgressRole = Qt::UserRole + 8;
|
||||||
|
@ -51,12 +50,12 @@ const int AircraftURIRole = Qt::UserRole + 14;
|
||||||
const int AircraftThumbnailSizeRole = Qt::UserRole + 15;
|
const int AircraftThumbnailSizeRole = Qt::UserRole + 15;
|
||||||
const int AircraftIsHelicopterRole = Qt::UserRole + 16;
|
const int AircraftIsHelicopterRole = Qt::UserRole + 16;
|
||||||
const int AircraftIsSeaplaneRole = Qt::UserRole + 17;
|
const int AircraftIsSeaplaneRole = Qt::UserRole + 17;
|
||||||
const int AircraftCurrentThumbnailRole = Qt::UserRole + 18;
|
|
||||||
const int AircraftPackageRefRole = Qt::UserRole + 19;
|
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 AircraftRatingRole = Qt::UserRole + 100;
|
||||||
const int AircraftVariantDescriptionRole = Qt::UserRole + 200;
|
const int AircraftVariantDescriptionRole = Qt::UserRole + 200;
|
||||||
const int AircraftThumbnailRole = Qt::UserRole + 300;
|
|
||||||
|
|
||||||
class AircraftScanThread;
|
class AircraftScanThread;
|
||||||
class QDataStream;
|
class QDataStream;
|
||||||
|
@ -81,17 +80,20 @@ struct AircraftItem
|
||||||
|
|
||||||
QPixmap thumbnail(bool loadIfRequired = true) const;
|
QPixmap thumbnail(bool loadIfRequired = true) const;
|
||||||
|
|
||||||
bool excluded;
|
bool excluded = false;
|
||||||
QString path;
|
QString path;
|
||||||
QString description;
|
QString description;
|
||||||
QString longDescription;
|
QString longDescription;
|
||||||
QString authors;
|
QString authors;
|
||||||
int ratings[4];
|
int ratings[4] = {0, 0, 0, 0};
|
||||||
QString variantOf;
|
QString variantOf;
|
||||||
QDateTime pathModTime;
|
QDateTime pathModTime;
|
||||||
QList<AircraftItemPtr> variants;
|
QList<AircraftItemPtr> variants;
|
||||||
bool usesHeliports;
|
bool usesHeliports = false;
|
||||||
bool usesSeaports;
|
bool usesSeaports = false;
|
||||||
|
QList<QUrl> previews;
|
||||||
|
bool isPrimary = false;
|
||||||
|
QString thumbnailPath;
|
||||||
private:
|
private:
|
||||||
mutable QPixmap m_thumbnail;
|
mutable QPixmap m_thumbnail;
|
||||||
};
|
};
|
||||||
|
@ -199,6 +201,8 @@ private:
|
||||||
QVariant packageThumbnail(simgear::pkg::PackageRef p,
|
QVariant packageThumbnail(simgear::pkg::PackageRef p,
|
||||||
const DelegateState& state, bool download = true) const;
|
const DelegateState& state, bool download = true) const;
|
||||||
|
|
||||||
|
QVariant packagePreviews(simgear::pkg::PackageRef p, const DelegateState &ds) const;
|
||||||
|
|
||||||
void abandonCurrentScan();
|
void abandonCurrentScan();
|
||||||
void refreshPackages();
|
void refreshPackages();
|
||||||
|
|
||||||
|
@ -217,7 +221,7 @@ private:
|
||||||
simgear::pkg::RootRef m_packageRoot;
|
simgear::pkg::RootRef m_packageRoot;
|
||||||
simgear::pkg::PackageList m_packages;
|
simgear::pkg::PackageList m_packages;
|
||||||
|
|
||||||
mutable QHash<QString, QPixmap> m_thumbnailPixmapCache;
|
mutable QHash<QString, QPixmap> m_downloadedPixmapCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // of FG_GUI_AIRCRAFT_MODEL
|
#endif // of FG_GUI_AIRCRAFT_MODEL
|
||||||
|
|
|
@ -189,7 +189,8 @@ void AirportDiagram::addRunway(FGRunwayRef rwy)
|
||||||
r.runway = rwy;
|
r.runway = rwy;
|
||||||
m_runways.append(r);
|
m_runways.append(r);
|
||||||
|
|
||||||
recomputeBounds(false);
|
extendBounds(r.p1);
|
||||||
|
extendBounds(r.p2);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +225,7 @@ void AirportDiagram::addParking(FGParkingRef park)
|
||||||
{
|
{
|
||||||
ParkingData pd = { project(park->geod()), park };
|
ParkingData pd = { project(park->geod()), park };
|
||||||
m_parking.push_back(pd);
|
m_parking.push_back(pd);
|
||||||
recomputeBounds(false);
|
extendBounds(pd.pt);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +233,7 @@ void AirportDiagram::addHelipad(FGHelipadRef pad)
|
||||||
{
|
{
|
||||||
HelipadData pd = { project(pad->geod()), pad };
|
HelipadData pd = { project(pad->geod()), pad };
|
||||||
m_helipads.push_back(pd);
|
m_helipads.push_back(pd);
|
||||||
recomputeBounds(false);
|
extendBounds(pd.pt);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -587,6 +587,17 @@ void BaseDiagram::doComputeBounds()
|
||||||
|
|
||||||
void BaseDiagram::extendBounds(const QPointF& p)
|
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);
|
extendRect(m_bounds, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,11 +117,13 @@ if (HAVE_QT)
|
||||||
InstallSceneryDialog.cxx
|
InstallSceneryDialog.cxx
|
||||||
EditCustomMPServerDialog.cxx
|
EditCustomMPServerDialog.cxx
|
||||||
EditCustomMPServerDialog.hxx
|
EditCustomMPServerDialog.hxx
|
||||||
|
previewwindow.cpp
|
||||||
|
previewwindow.h
|
||||||
${uic_sources}
|
${uic_sources}
|
||||||
${qrc_sources})
|
${qrc_sources})
|
||||||
|
|
||||||
set_property(TARGET fglauncher PROPERTY AUTOMOC ON)
|
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)
|
target_include_directories(fglauncher PRIVATE ${PROJECT_BINARY_DIR}/src/GUI)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="summaryTab">
|
<widget class="QWidget" name="summaryTab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
|
@ -698,4 +698,4 @@
|
||||||
<include location="resources.qrc"/>
|
<include location="resources.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
|
|
@ -536,7 +536,7 @@ void LocationWidget::setLocationProperties()
|
||||||
QStringList props = QStringList() << "vor-id" << "fix" << "ndb-id" <<
|
QStringList props = QStringList() << "vor-id" << "fix" << "ndb-id" <<
|
||||||
"runway-requested" << "navaid-id" << "offset-azimuth-deg" <<
|
"runway-requested" << "navaid-id" << "offset-azimuth-deg" <<
|
||||||
"offset-distance-nm" << "glideslope-deg" <<
|
"offset-distance-nm" << "glideslope-deg" <<
|
||||||
"speed-set" << "on-ground" << "airspeed-kt" << "heading-deg" <<
|
"speed-set" << "on-ground" << "airspeed-kt" <<
|
||||||
"airport-id" << "runway" << "parkpos";
|
"airport-id" << "runway" << "parkpos";
|
||||||
|
|
||||||
Q_FOREACH(QString s, props) {
|
Q_FOREACH(QString s, props) {
|
||||||
|
@ -556,10 +556,10 @@ void LocationWidget::setLocationProperties()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fgSetDouble("/sim/presets/latitude-deg", -9999.0);
|
fgSetDouble("/sim/presets/latitude-deg", 9999.0);
|
||||||
fgSetDouble("/sim/presets/longitude-deg", -9999.0);
|
fgSetDouble("/sim/presets/longitude-deg", 9999.0);
|
||||||
fgSetDouble("/sim/presets/altitude-ft", -9999.0);
|
fgSetDouble("/sim/presets/altitude-ft", -9999.0);
|
||||||
|
fgSetDouble("/sim/presets/heading-deg", 9999.0);
|
||||||
|
|
||||||
if (!m_location) {
|
if (!m_location) {
|
||||||
return;
|
return;
|
||||||
|
@ -569,6 +569,7 @@ void LocationWidget::setLocationProperties()
|
||||||
FGAirport* apt = static_cast<FGAirport*>(m_location.ptr());
|
FGAirport* apt = static_cast<FGAirport*>(m_location.ptr());
|
||||||
fgSetString("/sim/presets/airport-id", apt->ident());
|
fgSetString("/sim/presets/airport-id", apt->ident());
|
||||||
fgSetBool("/sim/presets/on-ground", true);
|
fgSetBool("/sim/presets/on-ground", true);
|
||||||
|
fgSetBool("/sim/presets/airport-requested", true);
|
||||||
|
|
||||||
if (m_ui->runwayRadio->isChecked()) {
|
if (m_ui->runwayRadio->isChecked()) {
|
||||||
if (apt->type() == FGPositioned::AIRPORT) {
|
if (apt->type() == FGPositioned::AIRPORT) {
|
||||||
|
|
|
@ -105,15 +105,24 @@ void AddOnsPage::onAddSceneryPath()
|
||||||
// validation
|
// validation
|
||||||
|
|
||||||
SGPath p(path.toStdString());
|
SGPath p(path.toStdString());
|
||||||
SGPath objectsPath = p / "Objects";
|
bool isValid = false;
|
||||||
SGPath terrainPath = p / "Terrain";
|
|
||||||
|
|
||||||
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;
|
QMessageBox mb;
|
||||||
mb.setText(QString("The folder '%1' doesn't appear to contain scenery - add anyway?").arg(path));
|
mb.setText(QString("The folder '%1' doesn't appear to contain scenery - add anyway?").arg(path));
|
||||||
mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||||
mb.setDefaultButton(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();
|
mb.exec();
|
||||||
|
|
||||||
if (mb.result() == QMessageBox::No) {
|
if (mb.result() == QMessageBox::No) {
|
||||||
|
@ -124,11 +133,6 @@ void AddOnsPage::onAddSceneryPath()
|
||||||
m_ui->sceneryPathsList->addItem(path);
|
m_ui->sceneryPathsList->addItem(path);
|
||||||
saveSceneryPaths();
|
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()
|
void AddOnsPage::onRemoveSceneryPath()
|
||||||
|
@ -175,11 +179,8 @@ void AddOnsPage::onAddAircraftPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
saveAircraftPaths();
|
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()
|
void AddOnsPage::onRemoveAircraftPath()
|
||||||
|
@ -187,6 +188,7 @@ void AddOnsPage::onRemoveAircraftPath()
|
||||||
if (m_ui->aircraftPathsList->currentItem()) {
|
if (m_ui->aircraftPathsList->currentItem()) {
|
||||||
delete m_ui->aircraftPathsList->currentItem();
|
delete m_ui->aircraftPathsList->currentItem();
|
||||||
saveAircraftPaths();
|
saveAircraftPaths();
|
||||||
|
emit aircraftPathsChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,13 +239,13 @@ void AddOnsPage::onAddCatalog()
|
||||||
|
|
||||||
void AddOnsPage::onAddDefaultCatalog()
|
void AddOnsPage::onAddDefaultCatalog()
|
||||||
{
|
{
|
||||||
addDefaultCatalog(this);
|
addDefaultCatalog(this, false /* not silent */);
|
||||||
|
|
||||||
m_catalogsModel->refresh();
|
m_catalogsModel->refresh();
|
||||||
updateUi();
|
updateUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddOnsPage::addDefaultCatalog(QWidget* pr)
|
void AddOnsPage::addDefaultCatalog(QWidget* pr, bool silent)
|
||||||
{
|
{
|
||||||
// check it's not a duplicate somehow
|
// check it's not a duplicate somehow
|
||||||
FGHTTPClient* http = globals->get_subsystem<FGHTTPClient>();
|
FGHTTPClient* http = globals->get_subsystem<FGHTTPClient>();
|
||||||
|
@ -252,6 +254,9 @@ void AddOnsPage::addDefaultCatalog(QWidget* pr)
|
||||||
|
|
||||||
QScopedPointer<AddCatalogDialog> dlg(new AddCatalogDialog(pr, globals->packageRoot()));
|
QScopedPointer<AddCatalogDialog> dlg(new AddCatalogDialog(pr, globals->packageRoot()));
|
||||||
QUrl url(QString::fromStdString(http->getDefaultCatalogUrl()));
|
QUrl url(QString::fromStdString(http->getDefaultCatalogUrl()));
|
||||||
|
if (silent) {
|
||||||
|
dlg->setNonInteractiveMode();
|
||||||
|
}
|
||||||
dlg->setUrlAndDownload(url);
|
dlg->setUrlAndDownload(url);
|
||||||
dlg->exec();
|
dlg->exec();
|
||||||
|
|
||||||
|
|
|
@ -20,11 +20,12 @@ public:
|
||||||
explicit AddOnsPage(QWidget *parent, simgear::pkg::RootRef root);
|
explicit AddOnsPage(QWidget *parent, simgear::pkg::RootRef root);
|
||||||
~AddOnsPage();
|
~AddOnsPage();
|
||||||
|
|
||||||
static void addDefaultCatalog(QWidget* pr);
|
static void addDefaultCatalog(QWidget* pr, bool silent);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void downloadDirChanged();
|
void downloadDirChanged();
|
||||||
void sceneryPathsChanged();
|
void sceneryPathsChanged();
|
||||||
|
void aircraftPathsChanged();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onAddSceneryPath();
|
void onAddSceneryPath();
|
||||||
|
|
|
@ -69,6 +69,7 @@
|
||||||
#include "AircraftModel.hxx"
|
#include "AircraftModel.hxx"
|
||||||
#include "PathsDialog.hxx"
|
#include "PathsDialog.hxx"
|
||||||
#include "EditCustomMPServerDialog.hxx"
|
#include "EditCustomMPServerDialog.hxx"
|
||||||
|
#include "previewwindow.h"
|
||||||
|
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
|
@ -696,6 +697,20 @@ bool runLauncherDialog()
|
||||||
// try to initialise various Cocoa structures.
|
// try to initialise various Cocoa structures.
|
||||||
flightgear::WindowBuilder::setPoseAsStandaloneApp(false);
|
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;
|
QtLauncher dlg;
|
||||||
dlg.show();
|
dlg.show();
|
||||||
|
|
||||||
|
@ -840,6 +855,8 @@ QtLauncher::QtLauncher() :
|
||||||
this, &QtLauncher::onRequestPackageUninstall);
|
this, &QtLauncher::onRequestPackageUninstall);
|
||||||
connect(delegate, &AircraftItemDelegate::cancelDownload,
|
connect(delegate, &AircraftItemDelegate::cancelDownload,
|
||||||
this, &QtLauncher::onCancelDownload);
|
this, &QtLauncher::onCancelDownload);
|
||||||
|
connect(delegate, &AircraftItemDelegate::showPreviews,
|
||||||
|
this, &QtLauncher::onShowPreviews);
|
||||||
|
|
||||||
connect(m_aircraftModel, &AircraftItemModel::aircraftInstallCompleted,
|
connect(m_aircraftModel, &AircraftItemModel::aircraftInstallCompleted,
|
||||||
this, &QtLauncher::onAircraftInstalledCompleted);
|
this, &QtLauncher::onAircraftInstalledCompleted);
|
||||||
|
@ -856,6 +873,8 @@ QtLauncher::QtLauncher() :
|
||||||
this, &QtLauncher::onDownloadDirChanged);
|
this, &QtLauncher::onDownloadDirChanged);
|
||||||
connect(addOnsPage, &AddOnsPage::sceneryPathsChanged,
|
connect(addOnsPage, &AddOnsPage::sceneryPathsChanged,
|
||||||
this, &QtLauncher::setSceneryPaths);
|
this, &QtLauncher::setSceneryPaths);
|
||||||
|
connect(addOnsPage, &AddOnsPage::aircraftPathsChanged,
|
||||||
|
this, &QtLauncher::onAircraftPathsChanged);
|
||||||
|
|
||||||
m_ui->tabWidget->addTab(addOnsPage, tr("Add-ons"));
|
m_ui->tabWidget->addTab(addOnsPage, tr("Add-ons"));
|
||||||
// after any kind of reset, try to restore selection and scroll
|
// after any kind of reset, try to restore selection and scroll
|
||||||
|
@ -1202,6 +1221,11 @@ void QtLauncher::onRun()
|
||||||
if (a.arg.startsWith("prop:")) {
|
if (a.arg.startsWith("prop:")) {
|
||||||
QString v = a.arg.mid(5) + "=" + a.value;
|
QString v = a.arg.mid(5) + "=" + a.value;
|
||||||
opt->addOption("prop", v.toStdString());
|
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 {
|
} else {
|
||||||
opt->addOption(a.arg.toStdString(), a.value.toStdString());
|
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)
|
void QtLauncher::onCancelDownload(const QModelIndex& index)
|
||||||
{
|
{
|
||||||
QString pkg = index.data(AircraftPackageIdRole).toString();
|
QString pkg = index.data(AircraftPackageIdRole).toString();
|
||||||
|
@ -1621,8 +1653,9 @@ void QtLauncher::onDownloadDirChanged()
|
||||||
|
|
||||||
globals->get_subsystem<FGHTTPClient>()->init();
|
globals->get_subsystem<FGHTTPClient>()->init();
|
||||||
|
|
||||||
QSettings settings;
|
|
||||||
// re-scan the aircraft list
|
// re-scan the aircraft list
|
||||||
|
QSettings settings;
|
||||||
|
|
||||||
m_aircraftModel->setPackageRoot(globals->packageRoot());
|
m_aircraftModel->setPackageRoot(globals->packageRoot());
|
||||||
m_aircraftModel->setPaths(settings.value("aircraft-paths").toStringList());
|
m_aircraftModel->setPaths(settings.value("aircraft-paths").toStringList());
|
||||||
m_aircraftModel->scanDirs();
|
m_aircraftModel->scanDirs();
|
||||||
|
@ -1633,6 +1666,13 @@ void QtLauncher::onDownloadDirChanged()
|
||||||
setSceneryPaths();
|
setSceneryPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QtLauncher::onAircraftPathsChanged()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
m_aircraftModel->setPaths(settings.value("aircraft-paths").toStringList());
|
||||||
|
m_aircraftModel->scanDirs();
|
||||||
|
}
|
||||||
|
|
||||||
bool QtLauncher::shouldShowOfficialCatalogMessage() const
|
bool QtLauncher::shouldShowOfficialCatalogMessage() const
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
|
@ -1663,7 +1703,7 @@ void QtLauncher::onOfficialCatalogMessageLink(QUrl link)
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.setValue("hide-official-catalog-message", true);
|
settings.setValue("hide-official-catalog-message", true);
|
||||||
} else if (s == "action:add-official") {
|
} else if (s == "action:add-official") {
|
||||||
AddOnsPage::addDefaultCatalog(this);
|
AddOnsPage::addDefaultCatalog(this, false /* not silent */);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkOfficialCatalogMessage();
|
checkOfficialCatalogMessage();
|
||||||
|
|
|
@ -75,7 +75,7 @@ private slots:
|
||||||
void onAircraftSelected(const QModelIndex& index);
|
void onAircraftSelected(const QModelIndex& index);
|
||||||
void onRequestPackageInstall(const QModelIndex& index);
|
void onRequestPackageInstall(const QModelIndex& index);
|
||||||
void onRequestPackageUninstall(const QModelIndex& index);
|
void onRequestPackageUninstall(const QModelIndex& index);
|
||||||
|
void onShowPreviews(const QModelIndex& index);
|
||||||
void onCancelDownload(const QModelIndex& index);
|
void onCancelDownload(const QModelIndex& index);
|
||||||
|
|
||||||
void onPopupAircraftHistory();
|
void onPopupAircraftHistory();
|
||||||
|
@ -109,6 +109,7 @@ private slots:
|
||||||
|
|
||||||
void onPackagesNeedUpdate(bool yes);
|
void onPackagesNeedUpdate(bool yes);
|
||||||
|
|
||||||
|
void onAircraftPathsChanged();
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,13 +17,13 @@ FGMenuBar::~FGMenuBar ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
std::string
|
||||||
FGMenuBar::getLocalizedLabel(SGPropertyNode* node)
|
FGMenuBar::getLocalizedLabel(SGPropertyNode* node)
|
||||||
{
|
{
|
||||||
const char* name = node->getStringValue("name", 0);
|
const char* name = node->getStringValue("name", 0);
|
||||||
|
|
||||||
const char* translated = globals->get_locale()->getLocalizedString(name, "menu");
|
std::string translated = globals->get_locale()->getLocalizedString(name, "menu");
|
||||||
if (translated)
|
if (!translated.empty())
|
||||||
return translated;
|
return translated;
|
||||||
|
|
||||||
// return default with fallback to name
|
// return default with fallback to name
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#ifndef __MENUBAR_HXX
|
#ifndef __MENUBAR_HXX
|
||||||
#define __MENUBAR_HXX 1
|
#define __MENUBAR_HXX 1
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
class SGPropertyNode;
|
class SGPropertyNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,7 +53,7 @@ public:
|
||||||
* Take care of mapping it to the appropriate translation, if available.
|
* Take care of mapping it to the appropriate translation, if available.
|
||||||
* Returns an UTF-8 encoded string.
|
* 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
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
Loading…
Add table
Reference in a new issue