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(-DNDEBUG)
|
||||
add_library(fgsqlite3 sqlite3.c)
|
||||
set_target_properties(fgsqlite3 PROPERTIES COMPILE_FLAGS "-fno-fast-math")
|
||||
set_target_properties(fgsqlite3 PROPERTIES COMPILE_FLAGS "-fpic -fno-fast-math")
|
||||
|
|
|
@ -25,6 +25,13 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
|||
"MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
if(NOT FG_BUILD_TYPE)
|
||||
message(STATUS "Setting build type to 'Dev' as none was specified.")
|
||||
set(FG_BUILD_TYPE Dev CACHE STRING "Choose the FlightGear build type" FORCE)
|
||||
# Set the possible values of build type for cmake-gui
|
||||
set_property(CACHE FG_BUILD_TYPE PROPERTY STRINGS "Dev" "Nightly" "Release")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks")
|
||||
# when building, don't use the install RPATH already
|
||||
|
@ -176,8 +183,6 @@ option(SYSTEM_SPEEX "Set to ON to build IAXClient with the system's speex a
|
|||
option(SYSTEM_GSM "Set to ON to build IAXClient with the system's GSM library" ${SYSTEM_GSM_DEFAULT})
|
||||
option(SYSTEM_FLITE "Set to ON to build Flightgear with the system's Flite library" ${SYSTEM_FLITE_DEFAULT})
|
||||
option(SYSTEM_HTS_ENGINE "Set to ON to build Flightgear with the system's HTS Engine library" ${SYSTEM_HTS_ENGINE_DEFAULT})
|
||||
option(FG_NIGHTLY "Set to ON to mark this as a nightly build" OFF)
|
||||
option(ENABLE_DEV_WARNINGS "Set to ON to include developer-warnings" OFF)
|
||||
|
||||
# additional utilities
|
||||
option(ENABLE_FGELEV "Set to ON to build the fgelev application (default)" ON)
|
||||
|
@ -194,6 +199,7 @@ option(ENABLE_FLITE "Set to ON to build the Flite text-to-speech module" ON
|
|||
option(ENABLE_QT "Set to ON to build the internal Qt launcher" ON)
|
||||
option(ENABLE_TRAFFIC "Set to ON to build the external traffic generator modules" ON)
|
||||
option(ENABLE_FGQCANVAS "Set to ON to build the Qt-based remote canvas application" OFF)
|
||||
option(ENABLE_DEMCONVERT "Set to ON to build the dem conversion tool (default)" ON)
|
||||
|
||||
include (DetectArch)
|
||||
|
||||
|
@ -305,7 +311,7 @@ endif (USE_DBUS)
|
|||
## Qt5 setup setup
|
||||
if (ENABLE_QT)
|
||||
message(STATUS "Qt launcher enabled, checking for Qt 5.1 / qmake")
|
||||
find_package(Qt5 5.1 COMPONENTS Widgets)
|
||||
find_package(Qt5 5.1 COMPONENTS Widgets Network)
|
||||
if (Qt5Widgets_FOUND)
|
||||
message(STATUS "Will enable Qt launcher GUI")
|
||||
message(STATUS " Qt5Widgets version: ${Qt5Widgets_VERSION_STRING}")
|
||||
|
@ -357,6 +363,24 @@ else()
|
|||
message(STATUS "RTI: DISABLED")
|
||||
endif(ENABLE_RTI)
|
||||
|
||||
if(ENABLE_GDAL)
|
||||
find_package(GDAL 2.0.0 REQUIRED)
|
||||
endif(ENABLE_GDAL)
|
||||
include_directories(${GDAL_INCLUDE_DIR})
|
||||
|
||||
if (ENABLE_OPENMP)
|
||||
find_package(OpenMP)
|
||||
if(OPENMP_FOUND)
|
||||
message(STATUS "OpenMP: ENABLED")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
|
||||
else()
|
||||
message(STATUS "OpenMP: NOT FOUND")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "OpenMP: DISABLED")
|
||||
endif()
|
||||
|
||||
if (ENABLE_SIMD)
|
||||
message(STATUS "SSE/SSE2 support: ENABLED")
|
||||
else()
|
||||
|
@ -485,6 +509,23 @@ configure_file (
|
|||
|
||||
add_subdirectory(3rdparty)
|
||||
add_subdirectory(utils)
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
# enable CTest / make test target
|
||||
message(STATUS "Tests: ENABLED")
|
||||
|
||||
include (Dart)
|
||||
enable_testing()
|
||||
if(WIN32)
|
||||
# tests disabled until shared library export is fixed on Windows
|
||||
message(STATUS "Tests disabled on Windows for the moment")
|
||||
else()
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Tests: DISABLED")
|
||||
endif(ENABLE_TESTS)
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(man)
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <Main/fg_props.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
#include <Scenery/scenery.hxx>
|
||||
#include <Scenery/tilemgr.hxx>
|
||||
#include <Airports/dynamics.hxx>
|
||||
#include <Airports/airport.hxx>
|
||||
#include <Main/util.hxx>
|
||||
|
@ -551,7 +550,7 @@ void FGAIAircraft::getGroundElev(double dt) {
|
|||
}
|
||||
|
||||
double range = 500.0;
|
||||
if (globals->get_tile_mgr()->schedule_scenery(pos, range, 5.0))
|
||||
if (globals->get_scenery()->schedule_scenery(pos, range, 5.0))
|
||||
{
|
||||
double alt;
|
||||
if (getGroundElevationM(SGGeod::fromGeodM(pos, 20000), alt, 0))
|
||||
|
|
|
@ -576,11 +576,9 @@ void FGSubmodelMgr::setData(int id, const string& path, bool serviceable, const
|
|||
sm->pitch_offset = new FGXMLAutopilot::InputValue(*prop_root, b ? *b : n);
|
||||
if (b) old = true;
|
||||
|
||||
#if defined(ENABLE_DEV_WARNINGS)
|
||||
if (old) {
|
||||
SG_LOG(SG_AI, SG_WARN, "Submodels: <*-offset> is deprecated. Use <offsets> instead");
|
||||
SG_LOG(SG_AI, SG_DEV_WARN, "Submodels: <*-offset> is deprecated. Use <offsets> instead");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Randomness
|
||||
|
|
|
@ -36,7 +36,7 @@ static string NO_ATIS("nil");
|
|||
static string EMPTY("");
|
||||
#define SPACE append(1,' ')
|
||||
|
||||
const char * ATCSpeech::getSpokenDigit( int i )
|
||||
std::string ATCSpeech::getSpokenDigit( int i )
|
||||
{
|
||||
string key = "n" + boost::lexical_cast<std::string>( i );
|
||||
return globals->get_locale()->getLocalizedString(key.c_str(), "atc", "" );
|
||||
|
@ -55,7 +55,7 @@ string ATCSpeech::getSpokenNumber( string number )
|
|||
|
||||
string ATCSpeech::getSpokenNumber( int number, bool leadingZero, int digits )
|
||||
{
|
||||
vector<const char *> spokenDigits;
|
||||
string_list spokenDigits;
|
||||
bool negative = false;
|
||||
if( number < 0 ) {
|
||||
negative = true;
|
||||
|
|
|
@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
|
||||
class ATCSpeech {
|
||||
public:
|
||||
static const char * getSpokenDigit( int i );
|
||||
static std::string getSpokenDigit( int i );
|
||||
static std::string getSpokenNumber( std::string number );
|
||||
static std::string getSpokenNumber( int number, bool leadingZero = false, int digits = 1 );
|
||||
static std::string getSpokenAltitude( int altitude );
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include "config.h"
|
||||
|
||||
#include "CommStation.hxx"
|
||||
#include <Airports/airport.hxx>
|
||||
#include <Navaids/NavDataCache.hxx>
|
||||
|
|
|
@ -724,7 +724,7 @@ void FGAirport::validateILSData()
|
|||
|
||||
SGPath path;
|
||||
if (!XMLLoader::findAirportData(ident(), "ils", path)) {
|
||||
return; // no XML tower data
|
||||
return; // no XML ILS data
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -99,7 +99,6 @@ void APTLoader::readAptDatFile(const SGPath &aptdb_file,
|
|||
sg_location(aptdb_file));
|
||||
}
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_INFO, "Opened apt.dat file: '" << apt_dat << "'" );
|
||||
string line;
|
||||
|
||||
unsigned int rowCode = 0; // terminology used in the apt.dat format spec
|
||||
|
|
|
@ -69,7 +69,7 @@ void FGGroundNetXMLLoader::endXML ()
|
|||
for (it = _parkingPushbacks.begin(); it != _parkingPushbacks.end(); ++it) {
|
||||
NodeIndexMap::const_iterator j = _indexMap.find(it->second);
|
||||
if (j == _indexMap.end()) {
|
||||
SG_LOG(SG_NAVAID, SG_WARN, "bad groundnet, no node for index:" << it->first);
|
||||
SG_LOG(SG_NAVAID, SG_DEV_WARN, "bad groundnet, no node for index:" << it->first);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ void FGGroundNetXMLLoader::endXML ()
|
|||
}
|
||||
|
||||
BOOST_FOREACH(FGTaxiNodeRef node, _unreferencedNodes) {
|
||||
SG_LOG(SG_NAVAID, SG_WARN, "unreferenced groundnet node:" << node->ident());
|
||||
SG_LOG(SG_NAVAID, SG_DEV_WARN, "unreferenced groundnet node:" << node->ident());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ void FGGroundNetXMLLoader::startNode(const XMLAttributes &atts)
|
|||
}
|
||||
|
||||
if (_indexMap.find(index) != _indexMap.end()) {
|
||||
SG_LOG(SG_NAVAID, SG_WARN, "duplicate ground-net index:" << index);
|
||||
SG_LOG(SG_NAVAID, SG_DEV_WARN, "duplicate ground-net index:" << index);
|
||||
}
|
||||
|
||||
SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
|
||||
|
@ -200,7 +200,7 @@ void FGGroundNetXMLLoader::startArc(const XMLAttributes &atts)
|
|||
|
||||
IntPair e(begin, end);
|
||||
if (_arcSet.find(e) != _arcSet.end()) {
|
||||
SG_LOG(SG_NAVAID, SG_WARN, _groundNetwork->airport()->ident() << " ground-net: skipping duplicate edge:" << begin << "->" << end);
|
||||
SG_LOG(SG_NAVAID, SG_DEV_WARN, _groundNetwork->airport()->ident() << " ground-net: skipping duplicate edge:" << begin << "->" << end);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -208,7 +208,7 @@ void FGGroundNetXMLLoader::startArc(const XMLAttributes &atts)
|
|||
FGTaxiNodeRef fromNode, toNode;
|
||||
it = _indexMap.find(begin);
|
||||
if (it == _indexMap.end()) {
|
||||
SG_LOG(SG_NAVAID, SG_WARN, "ground-net: bad edge:" << begin << "->" << end << ", begin index unknown");
|
||||
SG_LOG(SG_NAVAID, SG_DEV_WARN, "ground-net: bad edge:" << begin << "->" << end << ", begin index unknown");
|
||||
return;
|
||||
} else {
|
||||
_unreferencedNodes.erase(it->second);
|
||||
|
@ -217,7 +217,7 @@ void FGGroundNetXMLLoader::startArc(const XMLAttributes &atts)
|
|||
|
||||
it = _indexMap.find(end);
|
||||
if (it == _indexMap.end()) {
|
||||
SG_LOG(SG_NAVAID, SG_WARN, "ground-net: bad edge:" << begin << "->" << end << ", end index unknown");
|
||||
SG_LOG(SG_NAVAID, SG_DEV_WARN, "ground-net: bad edge:" << begin << "->" << end << ", end index unknown");
|
||||
return;
|
||||
} else {
|
||||
_unreferencedNodes.erase(it->second);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include "config.h"
|
||||
|
||||
#include "gnnode.hxx"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
|
|
@ -259,38 +259,38 @@ void FGRouteMgr::init() {
|
|||
magvar = fgGetNode("/environment/magnetic-variation-deg", true);
|
||||
|
||||
departure = fgGetNode(RM "departure", true);
|
||||
departure->tie("airport", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
||||
departure->tie("airport", SGStringValueMethods<FGRouteMgr>(*this,
|
||||
&FGRouteMgr::getDepartureICAO, &FGRouteMgr::setDepartureICAO));
|
||||
departure->tie("runway", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
||||
&FGRouteMgr::getDepartureRunway,
|
||||
&FGRouteMgr::setDepartureRunway));
|
||||
departure->tie("sid", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
||||
&FGRouteMgr::getSID,
|
||||
&FGRouteMgr::setSID));
|
||||
departure->tie("runway", SGStringValueMethods<FGRouteMgr>(*this,
|
||||
&FGRouteMgr::getDepartureRunway,
|
||||
&FGRouteMgr::setDepartureRunway));
|
||||
departure->tie("sid", SGStringValueMethods<FGRouteMgr>(*this,
|
||||
&FGRouteMgr::getSID,
|
||||
&FGRouteMgr::setSID));
|
||||
|
||||
departure->tie("name", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
||||
departure->tie("name", SGStringValueMethods<FGRouteMgr>(*this,
|
||||
&FGRouteMgr::getDepartureName, NULL));
|
||||
departure->tie("field-elevation-ft", SGRawValueMethods<FGRouteMgr, double>(*this,
|
||||
&FGRouteMgr::getDepartureFieldElevation, NULL));
|
||||
&FGRouteMgr::getDepartureFieldElevation, NULL));
|
||||
departure->getChild("etd", 0, true);
|
||||
departure->getChild("takeoff-time", 0, true);
|
||||
|
||||
destination = fgGetNode(RM "destination", true);
|
||||
destination->getChild("airport", 0, true);
|
||||
|
||||
destination->tie("airport", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
||||
destination->tie("airport", SGStringValueMethods<FGRouteMgr>(*this,
|
||||
&FGRouteMgr::getDestinationICAO, &FGRouteMgr::setDestinationICAO));
|
||||
destination->tie("runway", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
||||
destination->tie("runway", SGStringValueMethods<FGRouteMgr>(*this,
|
||||
&FGRouteMgr::getDestinationRunway,
|
||||
&FGRouteMgr::setDestinationRunway));
|
||||
destination->tie("star", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
||||
&FGRouteMgr::getSTAR,
|
||||
&FGRouteMgr::setSTAR));
|
||||
destination->tie("approach", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
||||
&FGRouteMgr::getApproach,
|
||||
&FGRouteMgr::setApproach));
|
||||
destination->tie("star", SGStringValueMethods<FGRouteMgr>(*this,
|
||||
&FGRouteMgr::getSTAR,
|
||||
&FGRouteMgr::setSTAR));
|
||||
destination->tie("approach", SGStringValueMethods<FGRouteMgr>(*this,
|
||||
&FGRouteMgr::getApproach,
|
||||
&FGRouteMgr::setApproach));
|
||||
|
||||
destination->tie("name", SGRawValueMethods<FGRouteMgr, const char*>(*this,
|
||||
destination->tie("name", SGStringValueMethods<FGRouteMgr>(*this,
|
||||
&FGRouteMgr::getDestinationName, NULL));
|
||||
destination->tie("field-elevation-ft", SGRawValueMethods<FGRouteMgr, double>(*this,
|
||||
&FGRouteMgr::getDestinationFieldElevation, NULL));
|
||||
|
@ -637,7 +637,7 @@ void FGRouteMgr::update_mirror()
|
|||
SGPropertyNode *prop = mirror->getChild("wp", i, 1);
|
||||
|
||||
const SGGeod& pos(wp->position());
|
||||
prop->setStringValue("id", wp->ident().c_str());
|
||||
prop->setStringValue("id", wp->ident());
|
||||
prop->setDoubleValue("longitude-deg", pos.getLongitudeDeg());
|
||||
prop->setDoubleValue("latitude-deg",pos.getLatitudeDeg());
|
||||
|
||||
|
@ -797,64 +797,64 @@ void FGRouteMgr::currentWaypointChanged()
|
|||
SG_LOG(SG_AUTOPILOT, SG_INFO, "route manager, current-wp is now " << currentIndex());
|
||||
}
|
||||
|
||||
const char* FGRouteMgr::getDepartureICAO() const
|
||||
std::string FGRouteMgr::getDepartureICAO() const
|
||||
{
|
||||
if (!_plan || !_plan->departureAirport()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return _plan->departureAirport()->ident().c_str();
|
||||
return _plan->departureAirport()->ident();
|
||||
}
|
||||
|
||||
const char* FGRouteMgr::getDepartureName() const
|
||||
std::string FGRouteMgr::getDepartureName() const
|
||||
{
|
||||
if (!_plan || !_plan->departureAirport()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return _plan->departureAirport()->name().c_str();
|
||||
return _plan->departureAirport()->name();
|
||||
}
|
||||
|
||||
const char* FGRouteMgr::getDepartureRunway() const
|
||||
std::string FGRouteMgr::getDepartureRunway() const
|
||||
{
|
||||
if (_plan && _plan->departureRunway()) {
|
||||
return _plan->departureRunway()->ident().c_str();
|
||||
return _plan->departureRunway()->ident();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void FGRouteMgr::setDepartureRunway(const char* aIdent)
|
||||
void FGRouteMgr::setDepartureRunway(const std::string& aIdent)
|
||||
{
|
||||
if (!_plan) {
|
||||
return;
|
||||
}
|
||||
|
||||
FGAirport* apt = _plan->departureAirport();
|
||||
if (!apt || (aIdent == NULL)) {
|
||||
if (!apt || aIdent.empty()) {
|
||||
_plan->setDeparture(apt);
|
||||
} else if (apt->hasRunwayWithIdent(aIdent)) {
|
||||
_plan->setDeparture(apt->getRunwayByIdent(aIdent));
|
||||
}
|
||||
}
|
||||
|
||||
void FGRouteMgr::setDepartureICAO(const char* aIdent)
|
||||
void FGRouteMgr::setDepartureICAO(const std::string& aIdent)
|
||||
{
|
||||
if (!_plan) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((aIdent == NULL) || (strlen(aIdent) < 4)) {
|
||||
if (aIdent.length() < 4) {
|
||||
_plan->setDeparture((FGAirport*) NULL);
|
||||
} else {
|
||||
_plan->setDeparture(FGAirport::findByIdent(aIdent));
|
||||
}
|
||||
}
|
||||
|
||||
const char* FGRouteMgr::getSID() const
|
||||
std::string FGRouteMgr::getSID() const
|
||||
{
|
||||
if (_plan && _plan->sid()) {
|
||||
return _plan->sid()->ident().c_str();
|
||||
return _plan->sid()->ident();
|
||||
}
|
||||
|
||||
return "";
|
||||
|
@ -923,19 +923,19 @@ flightgear::SID* createDefaultSID(FGRunway* aRunway, double enrouteCourse)
|
|||
return flightgear::SID::createTempSID("DEFAULT", aRunway, wpts);
|
||||
}
|
||||
|
||||
void FGRouteMgr::setSID(const char* aIdent)
|
||||
void FGRouteMgr::setSID(const std::string& aIdent)
|
||||
{
|
||||
if (!_plan) {
|
||||
return;
|
||||
}
|
||||
|
||||
FGAirport* apt = _plan->departureAirport();
|
||||
if (!apt || (aIdent == NULL)) {
|
||||
if (!apt || aIdent.empty()) {
|
||||
_plan->setSID((flightgear::SID*) NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcmp(aIdent, "DEFAULT")) {
|
||||
if (aIdent == "DEFAULT") {
|
||||
double enrouteCourse = -1.0;
|
||||
if (_plan->destinationAirport()) {
|
||||
enrouteCourse = SGGeodesy::courseDeg(apt->geod(), _plan->destinationAirport()->geod());
|
||||
|
@ -945,11 +945,10 @@ void FGRouteMgr::setSID(const char* aIdent)
|
|||
return;
|
||||
}
|
||||
|
||||
string ident(aIdent);
|
||||
size_t hyphenPos = ident.find('-');
|
||||
size_t hyphenPos = aIdent.find('-');
|
||||
if (hyphenPos != string::npos) {
|
||||
string sidIdent = ident.substr(0, hyphenPos);
|
||||
string transIdent = ident.substr(hyphenPos + 1);
|
||||
string sidIdent = aIdent.substr(0, hyphenPos);
|
||||
string transIdent = aIdent.substr(hyphenPos + 1);
|
||||
|
||||
flightgear::SID* sid = apt->findSIDWithIdent(sidIdent);
|
||||
Transition* trans = sid ? sid->findTransitionByName(transIdent) : NULL;
|
||||
|
@ -959,64 +958,64 @@ void FGRouteMgr::setSID(const char* aIdent)
|
|||
}
|
||||
}
|
||||
|
||||
const char* FGRouteMgr::getDestinationICAO() const
|
||||
std::string FGRouteMgr::getDestinationICAO() const
|
||||
{
|
||||
if (!_plan || !_plan->destinationAirport()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return _plan->destinationAirport()->ident().c_str();
|
||||
return _plan->destinationAirport()->ident();
|
||||
}
|
||||
|
||||
const char* FGRouteMgr::getDestinationName() const
|
||||
std::string FGRouteMgr::getDestinationName() const
|
||||
{
|
||||
if (!_plan || !_plan->destinationAirport()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return _plan->destinationAirport()->name().c_str();
|
||||
return _plan->destinationAirport()->name();
|
||||
}
|
||||
|
||||
void FGRouteMgr::setDestinationICAO(const char* aIdent)
|
||||
void FGRouteMgr::setDestinationICAO(const std::string& aIdent)
|
||||
{
|
||||
if (!_plan) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((aIdent == NULL) || (strlen(aIdent) < 4)) {
|
||||
if (aIdent.length() < 4) {
|
||||
_plan->setDestination((FGAirport*) NULL);
|
||||
} else {
|
||||
_plan->setDestination(FGAirport::findByIdent(aIdent));
|
||||
}
|
||||
}
|
||||
|
||||
const char* FGRouteMgr::getDestinationRunway() const
|
||||
std::string FGRouteMgr::getDestinationRunway() const
|
||||
{
|
||||
if (_plan && _plan->destinationRunway()) {
|
||||
return _plan->destinationRunway()->ident().c_str();
|
||||
return _plan->destinationRunway()->ident();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void FGRouteMgr::setDestinationRunway(const char* aIdent)
|
||||
void FGRouteMgr::setDestinationRunway(const std::string& aIdent)
|
||||
{
|
||||
if (!_plan) {
|
||||
return;
|
||||
}
|
||||
|
||||
FGAirport* apt = _plan->destinationAirport();
|
||||
if (!apt || (aIdent == NULL)) {
|
||||
if (!apt || aIdent.empty()) {
|
||||
_plan->setDestination(apt);
|
||||
} else if (apt->hasRunwayWithIdent(aIdent)) {
|
||||
_plan->setDestination(apt->getRunwayByIdent(aIdent));
|
||||
}
|
||||
}
|
||||
|
||||
const char* FGRouteMgr::getApproach() const
|
||||
std::string FGRouteMgr::getApproach() const
|
||||
{
|
||||
if (_plan && _plan->approach()) {
|
||||
return _plan->approach()->ident().c_str();
|
||||
return _plan->approach()->ident();
|
||||
}
|
||||
|
||||
return "";
|
||||
|
@ -1082,14 +1081,14 @@ flightgear::Approach* createDefaultApproach(FGRunway* aRunway, double aEnrouteCo
|
|||
return Approach::createTempApproach("DEFAULT", aRunway, wpts);
|
||||
}
|
||||
|
||||
void FGRouteMgr::setApproach(const char* aIdent)
|
||||
void FGRouteMgr::setApproach(const std::string& aIdent)
|
||||
{
|
||||
if (!_plan) {
|
||||
return;
|
||||
}
|
||||
|
||||
FGAirport* apt = _plan->destinationAirport();
|
||||
if (!strcmp(aIdent, "DEFAULT")) {
|
||||
if (aIdent == "DEFAULT") {
|
||||
double enrouteCourse = -1.0;
|
||||
if (_plan->departureAirport()) {
|
||||
enrouteCourse = SGGeodesy::courseDeg(_plan->departureAirport()->geod(), apt->geod());
|
||||
|
@ -1099,30 +1098,30 @@ void FGRouteMgr::setApproach(const char* aIdent)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!apt || (aIdent == NULL)) {
|
||||
if (!apt || aIdent.empty()) {
|
||||
_plan->setApproach(NULL);
|
||||
} else {
|
||||
_plan->setApproach(apt->findApproachWithIdent(aIdent));
|
||||
}
|
||||
}
|
||||
|
||||
const char* FGRouteMgr::getSTAR() const
|
||||
std::string FGRouteMgr::getSTAR() const
|
||||
{
|
||||
if (_plan && _plan->star()) {
|
||||
return _plan->star()->ident().c_str();
|
||||
return _plan->star()->ident();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void FGRouteMgr::setSTAR(const char* aIdent)
|
||||
void FGRouteMgr::setSTAR(const std::string& aIdent)
|
||||
{
|
||||
if (!_plan) {
|
||||
return;
|
||||
}
|
||||
|
||||
FGAirport* apt = _plan->destinationAirport();
|
||||
if (!apt || (aIdent == NULL)) {
|
||||
if (!apt || aIdent.empty()) {
|
||||
_plan->setSTAR((STAR*) NULL);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -183,28 +183,28 @@ private:
|
|||
virtual void currentWaypointChanged();
|
||||
|
||||
// tied getters and setters
|
||||
const char* getDepartureICAO() const;
|
||||
const char* getDepartureName() const;
|
||||
void setDepartureICAO(const char* aIdent);
|
||||
std::string getDepartureICAO() const;
|
||||
std::string getDepartureName() const;
|
||||
void setDepartureICAO(const std::string& aIdent);
|
||||
|
||||
const char* getDepartureRunway() const;
|
||||
void setDepartureRunway(const char* aIdent);
|
||||
std::string getDepartureRunway() const;
|
||||
void setDepartureRunway(const std::string& aIdent);
|
||||
|
||||
const char* getSID() const;
|
||||
void setSID(const char* aIdent);
|
||||
std::string getSID() const;
|
||||
void setSID(const std::string& aIdent);
|
||||
|
||||
const char* getDestinationICAO() const;
|
||||
const char* getDestinationName() const;
|
||||
void setDestinationICAO(const char* aIdent);
|
||||
std::string getDestinationICAO() const;
|
||||
std::string getDestinationName() const;
|
||||
void setDestinationICAO(const std::string& aIdent);
|
||||
|
||||
const char* getDestinationRunway() const;
|
||||
void setDestinationRunway(const char* aIdent);
|
||||
std::string getDestinationRunway() const;
|
||||
void setDestinationRunway(const std::string& aIdent);
|
||||
|
||||
const char* getApproach() const;
|
||||
void setApproach(const char* aIdent);
|
||||
std::string getApproach() const;
|
||||
void setApproach(const std::string& aIdent);
|
||||
|
||||
const char* getSTAR() const;
|
||||
void setSTAR(const char* aIdent);
|
||||
std::string getSTAR() const;
|
||||
void setSTAR(const std::string& aIdent);
|
||||
|
||||
double getDepartureFieldElevation() const;
|
||||
double getDestinationFieldElevation() const;
|
||||
|
|
|
@ -183,7 +183,7 @@ private:
|
|||
class SymbolRule
|
||||
{
|
||||
public:
|
||||
SymbolRule()
|
||||
SymbolRule() : enabled(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -26,8 +26,13 @@
|
|||
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#ifdef FG_TESTLIB
|
||||
#include <tests/fake_sgSky.hxx>
|
||||
#else
|
||||
#include <simgear/scene/sky/sky.hxx>
|
||||
#include <simgear/scene/model/particles.hxx>
|
||||
#endif
|
||||
#include <simgear/structure/event_mgr.hxx>
|
||||
|
||||
#include <Main/main.hxx>
|
||||
|
@ -47,6 +52,7 @@
|
|||
#include "gravity.hxx"
|
||||
#include "magvarmanager.hxx"
|
||||
|
||||
#ifndef FG_TESTLIB
|
||||
class FG3DCloudsListener : public SGPropertyChangeListener {
|
||||
public:
|
||||
FG3DCloudsListener( FGClouds * fgClouds );
|
||||
|
@ -77,19 +83,26 @@ void FG3DCloudsListener::valueChanged( SGPropertyNode * node )
|
|||
{
|
||||
_fgClouds->set_3dClouds( _enableNode->getBoolValue() );
|
||||
}
|
||||
#endif
|
||||
|
||||
FGEnvironmentMgr::FGEnvironmentMgr () :
|
||||
_environment(new FGEnvironment()),
|
||||
fgClouds(new FGClouds()),
|
||||
fgClouds(nullptr),
|
||||
_cloudLayersDirty(true),
|
||||
_3dCloudsEnableListener(new FG3DCloudsListener(fgClouds) ),
|
||||
_3dCloudsEnableListener(nullptr),
|
||||
_sky(globals->get_renderer()->getSky())
|
||||
{
|
||||
#ifndef FG_TESTLIB
|
||||
fgClouds = new FGClouds;
|
||||
_3dCloudsEnableListener = new FG3DCloudsListener(fgClouds);
|
||||
#endif
|
||||
set_subsystem("controller", Environment::LayerInterpolateController::createInstance( fgGetNode("/environment/config", true ) ));
|
||||
set_subsystem("realwx", Environment::RealWxController::createInstance( fgGetNode("/environment/realwx", true ) ), 1.0 );
|
||||
|
||||
set_subsystem("precipitation", new FGPrecipitationMgr);
|
||||
#ifndef FG_TESTLIB
|
||||
set_subsystem("realwx", Environment::RealWxController::createInstance( fgGetNode("/environment/realwx", true ) ), 1.0 );
|
||||
set_subsystem("terrainsampler", Environment::TerrainSampler::createInstance( fgGetNode("/environment/terrain", true ) ));
|
||||
#endif
|
||||
set_subsystem("ridgelift", new FGRidgeLift);
|
||||
|
||||
set_subsystem("magvar", new FGMagVarManager);
|
||||
|
@ -104,10 +117,11 @@ FGEnvironmentMgr::~FGEnvironmentMgr ()
|
|||
remove_subsystem("controller");
|
||||
remove_subsystem("magvar");
|
||||
|
||||
#ifndef FG_TESTLIB
|
||||
delete fgClouds;
|
||||
delete _environment;
|
||||
|
||||
delete _3dCloudsEnableListener;
|
||||
#endif
|
||||
delete _environment;
|
||||
}
|
||||
|
||||
SGSubsystem::InitStatus FGEnvironmentMgr::incrementalInit()
|
||||
|
@ -115,7 +129,9 @@ SGSubsystem::InitStatus FGEnvironmentMgr::incrementalInit()
|
|||
|
||||
InitStatus r = SGSubsystemGroup::incrementalInit();
|
||||
if (r == INIT_DONE) {
|
||||
#ifndef FG_TESTLIB
|
||||
fgClouds->Init();
|
||||
#endif
|
||||
globals->get_event_mgr()->addTask("updateClosestAirport", this,
|
||||
&FGEnvironmentMgr::updateClosestAirport, 30 );
|
||||
}
|
||||
|
@ -148,10 +164,11 @@ FGEnvironmentMgr::bind ()
|
|||
_tiedProperties.Tie( "effective-visibility-m", _sky,
|
||||
&SGSky::get_visibility );
|
||||
|
||||
#ifndef FG_TESTLIB
|
||||
_tiedProperties.Tie("rebuild-layers", fgClouds,
|
||||
&FGClouds::get_update_event,
|
||||
&FGClouds::set_update_event);
|
||||
|
||||
#endif
|
||||
// _tiedProperties.Tie("turbulence/use-cloud-turbulence", &sgEnviro,
|
||||
// &SGEnviro::get_turbulence_enable_state,
|
||||
// &SGEnviro::set_turbulence_enable_state);
|
||||
|
@ -221,7 +238,6 @@ FGEnvironmentMgr::bind ()
|
|||
_tiedProperties.Tie("clouds3d-use-impostors", _sky,
|
||||
&SGSky::get_3dCloudUseImpostors,
|
||||
&SGSky::set_3dCloudUseImpostors);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -240,13 +256,14 @@ FGEnvironmentMgr::update (double dt)
|
|||
SGGeod aircraftPos(globals->get_aircraft_position());
|
||||
_environment->set_elevation_ft( aircraftPos.getElevationFt() );
|
||||
|
||||
#ifndef FG_TESTLIB
|
||||
simgear::Particles::setWindFrom( _environment->get_wind_from_heading_deg(),
|
||||
_environment->get_wind_speed_kt() );
|
||||
if( _cloudLayersDirty ) {
|
||||
_cloudLayersDirty = false;
|
||||
fgClouds->set_update_event( fgClouds->get_update_event()+1 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
fgSetDouble( "/environment/gravitational-acceleration-mps2",
|
||||
Environment::Gravity::instance()->getGravity(aircraftPos));
|
||||
|
|
|
@ -160,7 +160,7 @@ FGMetar::FGMetar(const string& icao) :
|
|||
|
||||
long FGMetar::getAge_min() const
|
||||
{
|
||||
time_t now = _x_proxy ? _rq_time : sgGMTime();
|
||||
time_t now = _x_proxy ? _rq_time : time(nullptr);
|
||||
return (now - _time) / 60;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,8 +36,10 @@
|
|||
class FGPrecipitationMgr : public SGSubsystem
|
||||
{
|
||||
private:
|
||||
#ifndef FG_TESTLIB
|
||||
osg::ref_ptr<osg::MatrixTransform> transform;
|
||||
osg::ref_ptr<SGPrecipitation> precipitation;
|
||||
#endif
|
||||
float getPrecipitationAtAltitudeMax(void);
|
||||
simgear::TiedPropertyList _tiedProperties;
|
||||
|
||||
|
@ -56,4 +58,3 @@ public:
|
|||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGFDMExec.cpp,v 1.191 2016/05/16 18:19:57 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGFDMExec.cpp,v 1.194 2017/03/03 23:00:39 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_FDMEXEC);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -428,7 +428,7 @@ void FGFDMExec::LoadInputs(unsigned int idx)
|
|||
Propulsion->in.PropAdvance = FCS->GetPropAdvance();
|
||||
Propulsion->in.PropFeather = FCS->GetPropFeather();
|
||||
Propulsion->in.H_agl = Propagate->GetDistanceAGL();
|
||||
Propulsion->in.PQR = Propagate->GetPQR();
|
||||
Propulsion->in.PQRi = Propagate->GetPQRi();
|
||||
|
||||
break;
|
||||
case eAerodynamics:
|
||||
|
@ -650,24 +650,26 @@ vector <string> FGFDMExec::EnumerateFDMs(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGFDMExec::LoadScript(const string& script, double deltaT, const string& initfile)
|
||||
bool FGFDMExec::LoadScript(const SGPath& script, double deltaT,
|
||||
const SGPath& initfile)
|
||||
{
|
||||
bool result;
|
||||
|
||||
Script = new FGScript(this);
|
||||
result = Script->LoadScript(RootDir + script, deltaT, initfile);
|
||||
result = Script->LoadScript(GetFullPath(script), deltaT, initfile);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGFDMExec::LoadModel(const string& AircraftPath, const string& EnginePath, const string& SystemsPath,
|
||||
const string& model, bool addModelToPath)
|
||||
bool FGFDMExec::LoadModel(const SGPath& AircraftPath, const SGPath& EnginePath,
|
||||
const SGPath& SystemsPath, const string& model,
|
||||
bool addModelToPath)
|
||||
{
|
||||
FGFDMExec::AircraftPath = RootDir + AircraftPath;
|
||||
FGFDMExec::EnginePath = RootDir + EnginePath;
|
||||
FGFDMExec::SystemsPath = RootDir + SystemsPath;
|
||||
FGFDMExec::AircraftPath = GetFullPath(AircraftPath);
|
||||
FGFDMExec::EnginePath = GetFullPath(EnginePath);
|
||||
FGFDMExec::SystemsPath = GetFullPath(SystemsPath);
|
||||
|
||||
return LoadModel(model, addModelToPath);
|
||||
}
|
||||
|
@ -676,20 +678,20 @@ bool FGFDMExec::LoadModel(const string& AircraftPath, const string& EnginePath,
|
|||
|
||||
bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
||||
{
|
||||
string aircraftCfgFileName;
|
||||
SGPath aircraftCfgFileName;
|
||||
bool result = false; // initialize result to false, indicating input file not yet read
|
||||
|
||||
modelName = model; // Set the class modelName attribute
|
||||
|
||||
if( AircraftPath.empty() || EnginePath.empty() || SystemsPath.empty()) {
|
||||
if( AircraftPath.isNull() || EnginePath.isNull() || SystemsPath.isNull()) {
|
||||
cerr << "Error: attempted to load aircraft with undefined ";
|
||||
cerr << "aircraft, engine, and system paths" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
FullAircraftPath = AircraftPath;
|
||||
if (addModelToPath) FullAircraftPath += "/" + model;
|
||||
aircraftCfgFileName = FullAircraftPath + "/" + model + ".xml";
|
||||
if (addModelToPath) FullAircraftPath.append(model);
|
||||
aircraftCfgFileName = FullAircraftPath/(model + ".xml");
|
||||
|
||||
if (modelLoaded) {
|
||||
DeAllocate();
|
||||
|
|
|
@ -49,12 +49,13 @@ INCLUDES
|
|||
#include "models/FGPropagate.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
#include "models/FGOutput.h"
|
||||
#include "simgear/misc/sg_path.hxx"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_FDMEXEC "$Id: FGFDMExec.h,v 1.105 2016/04/16 12:24:39 bcoconni Exp $"
|
||||
#define ID_FDMEXEC "$Id: FGFDMExec.h,v 1.106 2017/02/25 14:23:18 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -178,7 +179,7 @@ CLASS DOCUMENTATION
|
|||
property actually maps toa function call of DoTrim().
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision: 1.105 $
|
||||
@version $Revision: 1.106 $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -284,8 +285,8 @@ public:
|
|||
@param addModelToPath set to true to add the model name to the
|
||||
AircraftPath, defaults to true
|
||||
@return true if successful */
|
||||
bool LoadModel(const std::string& AircraftPath, const std::string& EnginePath,
|
||||
const std::string& SystemsPath, const std::string& model,
|
||||
bool LoadModel(const SGPath& AircraftPath, const SGPath& EnginePath,
|
||||
const SGPath& SystemsPath, const std::string& model,
|
||||
bool addModelToPath = true);
|
||||
|
||||
/** Loads an aircraft model. The paths to the aircraft and engine
|
||||
|
@ -310,24 +311,33 @@ public:
|
|||
the file specified in the script will be used. If an initialization file
|
||||
is not given in either place, an error will result.
|
||||
@return true if successfully loads; false otherwise. */
|
||||
bool LoadScript(const std::string& Script, double deltaT=0.0,
|
||||
const std::string& initfile="");
|
||||
bool LoadScript(const SGPath& Script, double deltaT=0.0,
|
||||
const SGPath& initfile=SGPath());
|
||||
|
||||
/** Sets the path to the engine config file directories.
|
||||
@param path path to the directory under which engine config
|
||||
files are kept, for instance "engine" */
|
||||
bool SetEnginePath(const std::string& path) { EnginePath = RootDir + path; return true; }
|
||||
bool SetEnginePath(const SGPath& path) {
|
||||
EnginePath = GetFullPath(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Sets the path to the aircraft config file directories.
|
||||
@param path path to the aircraft directory. For instance:
|
||||
"aircraft". Under aircraft, then, would be directories for various
|
||||
modeled aircraft such as C172/, x15/, etc. */
|
||||
bool SetAircraftPath(const std::string& path) { AircraftPath = RootDir + path; return true; }
|
||||
bool SetAircraftPath(const SGPath& path) {
|
||||
AircraftPath = GetFullPath(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Sets the path to the systems config file directories.
|
||||
@param path path to the directory under which systems config
|
||||
files are kept, for instance "systems" */
|
||||
bool SetSystemsPath(const std::string& path) { SystemsPath = RootDir + path; return true; }
|
||||
bool SetSystemsPath(const SGPath& path) {
|
||||
SystemsPath = GetFullPath(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @name Top-level executive State and Model retrieval mechanism
|
||||
///@{
|
||||
|
@ -378,13 +388,13 @@ public:
|
|||
///@}
|
||||
|
||||
/// Retrieves the engine path.
|
||||
const std::string& GetEnginePath(void) {return EnginePath;}
|
||||
const SGPath& GetEnginePath(void) {return EnginePath;}
|
||||
/// Retrieves the aircraft path.
|
||||
const std::string& GetAircraftPath(void) {return AircraftPath;}
|
||||
const SGPath& GetAircraftPath(void) {return AircraftPath;}
|
||||
/// Retrieves the systems path.
|
||||
const std::string& GetSystemsPath(void) {return SystemsPath;}
|
||||
const SGPath& GetSystemsPath(void) {return SystemsPath;}
|
||||
/// Retrieves the full aircraft path name.
|
||||
const std::string& GetFullAircraftPath(void) {return FullAircraftPath;}
|
||||
const SGPath& GetFullAircraftPath(void) {return FullAircraftPath;}
|
||||
|
||||
/** Retrieves the value of a property.
|
||||
@param property the name of the property
|
||||
|
@ -428,8 +438,8 @@ public:
|
|||
be logged.
|
||||
@param fname the filename of an output directives file.
|
||||
*/
|
||||
bool SetOutputDirectives(const std::string& fname)
|
||||
{return Output->SetDirectivesFile(RootDir + fname);}
|
||||
bool SetOutputDirectives(const SGPath& fname)
|
||||
{ return Output->SetDirectivesFile(GetFullPath(fname)); }
|
||||
|
||||
/** Forces the specified output object to print its items once */
|
||||
void ForceOutput(int idx=0) { Output->ForceOutput(idx); }
|
||||
|
@ -550,11 +560,11 @@ public:
|
|||
|
||||
/** Sets the root directory where JSBSim starts looking for its system directories.
|
||||
@param rootDir the string containing the root directory. */
|
||||
void SetRootDir(const std::string& rootDir) {RootDir = rootDir;}
|
||||
void SetRootDir(const SGPath& rootDir) {RootDir = rootDir;}
|
||||
|
||||
/** Retrieves the Root Directory.
|
||||
@return the string representing the root (base) JSBSim directory. */
|
||||
const std::string& GetRootDir(void) const {return RootDir;}
|
||||
const SGPath& GetRootDir(void) const {return RootDir;}
|
||||
|
||||
/** Increments the simulation time if not in Holding mode. The Frame counter
|
||||
is also incremented.
|
||||
|
@ -606,13 +616,13 @@ private:
|
|||
bool modelLoaded;
|
||||
bool IsChild;
|
||||
std::string modelName;
|
||||
std::string AircraftPath;
|
||||
std::string FullAircraftPath;
|
||||
std::string EnginePath;
|
||||
std::string SystemsPath;
|
||||
SGPath AircraftPath;
|
||||
SGPath FullAircraftPath;
|
||||
SGPath EnginePath;
|
||||
SGPath SystemsPath;
|
||||
std::string CFGVersion;
|
||||
std::string Release;
|
||||
std::string RootDir;
|
||||
SGPath RootDir;
|
||||
|
||||
// Standard Model pointers - shortcuts for internal executive use only.
|
||||
FGPropagate* Propagate;
|
||||
|
@ -664,6 +674,12 @@ private:
|
|||
bool Allocate(void);
|
||||
bool DeAllocate(void);
|
||||
int GetDisperse(void) const {return disperse;}
|
||||
SGPath GetFullPath(const SGPath& name) {
|
||||
if (name.isRelative())
|
||||
return RootDir/name.utf8Str();
|
||||
else
|
||||
return name;
|
||||
}
|
||||
|
||||
void Debug(int from);
|
||||
};
|
||||
|
|
|
@ -77,18 +77,18 @@ using JSBSim::Element;
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
IDENT(IdSrc,"$Id: JSBSim.cpp,v 1.89 2016/05/20 14:14:05 ehofman Exp $");
|
||||
IDENT(IdSrc,"$Id: JSBSim.cpp,v 1.90 2017/02/25 14:23:18 bcoconni Exp $");
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
GLOBAL DATA
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
string RootDir = "";
|
||||
string ScriptName;
|
||||
SGPath RootDir;
|
||||
SGPath ScriptName;
|
||||
string AircraftName;
|
||||
string ResetName;
|
||||
SGPath ResetName;
|
||||
vector <string> LogOutputName;
|
||||
vector <string> LogDirectiveName;
|
||||
vector <SGPath> LogDirectiveName;
|
||||
vector <string> CommandLineProperties;
|
||||
vector <double> CommandLinePropertyValues;
|
||||
JSBSim::FGFDMExec* FDMExec;
|
||||
|
@ -151,28 +151,28 @@ void PrintHelp(void);
|
|||
of file is given on the command line */
|
||||
class XMLFile : public FGXMLFileRead {
|
||||
public:
|
||||
bool IsScriptFile(std::string filename) {
|
||||
bool IsScriptFile(const SGPath& filename) {
|
||||
bool result=false;
|
||||
Element *document = LoadXMLDocument(filename, false);
|
||||
if (document && document->GetName() == "runscript") result = true;
|
||||
ResetParser();
|
||||
return result;
|
||||
}
|
||||
bool IsLogDirectiveFile(std::string filename) {
|
||||
bool IsLogDirectiveFile(const SGPath& filename) {
|
||||
bool result=false;
|
||||
Element *document = LoadXMLDocument(filename, false);
|
||||
if (document && document->GetName() == "output") result = true;
|
||||
ResetParser();
|
||||
return result;
|
||||
}
|
||||
bool IsAircraftFile(std::string filename) {
|
||||
bool IsAircraftFile(const SGPath& filename) {
|
||||
bool result=false;
|
||||
Element* document = LoadXMLDocument(filename, false);
|
||||
if (document && document->GetName() == "fdm_config") result = true;
|
||||
ResetParser();
|
||||
return result;
|
||||
}
|
||||
bool IsInitFile(std::string filename) {
|
||||
bool IsInitFile(const SGPath& filename) {
|
||||
bool result=false;
|
||||
Element *document = LoadXMLDocument(filename, false);
|
||||
if (document && document->GetName() == "initialize") result = true;
|
||||
|
@ -345,9 +345,9 @@ int real_main(int argc, char* argv[])
|
|||
// *** SET UP JSBSIM *** //
|
||||
FDMExec = new JSBSim::FGFDMExec();
|
||||
FDMExec->SetRootDir(RootDir);
|
||||
FDMExec->SetAircraftPath("aircraft");
|
||||
FDMExec->SetEnginePath("engine");
|
||||
FDMExec->SetSystemsPath("systems");
|
||||
FDMExec->SetAircraftPath(SGPath("aircraft"));
|
||||
FDMExec->SetEnginePath(SGPath("engine"));
|
||||
FDMExec->SetSystemsPath(SGPath("systems"));
|
||||
FDMExec->GetPropertyManager()->Tie("simulation/frame_start_time", &actual_elapsed_time);
|
||||
FDMExec->GetPropertyManager()->Tie("simulation/cycle_duration", &cycle_duration);
|
||||
|
||||
|
@ -372,7 +372,7 @@ int real_main(int argc, char* argv[])
|
|||
}
|
||||
|
||||
// *** OPTION A: LOAD A SCRIPT, WHICH LOADS EVERYTHING ELSE *** //
|
||||
if (!ScriptName.empty()) {
|
||||
if (!ScriptName.isNull()) {
|
||||
|
||||
result = FDMExec->LoadScript(ScriptName, override_sim_rate_value, ResetName);
|
||||
|
||||
|
@ -383,14 +383,14 @@ int real_main(int argc, char* argv[])
|
|||
}
|
||||
|
||||
// *** OPTION B: LOAD AN AIRCRAFT AND A SET OF INITIAL CONDITIONS *** //
|
||||
} else if (!AircraftName.empty() || !ResetName.empty()) {
|
||||
} else if (!AircraftName.empty() || !ResetName.isNull()) {
|
||||
|
||||
if (catalog) FDMExec->SetDebugLevel(0);
|
||||
|
||||
if ( ! FDMExec->LoadModel( "aircraft",
|
||||
"engine",
|
||||
"systems",
|
||||
AircraftName)) {
|
||||
if ( ! FDMExec->LoadModel(SGPath("aircraft"),
|
||||
SGPath("engine"),
|
||||
SGPath("systems"),
|
||||
AircraftName)) {
|
||||
cerr << " JSBSim could not be started" << endl << endl;
|
||||
delete FDMExec;
|
||||
exit(-1);
|
||||
|
@ -417,7 +417,7 @@ int real_main(int argc, char* argv[])
|
|||
|
||||
// Load output directives file[s], if given
|
||||
for (unsigned int i=0; i<LogDirectiveName.size(); i++) {
|
||||
if (!LogDirectiveName[i].empty()) {
|
||||
if (!LogDirectiveName[i].isNull()) {
|
||||
if (!FDMExec->SetOutputDirectives(LogDirectiveName[i])) {
|
||||
cout << "Output directives not properly set in file " << LogDirectiveName[i] << endl;
|
||||
delete FDMExec;
|
||||
|
@ -621,17 +621,14 @@ bool options(int count, char **arg)
|
|||
}
|
||||
} else if (keyword == "--logdirectivefile") {
|
||||
if (n != string::npos) {
|
||||
LogDirectiveName.push_back(value);
|
||||
LogDirectiveName.push_back(SGPath::fromLocal8Bit(value.c_str()));
|
||||
} else {
|
||||
gripe;
|
||||
exit(1);
|
||||
}
|
||||
} else if (keyword == "--root") {
|
||||
if (n != string::npos) {
|
||||
RootDir = value;
|
||||
if (RootDir[RootDir.length()-1] != '/') {
|
||||
RootDir += '/';
|
||||
}
|
||||
RootDir = SGPath::fromLocal8Bit(value.c_str());
|
||||
} else {
|
||||
gripe;
|
||||
exit(1);
|
||||
|
@ -645,14 +642,14 @@ bool options(int count, char **arg)
|
|||
}
|
||||
} else if (keyword == "--script") {
|
||||
if (n != string::npos) {
|
||||
ScriptName = value;
|
||||
ScriptName = SGPath::fromLocal8Bit(value.c_str());
|
||||
} else {
|
||||
gripe;
|
||||
exit(1);
|
||||
}
|
||||
} else if (keyword == "--initfile") {
|
||||
if (n != string::npos) {
|
||||
ResetName = value;
|
||||
ResetName = SGPath::fromLocal8Bit(value.c_str());
|
||||
} else {
|
||||
gripe;
|
||||
exit(1);
|
||||
|
@ -704,12 +701,13 @@ bool options(int count, char **arg)
|
|||
// See what kind of files we are specifying on the command line
|
||||
|
||||
XMLFile xmlFile;
|
||||
SGPath path = SGPath::fromLocal8Bit(keyword.c_str());
|
||||
|
||||
if (xmlFile.IsScriptFile(keyword)) ScriptName = keyword;
|
||||
else if (xmlFile.IsLogDirectiveFile(keyword)) LogDirectiveName.push_back(keyword);
|
||||
else if (xmlFile.IsAircraftFile("aircraft/" + keyword + "/" + keyword)) AircraftName = keyword;
|
||||
else if (xmlFile.IsInitFile(keyword)) ResetName = keyword;
|
||||
else if (xmlFile.IsInitFile("aircraft/" + AircraftName + "/" + keyword)) ResetName = keyword;
|
||||
if (xmlFile.IsScriptFile(path)) ScriptName = path;
|
||||
else if (xmlFile.IsLogDirectiveFile(path)) LogDirectiveName.push_back(path);
|
||||
else if (xmlFile.IsAircraftFile(SGPath("aircraft")/keyword/keyword)) AircraftName = keyword;
|
||||
else if (xmlFile.IsInitFile(path)) ResetName = path;
|
||||
else if (xmlFile.IsInitFile(SGPath("aircraft")/AircraftName/keyword)) ResetName = SGPath("aircraft")/AircraftName/keyword;
|
||||
else {
|
||||
cerr << "The argument \"" << keyword << "\" cannot be interpreted as a file name or option." << endl;
|
||||
exit(1);
|
||||
|
@ -727,15 +725,15 @@ bool options(int count, char **arg)
|
|||
|
||||
// Post-processing for script options. check for incompatible options.
|
||||
|
||||
if (catalog && !ScriptName.empty()) {
|
||||
if (catalog && !ScriptName.isNull()) {
|
||||
cerr << "Cannot specify catalog with script option" << endl << endl;
|
||||
result = false;
|
||||
}
|
||||
if (AircraftName.size() > 0 && ResetName.size() == 0 && !catalog) {
|
||||
if (!AircraftName.empty() && ResetName.isNull() && !catalog) {
|
||||
cerr << "You must specify an initialization file with the aircraft name." << endl << endl;
|
||||
result = false;
|
||||
}
|
||||
if (ScriptName.size() > 0 && AircraftName.size() > 0) {
|
||||
if (!ScriptName.isNull() && !AircraftName.empty()) {
|
||||
cerr << "You cannot specify an aircraft file with a script." << endl;
|
||||
result = false;
|
||||
}
|
||||
|
|
|
@ -188,6 +188,11 @@ FGJSBsim::FGJSBsim( double dt )
|
|||
case SG_POPUP:
|
||||
FGJSBBase::debug_lvl = 0x00;
|
||||
break;
|
||||
|
||||
default:
|
||||
// silence warning about unhandled cases
|
||||
FGJSBBase::debug_lvl = 0x00;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// if flight is excluded, don't bother
|
||||
|
@ -234,9 +239,7 @@ FGJSBsim::FGJSBsim( double dt )
|
|||
|
||||
fdmex->Setdt( dt );
|
||||
|
||||
result = fdmex->LoadModel( aircraft_path.local8BitStr(),
|
||||
engine_path.local8BitStr(),
|
||||
systems_path.local8BitStr(),
|
||||
result = fdmex->LoadModel( aircraft_path, engine_path, systems_path,
|
||||
fgGetString("/sim/aero"), false );
|
||||
|
||||
if (result) {
|
||||
|
|
|
@ -58,7 +58,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGInitialCondition.cpp,v 1.111 2016/07/03 17:20:55 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGInitialCondition.cpp,v 1.114 2017/02/25 14:23:18 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_INITIALCONDITION);
|
||||
|
||||
//******************************************************************************
|
||||
|
@ -709,10 +709,10 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt)
|
|||
altitudeASL=alt;
|
||||
position.SetAltitudeASL(alt);
|
||||
|
||||
if (lastLatitudeSet == setgeod) {
|
||||
double h = ComputeGeodAltitude(geodLatitude);
|
||||
position.SetPositionGeodetic(position.GetLongitude(), geodLatitude, h);
|
||||
}
|
||||
// The call to SetAltitudeASL has most likely modified the geodetic latitude
|
||||
// so we need to restore it to its initial value.
|
||||
if (lastLatitudeSet == setgeod)
|
||||
SetGeodLatitudeRadIC(geodLatitude);
|
||||
|
||||
soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
||||
rho = Atmosphere->GetDensity(altitudeASL);
|
||||
|
@ -880,11 +880,11 @@ double FGInitialCondition::GetBodyVelFpsIC(int idx) const
|
|||
|
||||
//******************************************************************************
|
||||
|
||||
bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
|
||||
bool FGInitialCondition::Load(const SGPath& rstfile, bool useStoredPath)
|
||||
{
|
||||
string init_file_name;
|
||||
if( useStoredPath ) {
|
||||
init_file_name = fdmex->GetFullAircraftPath() + "/" + rstfile + ".xml";
|
||||
SGPath init_file_name;
|
||||
if(useStoredPath && rstfile.isRelative()) {
|
||||
init_file_name = fdmex->GetFullAircraftPath()/rstfile.utf8Str();
|
||||
} else {
|
||||
init_file_name = rstfile;
|
||||
}
|
||||
|
@ -931,16 +931,11 @@ bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
|
|||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Given an altitude above the sea level (or a position radius which is the
|
||||
// same) and a geodetic latitude, compute the geodetic altitude. It is assumed
|
||||
// that the terrain is a sphere and that the elevation is uniform all over the
|
||||
// Earth. Would that assumption fail, the computation below would need to be
|
||||
// adapted since the position radius would depend on the terrain elevation which
|
||||
// depends itself on the latitude.
|
||||
// Given an altitude above the mean sea level (or a position radius which is the
|
||||
// same) and a geodetic latitude, compute the geodetic altitude.
|
||||
//
|
||||
// This is an acceptable trade off because this routine is only used by
|
||||
// standalone JSBSim which uses FGDefaultGroundCallback which assumes that the
|
||||
// Earth is a sphere.
|
||||
// TODO: extend the routine to the case where lastAltitudeSet is equal to
|
||||
// setagl.
|
||||
|
||||
double FGInitialCondition::ComputeGeodAltitude(double geodLatitude)
|
||||
{
|
||||
|
@ -978,11 +973,8 @@ bool FGInitialCondition::LoadLatitude(Element* position_el)
|
|||
|
||||
string lat_type = latitude_el->GetAttributeValue("type");
|
||||
|
||||
if (lat_type == "geod" || lat_type == "geodetic") {
|
||||
double h = ComputeGeodAltitude(latitude);
|
||||
position.SetPositionGeodetic(position.GetLongitude(), latitude, h);
|
||||
lastLatitudeSet = setgeod;
|
||||
}
|
||||
if (lat_type == "geod" || lat_type == "geodetic")
|
||||
SetGeodLatitudeRadIC(latitude);
|
||||
else {
|
||||
position.SetLatitude(latitude);
|
||||
lastLatitudeSet = setgeoc;
|
||||
|
@ -1491,10 +1483,14 @@ void FGInitialCondition::bind(FGPropertyManager* PropertyManager)
|
|||
&FGInitialCondition::GetRRadpsIC,
|
||||
&FGInitialCondition::SetRRadpsIC,
|
||||
true);
|
||||
PropertyManager->Tie("ic/lat-geod-rad", &position,
|
||||
&FGLocation::GetGeodLatitudeRad);
|
||||
PropertyManager->Tie("ic/lat-geod-deg", &position,
|
||||
&FGLocation::GetGeodLatitudeDeg);
|
||||
PropertyManager->Tie("ic/lat-geod-rad", this,
|
||||
&FGInitialCondition::GetGeodLatitudeRadIC,
|
||||
&FGInitialCondition::SetGeodLatitudeRadIC,
|
||||
true);
|
||||
PropertyManager->Tie("ic/lat-geod-deg", this,
|
||||
&FGInitialCondition::GetGeodLatitudeDegIC,
|
||||
&FGInitialCondition::SetGeodLatitudeDegIC,
|
||||
true);
|
||||
PropertyManager->Tie("ic/geod-alt-ft", &position,
|
||||
&FGLocation::GetGeodAltitude);
|
||||
}
|
||||
|
|
|
@ -49,12 +49,13 @@ INCLUDES
|
|||
|
||||
#include "math/FGLocation.h"
|
||||
#include "math/FGQuaternion.h"
|
||||
#include "simgear/misc/sg_path.hxx"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.46 2016/07/03 17:20:55 bcoconni Exp $"
|
||||
#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.48 2017/02/25 14:23:18 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -220,7 +221,7 @@ CLASS DOCUMENTATION
|
|||
@property ic/r-rad_sec (read/write) Yaw rate initial condition in radians/second
|
||||
|
||||
@author Tony Peden
|
||||
@version "$Id: FGInitialCondition.h,v 1.46 2016/07/03 17:20:55 bcoconni Exp $"
|
||||
@version "$Id: FGInitialCondition.h,v 1.48 2017/02/25 14:23:18 bcoconni Exp $"
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -311,6 +312,13 @@ public:
|
|||
@param lat Initial latitude in degrees */
|
||||
void SetLatitudeDegIC(double lat) { SetLatitudeRadIC(lat*degtorad); }
|
||||
|
||||
/** Sets the initial geodetic latitude.
|
||||
This method modifies the geodetic altitude in order to keep the altitude
|
||||
above sea level unchanged.
|
||||
@param glat Initial geodetic latitude in degrees */
|
||||
void SetGeodLatitudeDegIC(double glat)
|
||||
{ SetGeodLatitudeRadIC(glat*degtorad); }
|
||||
|
||||
/** Sets the initial longitude.
|
||||
@param lon Initial longitude in degrees */
|
||||
void SetLongitudeDegIC(double lon) { SetLongitudeRadIC(lon*degtorad); }
|
||||
|
@ -369,6 +377,11 @@ public:
|
|||
@return Initial geocentric latitude in degrees */
|
||||
double GetLatitudeDegIC(void) const { return position.GetLatitudeDeg(); }
|
||||
|
||||
/** Gets the initial geodetic latitude.
|
||||
@return Initial geodetic latitude in degrees */
|
||||
double GetGeodLatitudeDegIC(void) const
|
||||
{ return position.GetGeodLatitudeDeg(); }
|
||||
|
||||
/** Gets the initial longitude.
|
||||
@return Initial longitude in degrees */
|
||||
double GetLongitudeDegIC(void) const { return position.GetLongitudeDeg(); }
|
||||
|
@ -628,6 +641,11 @@ public:
|
|||
@return Initial latitude in radians */
|
||||
double GetLatitudeRadIC(void) const { return position.GetLatitude(); }
|
||||
|
||||
/** Gets the initial geodetic latitude.
|
||||
@return Initial geodetic latitude in radians */
|
||||
double GetGeodLatitudeRadIC(void) const
|
||||
{ return position.GetGeodLatitudeRad(); }
|
||||
|
||||
/** Gets the initial longitude.
|
||||
@return Initial longitude in radians */
|
||||
double GetLongitudeRadIC(void) const { return position.GetLongitude(); }
|
||||
|
@ -660,7 +678,7 @@ public:
|
|||
@param rstname The name of an initial conditions file
|
||||
@param useStoredPath true if the stored path to the IC file should be used
|
||||
@return true if successful */
|
||||
bool Load(std::string rstname, bool useStoredPath = true );
|
||||
bool Load(const SGPath& rstname, bool useStoredPath = true );
|
||||
|
||||
/** Is an engine running ?
|
||||
@param index of the engine to be checked
|
||||
|
|
|
@ -46,7 +46,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc, "$Id: FGModelLoader.cpp,v 1.3 2015/07/12 12:41:55 bcoconni Exp $");
|
||||
IDENT(IdSrc, "$Id: FGModelLoader.cpp,v 1.4 2017/02/25 14:23:18 bcoconni Exp $");
|
||||
IDENT(IdHdr, ID_MODELLOADER);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -60,28 +60,21 @@ Element_ptr FGModelLoader::Open(Element *el)
|
|||
|
||||
if (!fname.empty()) {
|
||||
FGXMLFileRead XMLFileRead;
|
||||
string file;
|
||||
SGPath path(SGPath::fromLocal8Bit(fname.c_str()));
|
||||
|
||||
try {
|
||||
file = model->FindFullPathName(fname);
|
||||
if (file.empty()) throw string("File does not exist.");
|
||||
}
|
||||
catch(string& e) {
|
||||
cerr << endl << el->ReadFrom()
|
||||
<< "Could not open file: " << fname << endl << e << endl;
|
||||
return NULL;
|
||||
}
|
||||
if (path.isRelative())
|
||||
path = model->FindFullPathName(path);
|
||||
|
||||
if (CachedFiles.find(file) != CachedFiles.end())
|
||||
document = CachedFiles[file];
|
||||
if (CachedFiles.find(path.utf8Str()) != CachedFiles.end())
|
||||
document = CachedFiles[path.utf8Str()];
|
||||
else {
|
||||
document = XMLFileRead.LoadXMLDocument(file);
|
||||
document = XMLFileRead.LoadXMLDocument(path);
|
||||
if (document == 0L) {
|
||||
cerr << endl << el->ReadFrom()
|
||||
<< "Could not open file: " << file << endl;
|
||||
<< "Could not open file: " << path << endl;
|
||||
return NULL;
|
||||
}
|
||||
CachedFiles[file] = document;
|
||||
CachedFiles[path.utf8Str()] = document;
|
||||
}
|
||||
|
||||
if (document->GetName() != el->GetName()) {
|
||||
|
@ -93,19 +86,12 @@ Element_ptr FGModelLoader::Open(Element *el)
|
|||
return document;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
SGPath CheckPathName(const SGPath& path, const SGPath& filename) {
|
||||
SGPath fullName = path/filename.utf8Str();
|
||||
|
||||
string CheckFullPathName(const string& path, const string& fname)
|
||||
{
|
||||
string name = path + "/" + fname;
|
||||
if (fullName.extension() != "xml")
|
||||
fullName.concat(".xml");
|
||||
|
||||
if (name.length() <=4 || name.substr(name.length()-4, 4) != ".xml")
|
||||
name.append(".xml");
|
||||
|
||||
ifstream file(name.c_str());
|
||||
if (!file.is_open())
|
||||
return string();
|
||||
|
||||
return name;
|
||||
return fullName.exists() ? fullName : SGPath();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,12 +41,13 @@ INCLUDES
|
|||
#include <string>
|
||||
|
||||
#include "FGXMLElement.h"
|
||||
#include "simgear/misc/sg_path.hxx"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_MODELLOADER "$Id: FGModelLoader.h,v 1.1 2014/06/09 11:52:06 bcoconni Exp $"
|
||||
#define ID_MODELLOADER "$Id: FGModelLoader.h,v 1.2 2017/02/25 14:23:18 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -75,7 +76,7 @@ private:
|
|||
std::map<std::string, Element_ptr> CachedFiles;
|
||||
};
|
||||
|
||||
std::string CheckFullPathName(const std::string& path, const std::string& fname);
|
||||
SGPath CheckPathName(const SGPath& path, const SGPath& filename);
|
||||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#endif
|
||||
|
|
|
@ -47,7 +47,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGOutputFile.cpp,v 1.9 2014/05/04 17:00:27 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGOutputFile.cpp,v 1.10 2017/02/25 14:23:18 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_OUTPUTFILE);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -65,8 +65,8 @@ FGOutputFile::FGOutputFile(FGFDMExec* fdmex) :
|
|||
bool FGOutputFile::InitModel(void)
|
||||
{
|
||||
if (FGOutputType::InitModel()) {
|
||||
if (Filename.empty()) {
|
||||
Filename = Name;
|
||||
if (Filename.isNull()) {
|
||||
Filename = SGPath(Name);
|
||||
runID_postfix = 0;
|
||||
}
|
||||
return OpenFile();
|
||||
|
@ -87,7 +87,7 @@ void FGOutputFile::SetStartNewOutput(void)
|
|||
} else {
|
||||
buf << Name << '_' << runID_postfix++;
|
||||
}
|
||||
Filename = buf.str();
|
||||
Filename = SGPath(buf.str());
|
||||
}
|
||||
|
||||
CloseFile();
|
||||
|
|
|
@ -45,7 +45,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_OUTPUTFILE "$Id: FGOutputFile.h,v 1.6 2014/05/04 17:00:27 bcoconni Exp $"
|
||||
#define ID_OUTPUTFILE "$Id: FGOutputFile.h,v 1.8 2017/02/25 14:23:18 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -106,9 +106,9 @@ public:
|
|||
the next call to SetStartNewOutput().
|
||||
@param name new name */
|
||||
void SetOutputName(const std::string& fname) {
|
||||
Name = FDMExec->GetRootDir() + fname;
|
||||
Name = (FDMExec->GetRootDir()/fname).utf8Str();
|
||||
runID_postfix = -1;
|
||||
Filename = std::string();
|
||||
Filename = SGPath();
|
||||
}
|
||||
/** Generate the output. This is a pure method so it must be implemented by
|
||||
the classes that inherits from FGOutputFile.
|
||||
|
@ -116,7 +116,7 @@ public:
|
|||
void Print(void) = 0;
|
||||
|
||||
protected:
|
||||
std::string Filename;
|
||||
SGPath Filename;
|
||||
|
||||
/// Opens the file
|
||||
virtual bool OpenFile(void) = 0;
|
||||
|
|
|
@ -64,7 +64,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGOutputTextFile.cpp,v 1.12 2016/05/22 10:28:23 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGOutputTextFile.cpp,v 1.13 2017/02/25 14:23:18 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_OUTPUTTEXTFILE);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -96,7 +96,7 @@ bool FGOutputTextFile::Load(Element* el)
|
|||
bool FGOutputTextFile::OpenFile(void)
|
||||
{
|
||||
datafile.clear();
|
||||
datafile.open(Filename.c_str());
|
||||
datafile.open(Filename);
|
||||
if (!datafile) {
|
||||
cerr << endl << fgred << highint << "ERROR: unable to open the file "
|
||||
<< reset << Filename.c_str() << endl
|
||||
|
@ -261,9 +261,9 @@ bool FGOutputTextFile::OpenFile(void)
|
|||
void FGOutputTextFile::Print(void)
|
||||
{
|
||||
streambuf* buffer;
|
||||
string scratch = "";
|
||||
string scratch = Filename.utf8Str();
|
||||
|
||||
if (Filename == "COUT" || Filename == "cout") {
|
||||
if (to_upper(scratch) == "COUT") {
|
||||
buffer = cout.rdbuf();
|
||||
} else {
|
||||
buffer = datafile.rdbuf();
|
||||
|
|
|
@ -41,12 +41,13 @@ INCLUDES
|
|||
#include <fstream>
|
||||
|
||||
#include "FGOutputFile.h"
|
||||
#include "simgear/io/iostreams/sgstream.hxx"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_OUTPUTTEXTFILE "$Id: FGOutputTextFile.h,v 1.4 2012/12/15 16:13:58 bcoconni Exp $"
|
||||
#define ID_OUTPUTTEXTFILE "$Id: FGOutputTextFile.h,v 1.5 2017/02/25 14:23:18 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -89,7 +90,7 @@ public:
|
|||
|
||||
protected:
|
||||
std::string delimeter;
|
||||
std::ofstream datafile;
|
||||
sg_ofstream datafile;
|
||||
|
||||
virtual bool OpenFile(void);
|
||||
virtual void CloseFile(void) { if (datafile.is_open()) datafile.close(); }
|
||||
|
|
|
@ -58,7 +58,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGScript.cpp,v 1.64 2016/04/03 17:10:46 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGScript.cpp,v 1.65 2017/02/25 14:23:18 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_FGSCRIPT);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -96,10 +96,11 @@ FGScript::~FGScript()
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGScript::LoadScript(const string& script, double default_dT,
|
||||
const string& initfile)
|
||||
bool FGScript::LoadScript(const SGPath& script, double default_dT,
|
||||
const SGPath& initfile)
|
||||
{
|
||||
string aircraft="", initialize="", prop_name="";
|
||||
SGPath initialize;
|
||||
string aircraft="", prop_name="";
|
||||
string notifyPropertyName="";
|
||||
Element *element=0, *run_element=0, *event_element=0;
|
||||
Element *set_element=0;
|
||||
|
@ -171,9 +172,9 @@ bool FGScript::LoadScript(const string& script, double default_dT,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (initfile.empty()) {
|
||||
initialize = element->GetAttributeValue("initialize");
|
||||
if (initialize.empty()) {
|
||||
initialize = SGPath::fromLocal8Bit(element->GetAttributeValue("initialize").c_str());
|
||||
if (initfile.isNull()) {
|
||||
if (initialize.isNull()) {
|
||||
cerr << "Initialization file must be specified in use element." << endl;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -43,12 +43,13 @@ INCLUDES
|
|||
#include "FGJSBBase.h"
|
||||
#include "FGPropertyReader.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
#include "simgear/misc/sg_path.hxx"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_FGSCRIPT "$Id: FGScript.h,v 1.30 2015/09/20 16:32:11 bcoconni Exp $"
|
||||
#define ID_FGSCRIPT "$Id: FGScript.h,v 1.31 2017/02/25 14:23:18 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -161,7 +162,7 @@ CLASS DOCUMENTATION
|
|||
comes the "run" section, where the conditions are
|
||||
described in "event" clauses.</p>
|
||||
@author Jon S. Berndt
|
||||
@version "$Id: FGScript.h,v 1.30 2015/09/20 16:32:11 bcoconni Exp $"
|
||||
@version "$Id: FGScript.h,v 1.31 2017/02/25 14:23:18 bcoconni Exp $"
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -188,8 +189,8 @@ public:
|
|||
default. If a file name is passed in, it will override the
|
||||
one present in the script.
|
||||
@return true if successful */
|
||||
bool LoadScript(const std::string& script, double default_dT,
|
||||
const std::string& initfile);
|
||||
bool LoadScript(const SGPath& script, double default_dT,
|
||||
const SGPath& initfile);
|
||||
|
||||
/** This function is called each pass through the executive Run() method IF
|
||||
scripting is enabled.
|
||||
|
|
|
@ -45,7 +45,7 @@ FORWARD DECLARATIONS
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGXMLElement.cpp,v 1.55 2016/01/02 15:23:50 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGXMLElement.cpp,v 1.56 2016/09/11 11:26:04 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_XMLELEMENT);
|
||||
|
||||
bool Element::converterIsInitialized = false;
|
||||
|
@ -467,12 +467,14 @@ double Element::FindElementValueAsNumberConvertTo(const string& el, const string
|
|||
|
||||
// Sanity check for angular values
|
||||
if ((supplied_units == "RAD") && (fabs(value) > 2 * M_PI)) {
|
||||
cerr << element->ReadFrom() << "The value " << value
|
||||
<< " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]" << endl;
|
||||
cerr << element->ReadFrom() << element->GetName() << " value "
|
||||
<< value << " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]"
|
||||
<< endl;
|
||||
}
|
||||
if ((supplied_units == "DEG") && (fabs(value) > 360.0)) {
|
||||
cerr << element->ReadFrom() << "The value " << value
|
||||
<< " DEG is outside the range [ -360 DEG ; +360 DEG ]" << endl;
|
||||
cerr << element->ReadFrom() << element->GetName() << " value "
|
||||
<< value << " DEG is outside the range [ -360 DEG ; +360 DEG ]"
|
||||
<< endl;
|
||||
}
|
||||
|
||||
|
||||
|
@ -481,12 +483,14 @@ double Element::FindElementValueAsNumberConvertTo(const string& el, const string
|
|||
}
|
||||
|
||||
if ((target_units == "RAD") && (fabs(value) > 2 * M_PI)) {
|
||||
cerr << element->ReadFrom() << "The value " << value
|
||||
<< " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]" << endl;
|
||||
cerr << element->ReadFrom() << element->GetName() << " value "
|
||||
<< value << " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]"
|
||||
<< endl;
|
||||
}
|
||||
if ((target_units == "DEG") && (fabs(value) > 360.0)) {
|
||||
cerr << element->ReadFrom() << "The value " << value
|
||||
<< " DEG is outside the range [ -360 DEG ; +360 DEG ]" << endl;
|
||||
cerr << element->ReadFrom() << element->GetName() << " value "
|
||||
<< value << " DEG is outside the range [ -360 DEG ; +360 DEG ]"
|
||||
<< endl;
|
||||
}
|
||||
|
||||
value = DisperseValue(element, value, supplied_units, target_units);
|
||||
|
|
|
@ -35,15 +35,18 @@ SENTRY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "input_output/FGXMLParse.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "input_output/FGXMLParse.h"
|
||||
#include "simgear/misc/sg_path.hxx"
|
||||
#include "simgear/io/iostreams/sgstream.hxx"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_XMLFILEREAD "$Id: FGXMLFileRead.h,v 1.9 2013/12/01 14:33:51 bcoconni Exp $"
|
||||
#define ID_XMLFILEREAD "$Id: FGXMLFileRead.h,v 1.10 2017/02/25 14:23:18 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -56,20 +59,23 @@ public:
|
|||
FGXMLFileRead(void) {}
|
||||
~FGXMLFileRead(void) {}
|
||||
|
||||
Element* LoadXMLDocument(std::string XML_filename, bool verbose=true)
|
||||
Element* LoadXMLDocument(const SGPath& XML_filename, bool verbose=true)
|
||||
{
|
||||
return LoadXMLDocument(XML_filename, file_parser, verbose);
|
||||
}
|
||||
|
||||
Element* LoadXMLDocument(std::string XML_filename, FGXMLParse& fparse, bool verbose=true)
|
||||
Element* LoadXMLDocument(const SGPath& XML_filename, FGXMLParse& fparse, bool verbose=true)
|
||||
{
|
||||
std::ifstream infile;
|
||||
sg_ifstream infile;
|
||||
SGPath filename(XML_filename);
|
||||
|
||||
if ( !XML_filename.empty() ) {
|
||||
if (XML_filename.find(".xml") == std::string::npos) XML_filename += ".xml";
|
||||
infile.open(XML_filename.c_str());
|
||||
if (!filename.isNull()) {
|
||||
if (filename.extension().empty())
|
||||
filename.concat(".xml");
|
||||
|
||||
infile.open(filename);
|
||||
if ( !infile.is_open()) {
|
||||
if (verbose) std::cerr << "Could not open file: " << XML_filename << std::endl;
|
||||
if (verbose) std::cerr << "Could not open file: " << filename << std::endl;
|
||||
return 0L;
|
||||
}
|
||||
} else {
|
||||
|
@ -77,7 +83,7 @@ public:
|
|||
return 0L;
|
||||
}
|
||||
|
||||
readXML(infile, fparse, XML_filename);
|
||||
readXML(infile, fparse, filename.utf8Str());
|
||||
Element* document = fparse.GetDocument();
|
||||
infile.close();
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ using std::string;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGfdmSocket.cpp,v 1.31 2015/03/22 12:19:31 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGfdmSocket.cpp,v 1.32 2017/03/11 12:12:12 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_FDMSOCKET);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -93,9 +93,9 @@ FGfdmSocket::FGfdmSocket(const string& address, int port, int protocol)
|
|||
cout << "Could not get host net address by name..." << endl;
|
||||
}
|
||||
} else {
|
||||
unsigned int ip;
|
||||
unsigned long ip;
|
||||
ip = inet_addr(address.c_str());
|
||||
if ((host = gethostbyaddr((char*)&ip, address.size(), PF_INET)) == NULL) {
|
||||
if ((host = gethostbyaddr((char*)&ip, sizeof(ip), PF_INET)) == NULL) {
|
||||
cout << "Could not get host net address by number..." << endl;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,6 +104,8 @@ bool FGAccelerations::InitModel(void)
|
|||
vGravAccel.InitMatrix();
|
||||
vBodyAccel.InitMatrix();
|
||||
|
||||
maxiter = 50;
|
||||
matrixSize = iter = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -255,6 +257,7 @@ void FGAccelerations::ResolveFrictionForces(double dt)
|
|||
FGColumnVector3 vdot, wdot;
|
||||
vector<LagrangeMultiplier*>& multipliers = *in.MultipliersList;
|
||||
size_t n = multipliers.size();
|
||||
matrixSize = n;
|
||||
|
||||
vFrictionForces.InitMatrix();
|
||||
vFrictionMoments.InitMatrix();
|
||||
|
@ -303,7 +306,7 @@ void FGAccelerations::ResolveFrictionForces(double dt)
|
|||
}
|
||||
|
||||
// Resolve the Lagrange multipliers with the projected Gauss-Seidel method
|
||||
for (int iter=0; iter < 50; iter++) {
|
||||
for (iter=0; iter < maxiter; iter = iter+1) {
|
||||
double norm = 0.;
|
||||
|
||||
for (unsigned int i=0; i < n; i++) {
|
||||
|
@ -384,6 +387,10 @@ void FGAccelerations::bind(void)
|
|||
PropertyManager->Tie("forces/fbx-gear-lbs", this, eX, (PMF)&FGAccelerations::GetGroundForces);
|
||||
PropertyManager->Tie("forces/fby-gear-lbs", this, eY, (PMF)&FGAccelerations::GetGroundForces);
|
||||
PropertyManager->Tie("forces/fbz-gear-lbs", this, eZ, (PMF)&FGAccelerations::GetGroundForces);
|
||||
|
||||
iter = PropertyManager->CreatePropertyObject<int>("numerical/friction-resolver/iterations");
|
||||
maxiter = PropertyManager->CreatePropertyObject<int>("numerical/friction-resolver/max-iterations");
|
||||
matrixSize = PropertyManager->CreatePropertyObject<int>("numerical/friction-resolver/matrix-size");
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -40,6 +40,7 @@ INCLUDES
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "simgear/props/propertyObject.hxx"
|
||||
#include "models/FGModel.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
#include "math/LagrangeMultiplier.h"
|
||||
|
@ -391,6 +392,7 @@ private:
|
|||
FGColumnVector3 vGravAccel;
|
||||
FGColumnVector3 vFrictionForces;
|
||||
FGColumnVector3 vFrictionMoments;
|
||||
simgear::PropertyObject<int> iter, maxiter, matrixSize;
|
||||
|
||||
int gravType;
|
||||
bool gravTorque;
|
||||
|
|
|
@ -70,7 +70,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGFCS.cpp,v 1.95 2016/05/16 18:19:57 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGFCS.cpp,v 1.98 2017/02/25 14:23:18 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_FCS);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -602,16 +602,15 @@ double FGFCS::GetBrake(FGLGear::BrakeGroup bg)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGFCS::FindFullPathName(const string& sysfilename) const
|
||||
SGPath FGFCS::FindFullPathName(const SGPath& path) const
|
||||
{
|
||||
string name = FGModel::FindFullPathName(sysfilename);
|
||||
SGPath name = FGModel::FindFullPathName(path);
|
||||
if (systype != stSystem || !name.isNull()) return name;
|
||||
|
||||
if (systype != stSystem || !name.empty()) return name;
|
||||
name = CheckPathName(FDMExec->GetFullAircraftPath()/string("Systems"), path);
|
||||
if (!name.isNull()) return name;
|
||||
|
||||
name = CheckFullPathName(FDMExec->GetFullAircraftPath() + "/Systems", sysfilename);
|
||||
if (!name.empty()) return name;
|
||||
|
||||
return CheckFullPathName(FDMExec->GetSystemsPath(), sysfilename);
|
||||
return CheckPathName(FDMExec->GetSystemsPath(), path);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -50,7 +50,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_FCS "$Id: FGFCS.h,v 1.53 2016/05/18 08:06:57 ehofman Exp $"
|
||||
#define ID_FCS "$Id: FGFCS.h,v 1.55 2017/03/03 23:03:20 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -168,7 +168,7 @@ CLASS DOCUMENTATION
|
|||
@property gear/tailhook-pos-norm
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision: 1.53 $
|
||||
@version $Revision: 1.55 $
|
||||
@see FGActuator
|
||||
@see FGDeadBand
|
||||
@see FGFCSFunction
|
||||
|
@ -430,7 +430,7 @@ public:
|
|||
|
||||
/** Sets the propeller pitch command for the specified engine
|
||||
@param engine engine ID number
|
||||
@param cmd mixture command in percent (0.0 - 1.0)*/
|
||||
@param cmd pitch command in percent (0.0 - 1.0)*/
|
||||
void SetPropAdvanceCmd(int engine, double cmd);
|
||||
|
||||
/** Sets the propeller feather command for the specified engine
|
||||
|
@ -544,7 +544,7 @@ public:
|
|||
@return true if succesful */
|
||||
bool Load(Element* el);
|
||||
|
||||
std::string FindFullPathName(const std::string& system_filename) const;
|
||||
SGPath FindFullPathName(const SGPath& path) const;
|
||||
|
||||
void AddThrottle(void);
|
||||
double GetDt(void) const;
|
||||
|
|
|
@ -50,7 +50,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGInput.cpp,v 1.34 2015/08/23 09:43:31 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGInput.cpp,v 1.35 2017/02/25 14:23:19 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_INPUT);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -153,7 +153,7 @@ bool FGInput::Run(bool Holding)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGInput::SetDirectivesFile(const std::string& fname)
|
||||
bool FGInput::SetDirectivesFile(const SGPath& fname)
|
||||
{
|
||||
FGXMLFileRead XMLFile;
|
||||
Element* document = XMLFile.LoadXMLDocument(fname);
|
||||
|
|
|
@ -46,7 +46,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_INPUT "$Id: FGInput.h,v 1.13 2015/08/23 09:43:31 bcoconni Exp $"
|
||||
#define ID_INPUT "$Id: FGInput.h,v 1.14 2017/02/25 14:23:19 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -81,7 +81,7 @@ CLASS DOCUMENTATION
|
|||
|
||||
The class FGInput is the manager of the inputs requested by the user. It
|
||||
manages a list of instances derived from the abstract class FGInputType.
|
||||
@version $Id: FGInput.h,v 1.13 2015/08/23 09:43:31 bcoconni Exp $
|
||||
@version $Id: FGInput.h,v 1.14 2017/02/25 14:23:19 bcoconni Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -122,7 +122,7 @@ public:
|
|||
@param fname the name of the file from which the ouput directives should
|
||||
be read.
|
||||
@return true if the execution succeeded. */
|
||||
bool SetDirectivesFile(const std::string& fname);
|
||||
bool SetDirectivesFile(const SGPath& fname);
|
||||
|
||||
/// Enables the input generation for all input instances.
|
||||
void Enable(void) { enabled = true; }
|
||||
|
|
|
@ -61,7 +61,7 @@ DEFINITIONS
|
|||
GLOBAL DATA
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
IDENT(IdSrc,"$Id: FGLGear.cpp,v 1.124 2016/06/25 17:48:02 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGLGear.cpp,v 1.125 2017/02/21 21:14:13 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_LGEAR);
|
||||
|
||||
// Body To Structural (body frame is rotated 180 deg about Y and lengths are given in
|
||||
|
@ -784,9 +784,15 @@ void FGLGear::bind(void)
|
|||
|
||||
property_name = base_property_name + "/WOW";
|
||||
PropertyManager->Tie( property_name.c_str(), &WOW );
|
||||
property_name = base_property_name + "/x-position";
|
||||
PropertyManager->Tie( property_name.c_str(), (FGForce*)this,
|
||||
&FGForce::GetLocationX, &FGForce::SetLocationX);
|
||||
property_name = base_property_name + "/y-position";
|
||||
PropertyManager->Tie( property_name.c_str(), (FGForce*)this,
|
||||
&FGForce::GetLocationY, &FGForce::SetLocationY);
|
||||
property_name = base_property_name + "/z-position";
|
||||
PropertyManager->Tie( property_name.c_str(), (FGForce*)this,
|
||||
&FGForce::GetLocationZ, &FGForce::SetLocationZ);
|
||||
&FGForce::GetLocationZ, &FGForce::SetLocationZ);
|
||||
property_name = base_property_name + "/compression-ft";
|
||||
PropertyManager->Tie( property_name.c_str(), &compressLength );
|
||||
property_name = base_property_name + "/compression-velocity-fps";
|
||||
|
|
|
@ -49,7 +49,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_LGEAR "$Id: FGLGear.h,v 1.65 2016/05/16 18:19:57 bcoconni Exp $"
|
||||
#define ID_LGEAR "$Id: FGLGear.h,v 1.66 2017/03/11 12:07:22 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -178,7 +178,7 @@ CLASS DOCUMENTATION
|
|||
</contact>
|
||||
@endcode
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGLGear.h,v 1.65 2016/05/16 18:19:57 bcoconni Exp $
|
||||
@version $Id: FGLGear.h,v 1.66 2017/03/11 12:07:22 bcoconni Exp $
|
||||
@see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
|
||||
NASA-Ames", NASA CR-2497, January 1975
|
||||
@see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
|
||||
|
@ -273,7 +273,9 @@ public:
|
|||
/** Get the console touchdown reporting feature
|
||||
@return true if reporting is turned on */
|
||||
bool GetReport(void) const { return ReportEnable; }
|
||||
double GetSteerNorm(void) const { return radtodeg/maxSteerAngle*SteerAngle; }
|
||||
double GetSteerNorm(void) const {
|
||||
return maxSteerAngle == 0.0 ? 0.0 : radtodeg/maxSteerAngle*SteerAngle;
|
||||
}
|
||||
void SetSteerCmd(double cmd) { SetSteerAngleDeg(cmd * maxSteerAngle); }
|
||||
double GetstaticFCoeff(void) const { return staticFCoeff; }
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGModel.cpp,v 1.26 2015/07/12 19:34:08 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGModel.cpp,v 1.27 2017/02/25 14:23:19 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_MODEL);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -103,9 +103,9 @@ bool FGModel::Run(bool Holding)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGModel::FindFullPathName(const string& fname) const
|
||||
SGPath FGModel::FindFullPathName(const SGPath& path) const
|
||||
{
|
||||
return CheckFullPathName(FDMExec->GetFullAircraftPath(), fname);
|
||||
return CheckPathName(FDMExec->GetFullAircraftPath(), path);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -41,12 +41,13 @@ INCLUDES
|
|||
#include <string>
|
||||
|
||||
#include "math/FGModelFunctions.h"
|
||||
#include "simgear/misc/sg_path.hxx"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_MODEL "$Id: FGModel.h,v 1.25 2015/08/16 13:19:52 bcoconni Exp $"
|
||||
#define ID_MODEL "$Id: FGModel.h,v 1.26 2017/02/25 14:23:19 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -100,7 +101,7 @@ public:
|
|||
FGFDMExec* GetExec(void) {return FDMExec;}
|
||||
|
||||
void SetPropertyManager(FGPropertyManager *fgpm) { PropertyManager=fgpm;}
|
||||
virtual std::string FindFullPathName(const std::string& filename) const;
|
||||
virtual SGPath FindFullPathName(const SGPath& path) const;
|
||||
|
||||
protected:
|
||||
unsigned int exe_ctr;
|
||||
|
@ -119,4 +120,3 @@ protected:
|
|||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#endif
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGOutput.cpp,v 1.86 2015/08/23 09:43:31 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGOutput.cpp,v 1.87 2017/02/25 14:23:19 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_OUTPUT);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -182,7 +182,7 @@ string FGOutput::GetOutputName(unsigned int idx) const
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGOutput::SetDirectivesFile(const std::string& fname)
|
||||
bool FGOutput::SetDirectivesFile(const SGPath& fname)
|
||||
{
|
||||
FGXMLFileRead XMLFile;
|
||||
Element* document = XMLFile.LoadXMLDocument(fname);
|
||||
|
|
|
@ -47,7 +47,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_OUTPUT "$Id: FGOutput.h,v 1.33 2015/08/23 09:43:31 bcoconni Exp $"
|
||||
#define ID_OUTPUT "$Id: FGOutput.h,v 1.34 2017/02/25 14:23:19 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -121,7 +121,7 @@ CLASS DOCUMENTATION
|
|||
|
||||
The class FGOutput is the manager of the outputs requested by the user. It
|
||||
manages a list of instances derived from the abstract class FGOutputType.
|
||||
@version $Id: FGOutput.h,v 1.33 2015/08/23 09:43:31 bcoconni Exp $
|
||||
@version $Id: FGOutput.h,v 1.34 2017/02/25 14:23:19 bcoconni Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -181,7 +181,7 @@ public:
|
|||
@param fname the name of the file from which the ouput directives should
|
||||
be read.
|
||||
@return true if the execution succeeded. */
|
||||
bool SetDirectivesFile(const std::string& fname);
|
||||
bool SetDirectivesFile(const SGPath& fname);
|
||||
/// Enables the output generation for all output instances.
|
||||
void Enable(void) { enabled = true; }
|
||||
/// Disables the output generation for all output instances.
|
||||
|
|
|
@ -67,19 +67,19 @@ INCLUDES
|
|||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
|
||||
#include "initialization/FGInitialCondition.h"
|
||||
#include "FGPropagate.h"
|
||||
#include "FGGroundReactions.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
#include "simgear/io/iostreams/sgstream.hxx"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGPropagate.cpp,v 1.131 2016/05/01 18:25:57 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGPropagate.cpp,v 1.132 2017/02/25 14:23:19 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_PROPAGATE);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -659,21 +659,21 @@ void FGPropagate::DumpState(void)
|
|||
|
||||
void FGPropagate::WriteStateFile(int num)
|
||||
{
|
||||
ofstream outfile;
|
||||
sg_ofstream outfile;
|
||||
|
||||
if (num == 0) return;
|
||||
|
||||
string filename = FDMExec->GetFullAircraftPath();
|
||||
SGPath path = FDMExec->GetFullAircraftPath();
|
||||
|
||||
if (filename.empty()) filename = "initfile.";
|
||||
else filename.append("/initfile.");
|
||||
if (path.isNull()) path = SGPath("initfile.");
|
||||
else path.append("initfile.");
|
||||
|
||||
// Append sim time to the filename since there may be more than one created during a simulation run
|
||||
filename += to_string((double)FDMExec->GetSimTime())+".xml";
|
||||
path.concat(to_string((double)FDMExec->GetSimTime())+".xml");
|
||||
|
||||
switch(num) {
|
||||
case 1:
|
||||
outfile.open(filename.c_str());
|
||||
outfile.open(path);
|
||||
if (outfile.is_open()) {
|
||||
outfile << "<?xml version=\"1.0\"?>" << endl;
|
||||
outfile << "<initialize name=\"reset00\">" << endl;
|
||||
|
@ -689,11 +689,12 @@ void FGPropagate::WriteStateFile(int num)
|
|||
outfile << "</initialize>" << endl;
|
||||
outfile.close();
|
||||
} else {
|
||||
cerr << "Could not open and/or write the state to the initial conditions file: " << filename << endl;
|
||||
cerr << "Could not open and/or write the state to the initial conditions file: "
|
||||
<< path << endl;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
outfile.open(filename.c_str());
|
||||
outfile.open(path);
|
||||
if (outfile.is_open()) {
|
||||
outfile << "<?xml version=\"1.0\"?>" << endl;
|
||||
outfile << "<initialize name=\"IC File\" version=\"2.0\">" << endl;
|
||||
|
@ -725,7 +726,8 @@ void FGPropagate::WriteStateFile(int num)
|
|||
outfile << "</initialize>" << endl;
|
||||
outfile.close();
|
||||
} else {
|
||||
cerr << "Could not open and/or write the state to the initial conditions file: " << filename << endl;
|
||||
cerr << "Could not open and/or write the state to the initial conditions file: "
|
||||
<< path << endl;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -65,7 +65,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGPropulsion.cpp,v 1.87 2016/05/05 15:38:09 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGPropulsion.cpp,v 1.88 2017/02/25 14:23:19 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_PROPULSION);
|
||||
|
||||
extern short debug_lvl;
|
||||
|
@ -463,14 +463,15 @@ bool FGPropulsion::Load(Element* el)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGPropulsion::FindFullPathName(const string& filename) const
|
||||
SGPath FGPropulsion::FindFullPathName(const SGPath& path) const
|
||||
{
|
||||
if (!ReadingEngine) return FGModel::FindFullPathName(filename);
|
||||
if (!ReadingEngine) return FGModel::FindFullPathName(path);
|
||||
|
||||
string name = CheckFullPathName(FDMExec->GetFullAircraftPath() + "/Engines", filename);
|
||||
if (!name.empty()) return name;
|
||||
SGPath name = CheckPathName(FDMExec->GetFullAircraftPath()/string("Engines"),
|
||||
path);
|
||||
if (!name.isNull()) return name;
|
||||
|
||||
return CheckFullPathName(FDMExec->GetEnginePath(), filename);
|
||||
return CheckPathName(FDMExec->GetEnginePath(), path);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -50,7 +50,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_PROPULSION "$Id: FGPropulsion.h,v 1.36 2016/05/05 15:38:08 bcoconni Exp $"
|
||||
#define ID_PROPULSION "$Id: FGPropulsion.h,v 1.37 2017/02/25 14:23:19 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -93,7 +93,7 @@ CLASS DOCUMENTATION
|
|||
@endcode
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGPropulsion.h,v 1.36 2016/05/05 15:38:08 bcoconni Exp $
|
||||
@version $Id: FGPropulsion.h,v 1.37 2017/02/25 14:23:19 bcoconni Exp $
|
||||
@see
|
||||
FGEngine
|
||||
FGTank
|
||||
|
@ -180,7 +180,7 @@ public:
|
|||
const FGColumnVector3& GetTanksMoment(void);
|
||||
double GetTanksWeight(void) const;
|
||||
|
||||
std::string FindFullPathName(const std::string& filename) const;
|
||||
SGPath FindFullPathName(const SGPath& path) const;
|
||||
inline int GetActiveEngine(void) const {return ActiveEngine;}
|
||||
inline bool GetFuelFreeze(void) const {return FuelFreeze;}
|
||||
|
||||
|
|
0
src/FDM/JSBSim/models/flight_control/FGAngles.cpp
Executable file → Normal file
0
src/FDM/JSBSim/models/flight_control/FGAngles.cpp
Executable file → Normal file
|
@ -53,7 +53,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGEngine.cpp,v 1.67 2015/09/27 09:54:21 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGEngine.cpp,v 1.68 2017/03/03 23:00:39 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_ENGINE);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -158,7 +158,7 @@ void FGEngine::LoadThrusterInputs()
|
|||
{
|
||||
Thruster->in.TotalDeltaT = in.TotalDeltaT;
|
||||
Thruster->in.H_agl = in.H_agl;
|
||||
Thruster->in.PQR = in.PQR;
|
||||
Thruster->in.PQRi = in.PQRi;
|
||||
Thruster->in.AeroPQR = in.AeroPQR;
|
||||
Thruster->in.AeroUVW = in.AeroUVW;
|
||||
Thruster->in.Density = in.Density;
|
||||
|
|
|
@ -53,7 +53,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_ENGINE "$Id: FGEngine.h,v 1.47 2015/09/27 10:16:57 bcoconni Exp $"
|
||||
#define ID_ENGINE "$Id: FGEngine.h,v 1.48 2017/03/03 23:00:39 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -111,7 +111,7 @@ CLASS DOCUMENTATION
|
|||
documentation for engine and thruster classes.
|
||||
</pre>
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGEngine.h,v 1.47 2015/09/27 10:16:57 bcoconni Exp $
|
||||
@version $Id: FGEngine.h,v 1.48 2017/03/03 23:00:39 bcoconni Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -138,7 +138,7 @@ public:
|
|||
double H_agl;
|
||||
FGColumnVector3 AeroUVW;
|
||||
FGColumnVector3 AeroPQR;
|
||||
FGColumnVector3 PQR;
|
||||
FGColumnVector3 PQRi;
|
||||
std::vector <double> ThrottleCmd;
|
||||
std::vector <double> MixtureCmd;
|
||||
std::vector <double> ThrottlePos;
|
||||
|
|
|
@ -45,7 +45,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGPropeller.cpp,v 1.58 2016/06/04 11:06:51 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGPropeller.cpp,v 1.60 2017/03/03 23:00:39 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_PROPELLER);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -80,8 +80,8 @@ FGPropeller::FGPropeller(FGFDMExec* exec, Element* prop_element, int num)
|
|||
Ixx = max(prop_element->FindElementValueAsNumberConvertTo("ixx", "SLUG*FT2"), 0.001);
|
||||
|
||||
Sense_multiplier = 1.0;
|
||||
if (prop_element->HasAttribute("version"))
|
||||
if (prop_element->GetAttributeValueAsNumber("version") > 1.0)
|
||||
if (prop_element->HasAttribute("version")
|
||||
&& prop_element->GetAttributeValueAsNumber("version") > 1.0)
|
||||
Sense_multiplier = -1.0;
|
||||
|
||||
if (prop_element->FindElement("diameter"))
|
||||
|
@ -146,6 +146,7 @@ FGPropeller::FGPropeller(FGFDMExec* exec, Element* prop_element, int num)
|
|||
Type = ttPropeller;
|
||||
RPM = 0;
|
||||
vTorque.InitMatrix();
|
||||
vH.InitMatrix();
|
||||
D4 = Diameter*Diameter*Diameter*Diameter;
|
||||
D5 = D4*Diameter;
|
||||
Pitch = MinPitch;
|
||||
|
@ -186,6 +187,14 @@ FGPropeller::~FGPropeller()
|
|||
Debug(1);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPropeller::ResetToIC(void)
|
||||
{
|
||||
FGThruster::ResetToIC();
|
||||
Vinduced = 0.0;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// We must be getting the aerodynamic velocity here, NOT the inertial velocity.
|
||||
|
@ -211,11 +220,11 @@ double FGPropeller::Calculate(double EnginePower)
|
|||
double Vtip = RPS * Diameter * M_PI;
|
||||
HelicalTipMach = sqrt(Vtip*Vtip + Vel*Vel) / in.Soundspeed;
|
||||
|
||||
PowerAvailable = EnginePower - GetPowerRequired();
|
||||
|
||||
if (RPS > 0.0) J = Vel / (Diameter * RPS); // Calculate J normally
|
||||
else J = Vel / Diameter;
|
||||
|
||||
PowerAvailable = EnginePower - GetPowerRequired();
|
||||
|
||||
if (MaxPitch == MinPitch) { // Fixed pitch prop
|
||||
ThrustCoeff = cThrust->GetValue(J);
|
||||
} else { // Variable pitch prop
|
||||
|
@ -265,8 +274,6 @@ double FGPropeller::Calculate(double EnginePower)
|
|||
// FGForce::GetBodyForces() function.
|
||||
|
||||
vH(eX) = Ixx*omega*Sense*Sense_multiplier;
|
||||
vH(eY) = 0.0;
|
||||
vH(eZ) = 0.0;
|
||||
|
||||
if (omega > 0.0) ExcessTorque = PowerAvailable / omega;
|
||||
else ExcessTorque = PowerAvailable / 1.0;
|
||||
|
@ -277,7 +284,7 @@ double FGPropeller::Calculate(double EnginePower)
|
|||
|
||||
// Transform Torque and momentum first, as PQR is used in this
|
||||
// equation and cannot be transformed itself.
|
||||
vMn = in.PQR*(Transform()*vH) + Transform()*vTorque;
|
||||
vMn = in.PQRi*(Transform()*vH) + Transform()*vTorque;
|
||||
|
||||
return Thrust; // return thrust in pounds
|
||||
}
|
||||
|
@ -286,13 +293,7 @@ double FGPropeller::Calculate(double EnginePower)
|
|||
|
||||
double FGPropeller::GetPowerRequired(void)
|
||||
{
|
||||
double cPReq, J;
|
||||
double rho = in.Density;
|
||||
double Vel = in.AeroUVW(eU) + Vinduced;
|
||||
double RPS = RPM / 60.0;
|
||||
|
||||
if (RPS != 0.0) J = Vel / (Diameter * RPS);
|
||||
else J = Vel / Diameter;
|
||||
double cPReq;
|
||||
|
||||
if (MaxPitch == MinPitch) { // Fixed pitch prop
|
||||
cPReq = cPower->GetValue(J);
|
||||
|
@ -303,7 +304,7 @@ double FGPropeller::GetPowerRequired(void)
|
|||
|
||||
// do normal calculation when propeller is neither feathered nor reversed
|
||||
// Note: This method of feathering and reversing was added to support the
|
||||
// turboprop model. It's left here for backward compatablity, but
|
||||
// turboprop model. It's left here for backward compatiblity, but
|
||||
// now feathering and reversing should be done in Manual Pitch Mode.
|
||||
if (!Feathered) {
|
||||
if (!Reversed) {
|
||||
|
@ -349,9 +350,10 @@ double FGPropeller::GetPowerRequired(void)
|
|||
// Apply optional Mach effects from CP_MACH table
|
||||
if (CpMach) cPReq *= CpMach->GetValue(HelicalTipMach);
|
||||
|
||||
double RPS = RPM / 60.0;
|
||||
double local_RPS = RPS < 0.01 ? 0.01 : RPS;
|
||||
|
||||
PowerRequired = cPReq*local_RPS*local_RPS*local_RPS*D5*rho;
|
||||
PowerRequired = cPReq*local_RPS*local_RPS*local_RPS*D5*in.Density;
|
||||
vTorque(eX) = -Sense*PowerRequired / (local_RPS*2.0*M_PI);
|
||||
|
||||
return PowerRequired;
|
||||
|
|
|
@ -45,7 +45,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_PROPELLER "$Id: FGPropeller.h,v 1.26 2016/01/02 17:42:53 bcoconni Exp $"
|
||||
#define ID_PROPELLER "$Id: FGPropeller.h,v 1.28 2017/03/03 23:00:39 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -57,13 +57,14 @@ namespace JSBSim {
|
|||
CLASS DOCUMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/** FGPropeller models a propeller given the tabular data for Ct and Cp,
|
||||
indexed by the advance ratio "J".
|
||||
/** FGPropeller models a propeller given the tabular data for Ct (thrust) and
|
||||
Cp (power), indexed by the advance ratio "J".
|
||||
|
||||
<h3>Configuration File Format:</h3>
|
||||
@code
|
||||
### Configuration File Format
|
||||
|
||||
~~~{.xml}
|
||||
<sense> {1 | -1} </sense>
|
||||
<propeller name="{string}">
|
||||
<propeller name="{string}" version="{string}">
|
||||
<ixx> {number} </ixx>
|
||||
<diameter unit="IN"> {number} </diameter>
|
||||
<numblades> {number} </numblades>
|
||||
|
@ -102,11 +103,11 @@ CLASS DOCUMENTATION
|
|||
</tableData>
|
||||
</table>
|
||||
|
||||
|
||||
</propeller>
|
||||
@endcode
|
||||
~~~
|
||||
|
||||
### Configuration Parameters
|
||||
|
||||
<h3>Configuration Parameters:</h3>
|
||||
<pre>
|
||||
\<ixx> - Propeller rotational inertia.
|
||||
\<diameter> - Propeller disk diameter.
|
||||
|
@ -126,25 +127,40 @@ CLASS DOCUMENTATION
|
|||
\<cp_factor> - A multiplier for the coefficients of power.
|
||||
</pre>
|
||||
|
||||
Two tables are needed. One for coefficient of thrust (Ct) and one for
|
||||
coefficient of power (Cp).
|
||||
Two tables are needed. One for coefficient of thrust (Ct) and one for
|
||||
coefficient of power (Cp).
|
||||
|
||||
Two tables are optional. They apply a factor to Ct and Cp based on the
|
||||
helical tip Mach.
|
||||
<br>
|
||||
Two tables are optional. They apply a factor to Ct and Cp based on the
|
||||
helical tip Mach.
|
||||
|
||||
Several references were helpful, here:<ul>
|
||||
<li>Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
|
||||
Wiley & Sons, 1979 ISBN 0-471-03032-5</li>
|
||||
<li>Edwin Hartman, David Biermann, "The Aerodynamic Characteristics of
|
||||
Full Scale Propellers Having 2, 3, and 4 Blades of Clark Y and R.A.F. 6
|
||||
Airfoil Sections", NACA Report TN-640, 1938 (?)</li>
|
||||
<li>Various NACA Technical Notes and Reports</li>
|
||||
</ul>
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGPropeller.h,v 1.26 2016/01/02 17:42:53 bcoconni Exp $
|
||||
@see FGEngine
|
||||
@see FGThruster
|
||||
In addition to thrust, the propeller applies two moments to the aircraft:
|
||||
- The torque that tends to roll the aircraft in the direction opposite to the
|
||||
propeller rotation,
|
||||
- and the gyroscopic moment.
|
||||
|
||||
It should be noted that historically the gyroscopic moment had an incorrect
|
||||
sign. The correct sign can be obtained by specifying a **version** attribute
|
||||
higher than 1.0 to the propeller definition
|
||||
~~~.xml
|
||||
<propeller name="a_prop" version="1.1">
|
||||
<!-- propeller definition -->
|
||||
</propeller>
|
||||
~~~
|
||||
For backward compatibility, the absence of the **version** attribute will result
|
||||
in the gyroscopic moment to be computed with the legacy incorrect sign.
|
||||
|
||||
Several references were helpful, here:
|
||||
+ Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
|
||||
Wiley & Sons, 1979 ISBN 0-471-03032-5
|
||||
+ Edwin Hartman, David Biermann, "The Aerodynamic Characteristics of
|
||||
Full Scale Propellers Having 2, 3, and 4 Blades of Clark Y and R.A.F. 6
|
||||
Airfoil Sections", NACA Report TN-640, 1938 (?)
|
||||
+ Various NACA Technical Notes and Reports
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGPropeller.h,v 1.28 2017/03/03 23:00:39 bcoconni Exp $
|
||||
@see FGEngine
|
||||
@see FGThruster
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -163,15 +179,19 @@ public:
|
|||
/// Destructor for FGPropeller - deletes the FGTable objects
|
||||
~FGPropeller();
|
||||
|
||||
/// Reset the initial conditions.
|
||||
void ResetToIC(void);
|
||||
|
||||
/** Sets the Revolutions Per Minute for the propeller. Normally the propeller
|
||||
instance will calculate its own rotational velocity, given the Torque
|
||||
produced by the engine and integrating over time using the standard
|
||||
equation for rotational acceleration "a": a = Q/I , where Q is Torque and
|
||||
I is moment of inertia for the propeller.
|
||||
equation for rotational acceleration \f$a\f$: \f$a = Q/I\f$ , where
|
||||
\f$Q\f$ is Torque and \f$I\f$ is moment of inertia for the propeller.
|
||||
@param rpm the rotational velocity of the propeller */
|
||||
void SetRPM(double rpm) {RPM = rpm;}
|
||||
|
||||
/** Sets the Revolutions Per Minute for the propeller using the engine gear ratio **/
|
||||
/** Sets the Revolutions Per Minute for the propeller using the engine gear
|
||||
ratio */
|
||||
void SetEngineRPM(double rpm) {RPM = rpm/GearRatio;}
|
||||
|
||||
/// Returns true of this propeller is variable pitch
|
||||
|
@ -186,6 +206,9 @@ public:
|
|||
@param pitch the pitch of the blade in degrees. */
|
||||
void SetPitch(double pitch) {Pitch = pitch;}
|
||||
|
||||
/** Set the propeller pitch.
|
||||
@param advance the pitch command in percent (0.0 - 1.0)
|
||||
*/
|
||||
void SetAdvance(double advance) {Advance = advance;}
|
||||
|
||||
/// Sets the P-Factor constant
|
||||
|
@ -255,20 +278,35 @@ public:
|
|||
would be slowed.
|
||||
@return the thrust in pounds */
|
||||
double Calculate(double EnginePower);
|
||||
/// Retrieves the P-Factor constant
|
||||
FGColumnVector3 GetPFactor(void) const;
|
||||
/// Generate the labels for the thruster standard CSV output
|
||||
std::string GetThrusterLabels(int id, const std::string& delimeter);
|
||||
/// Generate the values for the thruster standard CSV output
|
||||
std::string GetThrusterValues(int id, const std::string& delimeter);
|
||||
|
||||
/** Set the propeller reverse pitch.
|
||||
@param c the reverse pitch command in percent (0.0 - 1.0)
|
||||
*/
|
||||
void SetReverseCoef (double c) { Reverse_coef = c; }
|
||||
/// Retrieves the reverse pitch command.
|
||||
double GetReverseCoef (void) const { return Reverse_coef; }
|
||||
/// If true, sets the propeller in reversed position.
|
||||
void SetReverse (bool r) { Reversed = r; }
|
||||
/// Returns true if the propeller is in reverse position.
|
||||
bool GetReverse (void) const { return Reversed; }
|
||||
/// If true, sets the propeller in feathered position.
|
||||
void SetFeather (bool f) { Feathered = f; }
|
||||
/// Returns true if the propeller is in feathered position.
|
||||
bool GetFeather (void) const { return Feathered; }
|
||||
/// Retrieves the thrust coefficient
|
||||
double GetThrustCoefficient(void) const {return ThrustCoeff;}
|
||||
/// Retrieves the Mach number at the propeller tips.
|
||||
double GetHelicalTipMach(void) const {return HelicalTipMach;}
|
||||
/// Returns a non-zero value if the propeller is constant speed.
|
||||
int GetConstantSpeed(void) const {return ConstantSpeed;}
|
||||
/// Set the propeller induced velocity
|
||||
void SetInducedVelocity(double Vi) {Vinduced = Vi;}
|
||||
/// Get the propeller induced velocity.
|
||||
double GetInducedVelocity(void) const {return Vinduced;}
|
||||
|
||||
private:
|
||||
|
|
|
@ -48,7 +48,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGTank.cpp,v 1.45 2016/05/05 17:23:10 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGTank.cpp,v 1.46 2017/02/21 21:07:04 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_TANK);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -465,6 +465,14 @@ void FGTank::bind(FGPropertyManager* PropertyManager)
|
|||
PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetIyy);
|
||||
property_name = base_property_name + "/local-izz-slug_ft2";
|
||||
PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetIzz);
|
||||
|
||||
property_name = base_property_name + "/x-position";
|
||||
PropertyManager->Tie(property_name.c_str(), (FGTank*)this, &FGTank::GetLocationX, &FGTank::SetLocationX);
|
||||
property_name = base_property_name + "/y-position";
|
||||
PropertyManager->Tie(property_name.c_str(), (FGTank*)this, &FGTank::GetLocationY, &FGTank::SetLocationY);
|
||||
property_name = base_property_name + "/z-position";
|
||||
PropertyManager->Tie(property_name.c_str(), (FGTank*)this, &FGTank::GetLocationZ, &FGTank::SetLocationZ);
|
||||
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -53,7 +53,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_TANK "$Id: FGTank.h,v 1.31 2015/12/09 04:28:18 jberndt Exp $"
|
||||
#define ID_TANK "$Id: FGTank.h,v 1.32 2017/02/21 21:07:04 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -283,6 +283,13 @@ public:
|
|||
double GetIyy(void) const {return Iyy;}
|
||||
double GetIzz(void) const {return Izz;}
|
||||
|
||||
inline double GetLocationX(void) const { return vXYZ(eX); }
|
||||
inline double GetLocationY(void) const { return vXYZ(eY); }
|
||||
inline double GetLocationZ(void) const { return vXYZ(eZ); }
|
||||
inline void SetLocationX(double x) { vXYZ(eX) = x; }
|
||||
inline void SetLocationY(double y) { vXYZ(eY) = y; }
|
||||
inline void SetLocationZ(double z) { vXYZ(eZ) = z; }
|
||||
|
||||
double GetStandpipe(void) const {return Standpipe;}
|
||||
|
||||
int GetPriority(void) const {return Priority;}
|
||||
|
|
|
@ -46,7 +46,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_THRUSTER "$Id: FGThruster.h,v 1.26 2015/09/27 10:03:53 bcoconni Exp $"
|
||||
#define ID_THRUSTER "$Id: FGThruster.h,v 1.27 2017/03/03 23:00:39 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -74,7 +74,7 @@ CLASS DOCUMENTATION
|
|||
1.57 (pi/2) results in no thrust at all.
|
||||
|
||||
@author Jon Berndt
|
||||
@version $Id: FGThruster.h,v 1.26 2015/09/27 10:03:53 bcoconni Exp $
|
||||
@version $Id: FGThruster.h,v 1.27 2017/03/03 23:00:39 bcoconni Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -116,7 +116,7 @@ public:
|
|||
struct Inputs {
|
||||
double TotalDeltaT;
|
||||
double H_agl;
|
||||
FGColumnVector3 PQR;
|
||||
FGColumnVector3 PQRi;
|
||||
FGColumnVector3 AeroPQR;
|
||||
FGColumnVector3 AeroUVW;
|
||||
double Density;
|
||||
|
|
11
src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp
Executable file → Normal file
11
src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp
Executable file → Normal file
|
@ -55,7 +55,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGTurboProp.cpp,v 1.35 2016/07/10 12:39:28 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGTurboProp.cpp,v 1.36 2017/02/26 11:41:28 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_TURBOPROP);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -111,8 +111,6 @@ bool FGTurboProp::Load(FGFDMExec* exec, Element *el)
|
|||
|
||||
// ToDo: Need to make sure units are properly accounted for below.
|
||||
|
||||
if (el->FindElement("milthrust"))
|
||||
MilThrust = el->FindElementValueAsNumberConvertTo("milthrust","LBS");
|
||||
if (el->FindElement("idlen1"))
|
||||
IdleN1 = el->FindElementValueAsNumber("idlen1");
|
||||
if (el->FindElement("maxn1"))
|
||||
|
@ -197,7 +195,8 @@ void FGTurboProp::Calculate(void)
|
|||
|
||||
ThrottlePos = in.ThrottlePos[EngineNumber];
|
||||
|
||||
/* The thruster controls the engine RPM because it encapsulates the gear ratio and other transmission variables */
|
||||
/* The thruster controls the engine RPM because it encapsulates the gear ratio
|
||||
and other transmission variables */
|
||||
RPM = Thruster->GetEngineRPM();
|
||||
if (thrusterType == FGThruster::ttPropeller) {
|
||||
((FGPropeller*)Thruster)->SetAdvance(in.PropAdvance[EngineNumber]);
|
||||
|
@ -320,7 +319,6 @@ double FGTurboProp::Off(void)
|
|||
|
||||
double FGTurboProp::Run(void)
|
||||
{
|
||||
double thrust = 0.0;
|
||||
double EngPower_HP;
|
||||
|
||||
Running = true; Starter = false; EngStarting = false;
|
||||
|
@ -342,7 +340,6 @@ double FGTurboProp::Run(void)
|
|||
|
||||
OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6; //from MPa to psi
|
||||
//---
|
||||
EPR = 1.0 + thrust/MilThrust;
|
||||
|
||||
OilTemp_degK = Seek(&OilTemp_degK, 353.15, 0.4-N1*0.001, 0.04);
|
||||
|
||||
|
@ -477,7 +474,6 @@ void FGTurboProp::SetDefaults(void)
|
|||
N1 = 0.0;
|
||||
HP = 0.0;
|
||||
Type = etTurboprop;
|
||||
MilThrust = 10000.0;
|
||||
IdleN1 = 30.0;
|
||||
MaxN1 = 100.0;
|
||||
Reversed = false;
|
||||
|
@ -590,7 +586,6 @@ void FGTurboProp::Debug(int from)
|
|||
if (from == 2) { // called from Load()
|
||||
cout << "\n ****MUJ MOTOR TURBOPROP****\n";
|
||||
cout << "\n Engine Name: " << Name << endl;
|
||||
cout << " MilThrust: " << MilThrust << endl;
|
||||
cout << " IdleN1: " << IdleN1 << endl;
|
||||
cout << " MaxN1: " << MaxN1 << endl;
|
||||
|
||||
|
|
6
src/FDM/JSBSim/models/propulsion/FGTurboProp.h
Executable file → Normal file
6
src/FDM/JSBSim/models/propulsion/FGTurboProp.h
Executable file → Normal file
|
@ -46,7 +46,7 @@ INCLUDES
|
|||
#include "FGEngine.h"
|
||||
#include "math/FGTable.h"
|
||||
|
||||
#define ID_TURBOPROP "$Id: FGTurboProp.h,v 1.24 2016/07/10 12:39:28 bcoconni Exp $"
|
||||
#define ID_TURBOPROP "$Id: FGTurboProp.h,v 1.25 2017/02/26 11:41:28 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -121,7 +121,6 @@ public:
|
|||
bool GetCutoff(void) const { return Cutoff; }
|
||||
|
||||
double GetN1(void) const {return N1;}
|
||||
double GetEPR(void) const {return EPR;}
|
||||
double GetITT(void) const {return Eng_ITT_degC;}
|
||||
double GetEngStarting(void) const { return EngStarting; }
|
||||
|
||||
|
@ -132,7 +131,6 @@ public:
|
|||
inline int GetCondition(void) const { return Condition; }
|
||||
|
||||
void SetPhase( phaseType p ) { phase = p; }
|
||||
void SetEPR(double epr) {EPR = epr;}
|
||||
void SetReverse(bool reversed) { Reversed = reversed; }
|
||||
void SetCutoff(bool cutoff) { Cutoff = cutoff; }
|
||||
|
||||
|
@ -145,7 +143,6 @@ public:
|
|||
private:
|
||||
|
||||
phaseType phase; ///< Operating mode, or "phase"
|
||||
double MilThrust; ///< Maximum Unaugmented Thrust, static @ S.L. (lbf)
|
||||
double IdleN1; ///< Idle N1
|
||||
double N1; ///< N1
|
||||
double MaxN1; ///< N1 at 100% throttle
|
||||
|
@ -155,7 +152,6 @@ private:
|
|||
bool Reversed;
|
||||
bool Cutoff;
|
||||
|
||||
double EPR;
|
||||
double OilPressure_psi;
|
||||
double OilTemp_degK;
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
namespace yasim {
|
||||
|
||||
// gadgets
|
||||
inline float norm(float f) { return f<1 ? 1/f : f; }
|
||||
inline float abs(float f) { return f<0 ? -f : f; }
|
||||
|
||||
// Solver threshold. How close to the solution are we trying
|
||||
|
@ -57,6 +56,9 @@ Airplane::Airplane()
|
|||
_tailIncidence = 0;
|
||||
|
||||
_failureMsg = 0;
|
||||
_wingsN = 0;
|
||||
_cgMaxX = -1e6;
|
||||
_cgMinX = 1e6;
|
||||
}
|
||||
|
||||
Airplane::~Airplane()
|
||||
|
@ -113,16 +115,6 @@ void Airplane::calcFuelWeights()
|
|||
}
|
||||
}
|
||||
|
||||
ControlMap* Airplane::getControlMap()
|
||||
{
|
||||
return &_controls;
|
||||
}
|
||||
|
||||
Model* Airplane::getModel()
|
||||
{
|
||||
return &_model;
|
||||
}
|
||||
|
||||
void Airplane::getPilotAccel(float* out)
|
||||
{
|
||||
State* s = _model.getState();
|
||||
|
@ -145,43 +137,6 @@ void Airplane::getPilotAccel(float* out)
|
|||
// FIXME: rotational & centripetal acceleration needed
|
||||
}
|
||||
|
||||
void Airplane::setPilotPos(float* pos)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<3; i++) _pilotPos[i] = pos[i];
|
||||
}
|
||||
|
||||
void Airplane::getPilotPos(float* out)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<3; i++) out[i] = _pilotPos[i];
|
||||
}
|
||||
|
||||
int Airplane::numGear()
|
||||
{
|
||||
return _gears.size();
|
||||
}
|
||||
|
||||
Gear* Airplane::getGear(int g)
|
||||
{
|
||||
return ((GearRec*)_gears.get(g))->gear;
|
||||
}
|
||||
|
||||
Hook* Airplane::getHook()
|
||||
{
|
||||
return _model.getHook();
|
||||
}
|
||||
|
||||
Launchbar* Airplane::getLaunchbar()
|
||||
{
|
||||
return _model.getLaunchbar();
|
||||
}
|
||||
|
||||
Rotorgear* Airplane::getRotorgear()
|
||||
{
|
||||
return _model.getRotorgear();
|
||||
}
|
||||
|
||||
void Airplane::updateGearState()
|
||||
{
|
||||
for(int i=0; i<_gears.size(); i++) {
|
||||
|
@ -247,51 +202,6 @@ void Airplane::addSolutionWeight(bool approach, int idx, float wgt)
|
|||
_solveWeights.add(w);
|
||||
}
|
||||
|
||||
int Airplane::numTanks()
|
||||
{
|
||||
return _tanks.size();
|
||||
}
|
||||
|
||||
float Airplane::getFuel(int tank)
|
||||
{
|
||||
return ((Tank*)_tanks.get(tank))->fill;
|
||||
}
|
||||
|
||||
float Airplane::setFuel(int tank, float fuel)
|
||||
{
|
||||
return ((Tank*)_tanks.get(tank))->fill = fuel;
|
||||
}
|
||||
|
||||
float Airplane::getFuelDensity(int tank)
|
||||
{
|
||||
return ((Tank*)_tanks.get(tank))->density;
|
||||
}
|
||||
|
||||
float Airplane::getTankCapacity(int tank)
|
||||
{
|
||||
return ((Tank*)_tanks.get(tank))->cap;
|
||||
}
|
||||
|
||||
void Airplane::setWeight(float weight)
|
||||
{
|
||||
_emptyWeight = weight;
|
||||
}
|
||||
|
||||
void Airplane::setWing(Wing* wing)
|
||||
{
|
||||
_wing = wing;
|
||||
}
|
||||
|
||||
void Airplane::setTail(Wing* tail)
|
||||
{
|
||||
_tail = tail;
|
||||
}
|
||||
|
||||
void Airplane::addVStab(Wing* vstab)
|
||||
{
|
||||
_vstabs.add(vstab);
|
||||
}
|
||||
|
||||
void Airplane::addFuselage(float* front, float* back, float width,
|
||||
float taper, float mid,
|
||||
float cx, float cy, float cz, float idrag)
|
||||
|
@ -330,21 +240,10 @@ void Airplane::addGear(Gear* gear)
|
|||
g->gear = gear;
|
||||
g->surf = 0;
|
||||
_gears.add(g);
|
||||
}
|
||||
|
||||
void Airplane::addHook(Hook* hook)
|
||||
{
|
||||
_model.addHook(hook);
|
||||
}
|
||||
|
||||
void Airplane::addHitch(Hitch* hitch)
|
||||
{
|
||||
_model.addHitch(hitch);
|
||||
}
|
||||
|
||||
void Airplane::addLaunchbar(Launchbar* launchbar)
|
||||
{
|
||||
_model.addLaunchbar(launchbar);
|
||||
float pos[3];
|
||||
g->gear->getPosition(pos);
|
||||
if (pos[0] > _cgMaxX) _cgMaxX = pos[0];
|
||||
if (pos[0] < _cgMinX) _cgMinX = pos[0];
|
||||
}
|
||||
|
||||
void Airplane::addThruster(Thruster* thruster, float mass, float* cg)
|
||||
|
@ -357,12 +256,14 @@ void Airplane::addThruster(Thruster* thruster, float mass, float* cg)
|
|||
_thrusters.add(t);
|
||||
}
|
||||
|
||||
/// Use ballast to redistribute mass, this is NOT added to empty weight.
|
||||
void Airplane::addBallast(float* pos, float mass)
|
||||
{
|
||||
_model.getBody()->addMass(mass, pos);
|
||||
_model.getBody()->addMass(mass, pos, true);
|
||||
_ballast += mass;
|
||||
}
|
||||
|
||||
/// Masses configurable at runtime, e.g. cargo, pax
|
||||
int Airplane::addWeight(float* pos, float size)
|
||||
{
|
||||
WeightRec* wr = new WeightRec();
|
||||
|
@ -377,6 +278,7 @@ int Airplane::addWeight(float* pos, float size)
|
|||
return _weights.add(wr);
|
||||
}
|
||||
|
||||
/// Change weight of a previously added mass point
|
||||
void Airplane::setWeight(int handle, float mass)
|
||||
{
|
||||
WeightRec* wr = (WeightRec*)_weights.get(handle);
|
||||
|
@ -398,45 +300,14 @@ void Airplane::setWeight(int handle, float mass)
|
|||
|
||||
void Airplane::setFuelFraction(float frac)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<_tanks.size(); i++) {
|
||||
for(int i=0; i<_tanks.size(); i++) {
|
||||
Tank* t = (Tank*)_tanks.get(i);
|
||||
t->fill = frac * t->cap;
|
||||
_model.getBody()->setMass(t->handle, t->cap * frac);
|
||||
}
|
||||
}
|
||||
|
||||
float Airplane::getDragCoefficient()
|
||||
{
|
||||
return _dragFactor;
|
||||
}
|
||||
|
||||
float Airplane::getLiftRatio()
|
||||
{
|
||||
return _liftRatio;
|
||||
}
|
||||
|
||||
float Airplane::getCruiseAoA()
|
||||
{
|
||||
return _cruiseAoA;
|
||||
}
|
||||
|
||||
float Airplane::getTailIncidence()
|
||||
{
|
||||
return _tailIncidence;
|
||||
}
|
||||
|
||||
const char* Airplane::getFailureMsg()
|
||||
{
|
||||
return _failureMsg;
|
||||
}
|
||||
|
||||
int Airplane::getSolutionIterations()
|
||||
{
|
||||
return _solutionIterations;
|
||||
}
|
||||
|
||||
void Airplane::setupState(float aoa, float speed, float gla, State* s)
|
||||
void Airplane::setupState(const float aoa, const float speed, const float gla, State* s)
|
||||
{
|
||||
float cosAoA = Math::cos(aoa);
|
||||
float sinAoA = Math::sin(aoa);
|
||||
|
@ -444,10 +315,10 @@ void Airplane::setupState(float aoa, float speed, float gla, State* s)
|
|||
s->orient[3] = 0; s->orient[4] = 1; s->orient[5] = 0;
|
||||
s->orient[6] = -sinAoA; s->orient[7] = 0; s->orient[8] = cosAoA;
|
||||
|
||||
//? what is gla? v[1]=y, v[2]=z? should sin go to v2 instead v1?
|
||||
s->v[0] = speed*Math::cos(gla); s->v[1] = -speed*Math::sin(gla); s->v[2] = 0;
|
||||
|
||||
int i;
|
||||
for(i=0; i<3; i++)
|
||||
for(int i=0; i<3; i++)
|
||||
s->pos[i] = s->rot[i] = s->acc[i] = s->racc[i] = 0;
|
||||
|
||||
// Put us 1m above the origin, or else the gravity computation in
|
||||
|
@ -455,39 +326,59 @@ void Airplane::setupState(float aoa, float speed, float gla, State* s)
|
|||
s->pos[2] = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief add contact point for crash detection
|
||||
* used to add wingtips and fuselage nose and tail
|
||||
*
|
||||
* @param pos ...
|
||||
* @return void
|
||||
*/
|
||||
|
||||
void Airplane::addContactPoint(float* pos)
|
||||
{
|
||||
ContactRec* c = new ContactRec;
|
||||
c->gear = 0;
|
||||
c->p[0] = pos[0];
|
||||
c->p[1] = pos[1];
|
||||
c->p[2] = pos[2];
|
||||
Math::set3(pos, c->p);
|
||||
_contacts.add(c);
|
||||
}
|
||||
|
||||
float Airplane::compileWing(Wing* w)
|
||||
{
|
||||
// The tip of the wing is a contact point
|
||||
float tip[3];
|
||||
w->getTip(tip);
|
||||
addContactPoint(tip);
|
||||
if(w->isMirrored()) {
|
||||
tip[1] *= -1;
|
||||
addContactPoint(tip);
|
||||
}
|
||||
|
||||
// Make sure it's initialized. The surfaces will pop out with
|
||||
// total drag coefficients equal to their areas, which is what we
|
||||
// want.
|
||||
w->compile();
|
||||
|
||||
float wgt = 0;
|
||||
int i;
|
||||
for(i=0; i<w->numSurfaces(); i++) {
|
||||
Surface* s = (Surface*)w->getSurface(i);
|
||||
// The tip of the wing is a contact point
|
||||
float tip[3];
|
||||
// need compile() before getTip()!
|
||||
w->getTip(tip);
|
||||
addContactPoint(tip);
|
||||
if(w->isMirrored()) {
|
||||
tip[1] *= -1;
|
||||
addContactPoint(tip);
|
||||
tip[1] *= -1; //undo mirror
|
||||
}
|
||||
if (_wingsN != 0) {
|
||||
_wingsN->getNode("tip-x", true)->setFloatValue(tip[0]);
|
||||
_wingsN->getNode("tip-y", true)->setFloatValue(tip[1]);
|
||||
_wingsN->getNode("tip-z", true)->setFloatValue(tip[2]);
|
||||
w->getBase(tip);
|
||||
_wingsN->getNode("base-x", true)->setFloatValue(tip[0]);
|
||||
_wingsN->getNode("base-y", true)->setFloatValue(tip[1]);
|
||||
_wingsN->getNode("base-z", true)->setFloatValue(tip[2]);
|
||||
_wingsN->getNode("wing-span", true)->setFloatValue(w->getSpan());
|
||||
_wingsN->getNode("wing-area", true)->setFloatValue(w->getArea());
|
||||
_wingsN->getNode("aspect-ratio", true)->setFloatValue(w->getAspectRatio());
|
||||
_wingsN->getNode("standard-mean-chord", true)->setFloatValue(w->getSMC());
|
||||
}
|
||||
|
||||
float td = s->getTotalDrag();
|
||||
s->setTotalDrag(td);
|
||||
float wgt = 0;
|
||||
float dragSum = 0;
|
||||
for(int i=0; i<w->numSurfaces(); i++) {
|
||||
Surface* s = (Surface*)w->getSurface(i);
|
||||
float td = s->getTotalDrag();
|
||||
int sid = s->getID();
|
||||
|
||||
_model.addSurface(s);
|
||||
|
||||
|
@ -495,8 +386,18 @@ float Airplane::compileWing(Wing* w)
|
|||
mass = mass * Math::sqrt(mass);
|
||||
float pos[3];
|
||||
s->getPosition(pos);
|
||||
_model.getBody()->addMass(mass, pos);
|
||||
int mid = _model.getBody()->addMass(mass, pos, true);
|
||||
if (_wingsN != 0) {
|
||||
SGPropertyNode_ptr n = _wingsN->getNode("surfaces", true)->getChild("surface", sid, true);
|
||||
n->getNode("drag", true)->setFloatValue(td);
|
||||
n->getNode("mass-id", true)->setIntValue(mid);
|
||||
}
|
||||
wgt += mass;
|
||||
dragSum += td;
|
||||
}
|
||||
if (_wingsN != 0) {
|
||||
_wingsN->getNode("weight", true)->setFloatValue(wgt);
|
||||
_wingsN->getNode("drag", true)->setFloatValue(dragSum);
|
||||
}
|
||||
return wgt;
|
||||
}
|
||||
|
@ -547,7 +448,7 @@ float Airplane::compileFuselage(Fuselage* f)
|
|||
|
||||
// _Mass_ weighting goes as surface area^(3/2)
|
||||
float mass = scale*segWgt * Math::sqrt(scale*segWgt);
|
||||
_model.getBody()->addMass(mass, pos);
|
||||
_model.getBody()->addMass(mass, pos, true);
|
||||
wgt += mass;
|
||||
|
||||
// Make a Surface too
|
||||
|
@ -635,6 +536,13 @@ void Airplane::compileGear(GearRec* gr)
|
|||
_surfs.add(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief add "fake gear" per contact point
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
void Airplane::compileContactPoints()
|
||||
{
|
||||
// Figure it will compress by 20cm
|
||||
|
@ -648,8 +556,7 @@ void Airplane::compileContactPoints()
|
|||
float spring = (1/DIST) * 9.8f * 10.0f * mass;
|
||||
float damp = 2 * Math::sqrt(spring * mass);
|
||||
|
||||
int i;
|
||||
for(i=0; i<_contacts.size(); i++) {
|
||||
for(int i=0; i<_contacts.size(); i++) {
|
||||
ContactRec* c = (ContactRec*)_contacts.get(i);
|
||||
|
||||
Gear* g = new Gear();
|
||||
|
@ -674,6 +581,8 @@ void Airplane::compile()
|
|||
{
|
||||
RigidBody* body = _model.getBody();
|
||||
int firstMass = body->numMasses();
|
||||
SGPropertyNode_ptr baseN = fgGetNode("/fdm/yasim/model/wings", true);
|
||||
SGPropertyNode_ptr n;
|
||||
|
||||
// Generate the point masses for the plane. Just use unitless
|
||||
// numbers for a first pass, then go back through and rescale to
|
||||
|
@ -682,13 +591,21 @@ void Airplane::compile()
|
|||
|
||||
// The Wing objects
|
||||
if (_wing)
|
||||
{
|
||||
if (baseN != 0) _wingsN = baseN->getChild("wing", 0, true);
|
||||
aeroWgt += compileWing(_wing);
|
||||
}
|
||||
if (_tail)
|
||||
{
|
||||
if (baseN != 0) _wingsN = baseN->getChild("tail", 0, true);
|
||||
aeroWgt += compileWing(_tail);
|
||||
}
|
||||
int i;
|
||||
for(i=0; i<_vstabs.size(); i++)
|
||||
aeroWgt += compileWing((Wing*)_vstabs.get(i));
|
||||
|
||||
{
|
||||
if (baseN != 0) _wingsN = baseN->getChild("stab", i, true);
|
||||
aeroWgt += compileWing((Wing*)_vstabs.get(i));
|
||||
}
|
||||
|
||||
// The fuselage(s)
|
||||
for(i=0; i<_fuselages.size(); i++)
|
||||
|
@ -707,7 +624,7 @@ void Airplane::compile()
|
|||
// Add the thruster masses
|
||||
for(i=0; i<_thrusters.size(); i++) {
|
||||
ThrustRec* t = (ThrustRec*)_thrusters.get(i);
|
||||
body->addMass(t->mass, t->cg);
|
||||
body->addMass(t->mass, t->cg, true);
|
||||
}
|
||||
|
||||
// Add the tanks, empty for now.
|
||||
|
@ -733,10 +650,23 @@ void Airplane::compile()
|
|||
}
|
||||
|
||||
// Ground effect
|
||||
// If a double tapered wing is modelled with wing and mstab, wing must
|
||||
// be outboard to get correct wingspan.
|
||||
if(_wing) {
|
||||
float gepos[3];
|
||||
float gespan = 0;
|
||||
gespan = _wing->getGroundEffect(gepos);
|
||||
gespan = _wing->getSpan();
|
||||
_wing->getBase(gepos);
|
||||
if(!isVersionOrNewer( Version::YASIM_VERSION_2017_2 )) {
|
||||
//old code
|
||||
//float span = _length * Math::cos(_sweep) * Math::cos(_dihedral);
|
||||
//span = 2*(span + Math::abs(_base[2]));
|
||||
gespan -= 2*gepos[1]; // cut away base (y-distance)
|
||||
gespan += 2*Math::abs(gepos[2]); // add (wrong) z-distance
|
||||
}
|
||||
if (baseN != 0)
|
||||
baseN->getChild("wing", 0)->getNode("gnd-eff-span", true)->setFloatValue(gespan);
|
||||
// where does the hard coded factor 0.15 come from?
|
||||
_model.setGroundEffect(gepos, gespan, 0.15f);
|
||||
}
|
||||
|
||||
|
@ -822,11 +752,11 @@ void Airplane::initEngines()
|
|||
|
||||
void Airplane::stabilizeThrust()
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<_thrusters.size(); i++)
|
||||
for(int i=0; i<_thrusters.size(); i++)
|
||||
_model.getThruster(i)->stabilize();
|
||||
}
|
||||
|
||||
/// Setup weights for cruise or approach during solve.
|
||||
void Airplane::setupWeights(bool isApproach)
|
||||
{
|
||||
int i;
|
||||
|
@ -839,6 +769,18 @@ void Airplane::setupWeights(bool isApproach)
|
|||
}
|
||||
}
|
||||
|
||||
/// load values for controls as defined in cruise configuration
|
||||
void Airplane::loadCruiseControls()
|
||||
{
|
||||
_controls.reset();
|
||||
for(int i=0; i<_cruiseControls.size(); i++) {
|
||||
Control* c = (Control*)_cruiseControls.get(i);
|
||||
_controls.setInput(c->control, c->val);
|
||||
}
|
||||
_controls.applyControls();
|
||||
}
|
||||
|
||||
/// Helper for solve()
|
||||
void Airplane::runCruise()
|
||||
{
|
||||
setupState(_cruiseAoA, _cruiseSpeed,_cruiseGlideAngle, &_cruiseState);
|
||||
|
@ -847,13 +789,7 @@ void Airplane::runCruise()
|
|||
Atmosphere::calcStdDensity(_cruiseP, _cruiseT));
|
||||
|
||||
// The control configuration
|
||||
_controls.reset();
|
||||
int i;
|
||||
for(i=0; i<_cruiseControls.size(); i++) {
|
||||
Control* c = (Control*)_cruiseControls.get(i);
|
||||
_controls.setInput(c->control, c->val);
|
||||
}
|
||||
_controls.applyControls(1000000); // Huge dt value
|
||||
loadCruiseControls();
|
||||
|
||||
// The local wind
|
||||
float wind[3];
|
||||
|
@ -865,7 +801,7 @@ void Airplane::runCruise()
|
|||
|
||||
// Set up the thruster parameters and iterate until the thrust
|
||||
// stabilizes.
|
||||
for(i=0; i<_thrusters.size(); i++) {
|
||||
for(int i=0; i<_thrusters.size(); i++) {
|
||||
Thruster* t = ((ThrustRec*)_thrusters.get(i))->thruster;
|
||||
t->setWind(wind);
|
||||
t->setAir(_cruiseP, _cruiseT,
|
||||
|
@ -882,6 +818,18 @@ void Airplane::runCruise()
|
|||
_model.calcForces(&_cruiseState);
|
||||
}
|
||||
|
||||
/// load values for controls as defined in approach configuration
|
||||
void Airplane::loadApproachControls()
|
||||
{
|
||||
_controls.reset();
|
||||
for(int i=0; i<_approachControls.size(); i++) {
|
||||
Control* c = (Control*)_approachControls.get(i);
|
||||
_controls.setInput(c->control, c->val);
|
||||
}
|
||||
_controls.applyControls();
|
||||
}
|
||||
|
||||
/// Helper for solve()
|
||||
void Airplane::runApproach()
|
||||
{
|
||||
setupState(_approachAoA, _approachSpeed,_approachGlideAngle, &_approachState);
|
||||
|
@ -890,13 +838,7 @@ void Airplane::runApproach()
|
|||
Atmosphere::calcStdDensity(_approachP, _approachT));
|
||||
|
||||
// The control configuration
|
||||
_controls.reset();
|
||||
int i;
|
||||
for(i=0; i<_approachControls.size(); i++) {
|
||||
Control* c = (Control*)_approachControls.get(i);
|
||||
_controls.setInput(c->control, c->val);
|
||||
}
|
||||
_controls.applyControls(1000000);
|
||||
loadApproachControls();
|
||||
|
||||
// The local wind
|
||||
float wind[3];
|
||||
|
@ -909,7 +851,7 @@ void Airplane::runApproach()
|
|||
|
||||
// Run the thrusters until they get to a stable setting. FIXME:
|
||||
// this is lots of wasted work.
|
||||
for(i=0; i<_thrusters.size(); i++) {
|
||||
for(int i=0; i<_thrusters.size(); i++) {
|
||||
Thruster* t = ((ThrustRec*)_thrusters.get(i))->thruster;
|
||||
t->setWind(wind);
|
||||
t->setAir(_approachP, _approachT,
|
||||
|
@ -926,6 +868,7 @@ void Airplane::runApproach()
|
|||
_model.calcForces(&_approachState);
|
||||
}
|
||||
|
||||
/// Used only in Airplane::solve() and solveHelicopter(), not at runtime
|
||||
void Airplane::applyDragFactor(float factor)
|
||||
{
|
||||
float applied = Math::pow(factor, SOLVE_TWEAK);
|
||||
|
@ -971,6 +914,7 @@ void Airplane::applyDragFactor(float factor)
|
|||
}
|
||||
}
|
||||
|
||||
/// Used only in Airplane::solve() and solveHelicopter(), not at runtime
|
||||
void Airplane::applyLiftRatio(float factor)
|
||||
{
|
||||
float applied = Math::pow(factor, SOLVE_TWEAK);
|
||||
|
@ -986,13 +930,7 @@ void Airplane::applyLiftRatio(float factor)
|
|||
}
|
||||
}
|
||||
|
||||
float Airplane::clamp(float val, float min, float max)
|
||||
{
|
||||
if(val < min) return min;
|
||||
if(val > max) return max;
|
||||
return val;
|
||||
}
|
||||
|
||||
/// Helper for solve()
|
||||
float Airplane::normFactor(float f)
|
||||
{
|
||||
if(f < 0) f = -f;
|
||||
|
@ -1102,8 +1040,8 @@ void Airplane::solve()
|
|||
_cruiseAoA += SOLVE_TWEAK*aoaDelta;
|
||||
_tailIncidence += SOLVE_TWEAK*tailDelta;
|
||||
|
||||
_cruiseAoA = clamp(_cruiseAoA, -0.175f, 0.175f);
|
||||
_tailIncidence = clamp(_tailIncidence, -0.175f, 0.175f);
|
||||
_cruiseAoA = Math::clamp(_cruiseAoA, -0.175f, 0.175f);
|
||||
_tailIncidence = Math::clamp(_tailIncidence, -0.175f, 0.175f);
|
||||
|
||||
if(abs(xforce/_cruiseWeight) < STHRESH*0.0001 &&
|
||||
abs(alift/_approachWeight) < STHRESH*0.0001 &&
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "Rotor.hpp"
|
||||
#include "Vector.hpp"
|
||||
#include "Version.hpp"
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
namespace yasim {
|
||||
|
||||
|
@ -16,7 +17,9 @@ class Launchbar;
|
|||
class Thruster;
|
||||
class Hitch;
|
||||
|
||||
/// The Airplane class ties together the different components
|
||||
class Airplane : public Version {
|
||||
SGPropertyNode_ptr _wingsN;
|
||||
public:
|
||||
Airplane();
|
||||
~Airplane();
|
||||
|
@ -24,30 +27,30 @@ public:
|
|||
void iterate(float dt);
|
||||
void calcFuelWeights();
|
||||
|
||||
ControlMap* getControlMap();
|
||||
Model* getModel();
|
||||
ControlMap* getControlMap() { return &_controls; }
|
||||
Model* getModel() { return &_model; }
|
||||
|
||||
void setPilotPos(float* pos);
|
||||
void getPilotPos(float* out);
|
||||
void setPilotPos(float* pos) { Math::set3(pos, _pilotPos); }
|
||||
void getPilotPos(float* out) { Math::set3(_pilotPos, out); }
|
||||
|
||||
void getPilotAccel(float* out);
|
||||
|
||||
void setWeight(float weight);
|
||||
void setEmptyWeight(float weight) { _emptyWeight = weight; }
|
||||
|
||||
void setWing(Wing* wing);
|
||||
void setTail(Wing* tail);
|
||||
void addVStab(Wing* vstab);
|
||||
void setWing(Wing* wing) { _wing = wing; }
|
||||
void setTail(Wing* tail) { _tail = tail; }
|
||||
void addVStab(Wing* vstab) { _vstabs.add(vstab); }
|
||||
|
||||
void addFuselage(float* front, float* back, float width,
|
||||
float taper=1, float mid=0.5,
|
||||
float cx=1, float cy=1, float cz=1, float idrag=1);
|
||||
int addTank(float* pos, float cap, float fuelDensity);
|
||||
void addGear(Gear* g);
|
||||
void addHook(Hook* h);
|
||||
void addLaunchbar(Launchbar* l);
|
||||
void addHook(Hook* h) { _model.addHook(h); }
|
||||
void addLaunchbar(Launchbar* l) { _model.addLaunchbar(l); }
|
||||
void addThruster(Thruster* t, float mass, float* cg);
|
||||
void addBallast(float* pos, float mass);
|
||||
void addHitch(Hitch* h);
|
||||
void addHitch(Hitch* h) { _model.addHitch(h); }
|
||||
|
||||
int addWeight(float* pos, float size);
|
||||
void setWeight(int handle, float mass);
|
||||
|
@ -61,39 +64,47 @@ public:
|
|||
|
||||
void addSolutionWeight(bool approach, int idx, float wgt);
|
||||
|
||||
int numGear();
|
||||
Gear* getGear(int g);
|
||||
Hook* getHook();
|
||||
int numGear() { return _gears.size(); }
|
||||
Gear* getGear(int g) { return ((GearRec*)_gears.get(g))->gear; }
|
||||
Hook* getHook() { return _model.getHook(); }
|
||||
int numHitches() { return _hitches.size(); }
|
||||
Hitch* getHitch(int h);
|
||||
Rotorgear* getRotorgear();
|
||||
Launchbar* getLaunchbar();
|
||||
Rotorgear* getRotorgear() { return _model.getRotorgear(); }
|
||||
Launchbar* getLaunchbar() { return _model.getLaunchbar(); }
|
||||
|
||||
int numThrusters() { return _thrusters.size(); }
|
||||
Thruster* getThruster(int n) {
|
||||
return ((ThrustRec*)_thrusters.get(n))->thruster; }
|
||||
|
||||
int numTanks();
|
||||
int numTanks() { return _tanks.size(); }
|
||||
void setFuelFraction(float frac); // 0-1, total amount of fuel
|
||||
float getFuel(int tank); // in kg!
|
||||
float setFuel(int tank, float fuel); // in kg!
|
||||
float getFuelDensity(int tank); // kg/m^3
|
||||
float getTankCapacity(int tank);
|
||||
// get fuel in kg
|
||||
float getFuel(int tank) { return ((Tank*)_tanks.get(tank))->fill; }
|
||||
// set fuel in kg
|
||||
float setFuel(int tank, float fuel) { return ((Tank*)_tanks.get(tank))->fill = fuel; }
|
||||
// get fuel density in kg/m^3
|
||||
float getFuelDensity(int tank) { return ((Tank*)_tanks.get(tank))->density; }
|
||||
float getTankCapacity(int tank) { return ((Tank*)_tanks.get(tank))->cap; }
|
||||
|
||||
void compile(); // generate point masses & such, then solve
|
||||
void initEngines();
|
||||
void stabilizeThrust();
|
||||
|
||||
// Solution output values
|
||||
int getSolutionIterations();
|
||||
float getDragCoefficient();
|
||||
float getLiftRatio();
|
||||
float getCruiseAoA();
|
||||
float getTailIncidence();
|
||||
int getSolutionIterations() { return _solutionIterations; }
|
||||
float getDragCoefficient() { return _dragFactor; }
|
||||
float getLiftRatio() { return _liftRatio; }
|
||||
float getCruiseAoA() { return _cruiseAoA; }
|
||||
float getTailIncidence() { return _tailIncidence; }
|
||||
float getApproachElevator() { return _approachElevator.val; }
|
||||
const char* getFailureMsg();
|
||||
const char* getFailureMsg() { return _failureMsg; }
|
||||
|
||||
static void setupState(float aoa, float speed, float gla, State* s); // utility
|
||||
static void setupState(const float aoa, const float speed, const float gla, yasim::State* s); // utility
|
||||
void loadApproachControls();
|
||||
void loadCruiseControls();
|
||||
|
||||
float getCGMinX() { return _cgMinX; }
|
||||
float getCGMaxX() { return _cgMaxX; }
|
||||
|
||||
private:
|
||||
struct Tank { float pos[3]; float cap; float fill;
|
||||
|
@ -119,7 +130,6 @@ private:
|
|||
void compileGear(GearRec* gr);
|
||||
void applyDragFactor(float factor);
|
||||
void applyLiftRatio(float factor);
|
||||
float clamp(float val, float min, float max);
|
||||
void addContactPoint(float* pos);
|
||||
void compileContactPoints();
|
||||
float normFactor(float f);
|
||||
|
@ -175,6 +185,10 @@ private:
|
|||
float _tailIncidence;
|
||||
Control _approachElevator;
|
||||
const char* _failureMsg;
|
||||
|
||||
// hard limits for cg from gear positions
|
||||
float _cgMaxX;
|
||||
float _cgMinX;
|
||||
};
|
||||
|
||||
}; // namespace yasim
|
||||
|
|
|
@ -21,25 +21,29 @@ namespace yasim {
|
|||
|
||||
ControlMap::~ControlMap()
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<_inputs.size(); i++) {
|
||||
Vector* v = (Vector*)_inputs.get(i);
|
||||
int j;
|
||||
for(j=0; j<v->size(); j++)
|
||||
int i;
|
||||
for(i=0; i<_inputs.size(); i++) {
|
||||
Vector* v = (Vector*)_inputs.get(i);
|
||||
int j;
|
||||
for(j=0; j<v->size(); j++)
|
||||
delete (MapRec*)v->get(j);
|
||||
delete v;
|
||||
}
|
||||
delete v;
|
||||
}
|
||||
|
||||
for(i=0; i<_outputs.size(); i++)
|
||||
delete (OutRec*)_outputs.get(i);
|
||||
}
|
||||
|
||||
int ControlMap::newInput()
|
||||
{
|
||||
Vector* v = new Vector();
|
||||
return _inputs.add(v);
|
||||
for(i=0; i<_outputs.size(); i++)
|
||||
delete (OutRec*)_outputs.get(i);
|
||||
|
||||
for(i=0; i<_properties.size(); i++) {
|
||||
PropHandle* p = (PropHandle*)_properties.get(i);
|
||||
delete[] p->name;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
input : index to _inputs
|
||||
type: identifier (see enum OutputType)
|
||||
*/
|
||||
void ControlMap::addMapping(int input, int type, void* object, int options,
|
||||
float src0, float src1, float dst0, float dst1)
|
||||
{
|
||||
|
@ -55,6 +59,10 @@ void ControlMap::addMapping(int input, int type, void* object, int options,
|
|||
m->dst1 = dst1;
|
||||
}
|
||||
|
||||
/**
|
||||
input : index to _inputs
|
||||
type: identifier (see enum OutputType)
|
||||
*/
|
||||
void ControlMap::addMapping(int input, int type, void* object, int options)
|
||||
{
|
||||
// See if the output object already exists
|
||||
|
@ -210,12 +218,12 @@ void ControlMap::applyControls(float dt)
|
|||
case LEXTEND: ((Launchbar*)obj)->setExtension(lval); break;
|
||||
case LACCEL: ((Launchbar*)obj)->setAcceleration(lval); break;
|
||||
case CASTERING:((Gear*)obj)->setCastering(lval != 0); break;
|
||||
case SLAT: ((Wing*)obj)->setSlat(lval); break;
|
||||
case FLAP0: ((Wing*)obj)->setFlap0(lval, rval); break;
|
||||
case SLAT: ((Wing*)obj)->setSlatPos(lval); break;
|
||||
case FLAP0: ((Wing*)obj)->setFlap0Pos(lval, rval); break;
|
||||
case FLAP0EFFECTIVENESS: ((Wing*)obj)->setFlap0Effectiveness(lval); break;
|
||||
case FLAP1: ((Wing*)obj)->setFlap1(lval, rval); break;
|
||||
case FLAP1: ((Wing*)obj)->setFlap1Pos(lval, rval); break;
|
||||
case FLAP1EFFECTIVENESS: ((Wing*)obj)->setFlap1Effectiveness(lval); break;
|
||||
case SPOILER: ((Wing*)obj)->setSpoiler(lval, rval); break;
|
||||
case SPOILER: ((Wing*)obj)->setSpoilerPos(lval, rval); break;
|
||||
case COLLECTIVE: ((Rotor*)obj)->setCollective(lval); break;
|
||||
case CYCLICAIL: ((Rotor*)obj)->setCyclicail(lval,rval); break;
|
||||
case CYCLICELE: ((Rotor*)obj)->setCyclicele(lval,rval); break;
|
||||
|
@ -278,4 +286,45 @@ float ControlMap::rangeMax(int type)
|
|||
}
|
||||
}
|
||||
|
||||
/// duplicate null-terminated string
|
||||
char* ControlMap::dup(const char* s)
|
||||
{
|
||||
int len=0;
|
||||
while(s[len++]);
|
||||
char* s2 = new char[len+1];
|
||||
char* p = s2;
|
||||
while((*p++ = *s++));
|
||||
s2[len] = 0;
|
||||
return s2;
|
||||
}
|
||||
|
||||
/// compare null-terminated strings
|
||||
bool ControlMap::eq(const char* a, const char* b)
|
||||
{
|
||||
while(*a && *b && *a == *b) { a++; b++; }
|
||||
// equal if both a and b points to null chars
|
||||
return !(*a || *b);
|
||||
}
|
||||
|
||||
/// register property name, return ID (int)
|
||||
int ControlMap::propertyHandle(const char* name)
|
||||
{
|
||||
for(int i=0; i < _properties.size(); i++) {
|
||||
PropHandle* p = (PropHandle*)_properties.get(i);
|
||||
if(eq(p->name, name))
|
||||
return p->handle;
|
||||
}
|
||||
|
||||
// create new
|
||||
PropHandle* p = new PropHandle();
|
||||
p->name = dup(name);
|
||||
|
||||
fgGetNode(p->name, true);
|
||||
|
||||
Vector* v = new Vector();
|
||||
p->handle = _inputs.add(v);
|
||||
_properties.add(p);
|
||||
return p->handle;
|
||||
}
|
||||
|
||||
} // namespace yasim
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef _CONTROL_MAP_HPP
|
||||
#define _CONTROL_MAP_HPP
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include "Vector.hpp"
|
||||
|
||||
namespace yasim {
|
||||
|
@ -26,9 +27,7 @@ public:
|
|||
OPT_INVERT = 0x02,
|
||||
OPT_SQUARE = 0x04 };
|
||||
|
||||
// Returns a new, not-yet-used "input handle" for addMapping and
|
||||
// setInput. This typically corresponds to one user axis.
|
||||
int newInput();
|
||||
struct PropHandle { char* name; int handle; };
|
||||
|
||||
// Adds a mapping to between input handle and a particular setting
|
||||
// on an output object. The value of output MUST match the type
|
||||
|
@ -45,12 +44,13 @@ public:
|
|||
// setInput() invokations.
|
||||
void reset();
|
||||
|
||||
// Sets the specified input (as returned by newInput) to the
|
||||
// Sets the specified input (as returned by propertyHandle) to the
|
||||
// specified value.
|
||||
void setInput(int input, float value);
|
||||
void setInput(int propHandle, float value);
|
||||
|
||||
// Calculates and applies the settings received since the last reset().
|
||||
void applyControls(float dt);
|
||||
/// Calculates and applies the settings received since the last reset().
|
||||
/// dt defaults to a large value used at solve time.
|
||||
void applyControls(float dt=1e6);
|
||||
|
||||
// Returns the input/output range appropriate for the given
|
||||
// control. Ailerons go from -1 to 1, while throttles are never
|
||||
|
@ -72,6 +72,15 @@ public:
|
|||
float getOutput(int handle);
|
||||
float getOutputR(int handle);
|
||||
|
||||
// register property name, return handle
|
||||
int propertyHandle(const char* name);
|
||||
int numProperties() { return _properties.size(); }
|
||||
PropHandle* getProperty(const int i) { return ((PropHandle*)_properties.get(i)); }
|
||||
|
||||
// helper
|
||||
char* dup(const char* s);
|
||||
bool eq(const char* a, const char* b);
|
||||
|
||||
private:
|
||||
struct OutRec { int type; void* object; Vector maps;
|
||||
float oldL, oldR, time; };
|
||||
|
@ -84,6 +93,8 @@ private:
|
|||
|
||||
// An unordered list of output settings.
|
||||
Vector _outputs;
|
||||
// control properties
|
||||
Vector _properties;
|
||||
};
|
||||
|
||||
}; // namespace yasim
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "Rotor.hpp"
|
||||
#include "Rotorpart.hpp"
|
||||
#include "Hitch.hpp"
|
||||
#include "Surface.hpp"
|
||||
|
||||
#include "FGFDM.hpp"
|
||||
|
||||
|
@ -28,6 +29,7 @@ namespace yasim {
|
|||
|
||||
// Some conversion factors
|
||||
static const float KTS2MPS = 0.514444444444;
|
||||
static const float KMH2MPS = 1/3.6;
|
||||
static const float FT2M = 0.3048;
|
||||
static const float DEG2RAD = 0.0174532925199;
|
||||
static const float RPM2RAD = 0.10471975512;
|
||||
|
@ -59,7 +61,7 @@ FGFDM::FGFDM()
|
|||
// Map /controls/flight/elevator to the approach elevator control. This
|
||||
// should probably be settable, but there are very few aircraft
|
||||
// who trim their approaches using things other than elevator.
|
||||
_airplane.setElevatorControl(parseAxis("/controls/flight/elevator-trim"));
|
||||
_airplane.setElevatorControl(_airplane.getControlMap()->propertyHandle("/controls/flight/elevator-trim"));
|
||||
|
||||
// FIXME: read seed from somewhere?
|
||||
int seed = 0;
|
||||
|
@ -68,12 +70,6 @@ FGFDM::FGFDM()
|
|||
|
||||
FGFDM::~FGFDM()
|
||||
{
|
||||
for(int i=0; i<_axes.size(); i++) {
|
||||
AxisRec* a = (AxisRec*)_axes.get(i);
|
||||
delete[] a->name;
|
||||
delete a;
|
||||
}
|
||||
|
||||
for(int i=0; i<_thrusters.size(); i++) {
|
||||
EngRec* er = (EngRec*)_thrusters.get(i);
|
||||
delete[] er->prefix;
|
||||
|
@ -124,18 +120,38 @@ Airplane* FGFDM::getAirplane()
|
|||
|
||||
void FGFDM::init()
|
||||
{
|
||||
//reset id generator, needed on simulator reset/re-init
|
||||
Surface::resetIDgen();
|
||||
_turb_magnitude_norm = fgGetNode("/environment/turbulence/magnitude-norm", true);
|
||||
_turb_rate_hz = fgGetNode("/environment/turbulence/rate-hz", true);
|
||||
|
||||
SGPropertyNode_ptr yasimNode = fgGetNode("/fdm/yasim", true);
|
||||
_gross_weight_lbs = yasimNode->getNode("gross-weight-lbs", true);
|
||||
_yasimN = fgGetNode("/fdm/yasim", true);
|
||||
_gross_weight_lbs = _yasimN->getNode("gross-weight-lbs", true);
|
||||
|
||||
// alias to older name
|
||||
fgGetNode("/yasim/gross-weight-lbs", true)->alias(_gross_weight_lbs);
|
||||
|
||||
_cg_x = yasimNode->getNode("cg-x-m", true);
|
||||
_cg_y = yasimNode->getNode("cg-y-m", true);
|
||||
_cg_z = yasimNode->getNode("cg-z-m", true);
|
||||
// write some compile time information to property tree
|
||||
_yasimN->getNode("config-version",true)->setIntValue(_airplane.getVersion());
|
||||
_yasimN->getNode("model/cg-x-min",true)->setFloatValue(_airplane.getCGMinX());
|
||||
_yasimN->getNode("model/cg-x-max",true)->setFloatValue(_airplane.getCGMaxX());
|
||||
|
||||
// prepare nodes for write at runtime
|
||||
_cg_x = _yasimN->getNode("cg-x-m", true);
|
||||
_cg_y = _yasimN->getNode("cg-y-m", true);
|
||||
_cg_z = _yasimN->getNode("cg-z-m", true);
|
||||
_vxN = _yasimN->getNode("velocities/v-x", true);
|
||||
_vyN = _yasimN->getNode("velocities/v-y", true);
|
||||
_vzN = _yasimN->getNode("velocities/v-z", true);
|
||||
_vrxN = _yasimN->getNode("velocities/vrot-x", true);
|
||||
_vryN = _yasimN->getNode("velocities/vrot-y", true);
|
||||
_vrzN = _yasimN->getNode("velocities/vrot-z", true);
|
||||
_axN = _yasimN->getNode("accelerations/a-x", true);
|
||||
_ayN = _yasimN->getNode("accelerations/a-y", true);
|
||||
_azN = _yasimN->getNode("accelerations/a-z", true);
|
||||
_arxN = _yasimN->getNode("accelerations/arot-x", true);
|
||||
_aryN = _yasimN->getNode("accelerations/arot-y", true);
|
||||
_arzN = _yasimN->getNode("accelerations/arot-z", true);
|
||||
|
||||
// Allows the user to start with something other than full fuel
|
||||
_airplane.setFuelFraction(fgGetFloat("/sim/fuel-fraction", 1));
|
||||
|
@ -225,34 +241,64 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
|
|||
XMLAttributes* a = (XMLAttributes*)&atts;
|
||||
float v[3];
|
||||
char buf[64];
|
||||
float f = 0;
|
||||
|
||||
if(eq(name, "airplane")) {
|
||||
_airplane.setWeight(attrf(a, "mass") * LBS2KG);
|
||||
if(a->hasAttribute("version")) {
|
||||
_airplane.setVersion( a->getValue("version") );
|
||||
}
|
||||
#if defined(ENABLE_DEV_WARNINGS)
|
||||
if( !_airplane.isVersionOrNewer( Version::YASIM_VERSION_CURRENT ) ) {
|
||||
SG_LOG(SG_FLIGHT,SG_ALERT, "This aircraft does not use the latest yasim configuration version.");
|
||||
}
|
||||
#endif
|
||||
if(a->hasAttribute("mass")) { f = attrf(a, "mass") * LBS2KG; }
|
||||
else if (a->hasAttribute("mass-lbs")) { f = attrf(a, "mass-lbs") * LBS2KG; }
|
||||
else if (a->hasAttribute("mass-kg")) { f = attrf(a, "mass-kg"); }
|
||||
else {
|
||||
SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, airplane needs one of {mass-lbs, mass-kg}");
|
||||
exit(1);
|
||||
}
|
||||
_airplane.setEmptyWeight(f);
|
||||
if(a->hasAttribute("version")) {
|
||||
_airplane.setVersion( a->getValue("version") );
|
||||
}
|
||||
if( !_airplane.isVersionOrNewer( Version::YASIM_VERSION_CURRENT ) ) {
|
||||
SG_LOG(SG_FLIGHT, SG_DEV_ALERT, "This aircraft does not use the latest yasim configuration version.");
|
||||
}
|
||||
} else if(eq(name, "approach")) {
|
||||
float spd = attrf(a, "speed") * KTS2MPS;
|
||||
float alt = attrf(a, "alt", 0) * FT2M;
|
||||
float aoa = attrf(a, "aoa", 0) * DEG2RAD;
|
||||
float gla = attrf(a, "glide-angle", 0) * DEG2RAD;
|
||||
_airplane.setApproach(spd, alt, aoa, attrf(a, "fuel", 0.2),gla);
|
||||
_cruiseCurr = false;
|
||||
float spd, alt = 0;
|
||||
if (a->hasAttribute("speed")) { spd = attrf(a, "speed") * KTS2MPS; }
|
||||
else if (a->hasAttribute("speed-kt")) { spd = attrf(a, "speed-kt") * KTS2MPS; }
|
||||
else if (a->hasAttribute("speed-kmh")) { spd = attrf(a, "speed-kmh") * KMH2MPS; }
|
||||
else {
|
||||
SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, approach needs one of {speed-kt, speed-kmh}");
|
||||
exit(1);
|
||||
}
|
||||
if (a->hasAttribute("alt")) { alt = attrf(a, "alt") * FT2M; }
|
||||
else if (a->hasAttribute("alt-ft")) { alt = attrf(a, "alt-ft") * FT2M; }
|
||||
else if (a->hasAttribute("alt-m")) { alt = attrf(a, "alt-m"); }
|
||||
float aoa = attrf(a, "aoa", 0) * DEG2RAD;
|
||||
float gla = attrf(a, "glide-angle", 0) * DEG2RAD;
|
||||
_airplane.setApproach(spd, alt, aoa, attrf(a, "fuel", 0.2), gla);
|
||||
_cruiseCurr = false;
|
||||
} else if(eq(name, "cruise")) {
|
||||
float spd = attrf(a, "speed") * KTS2MPS;
|
||||
float alt = attrf(a, "alt") * FT2M;
|
||||
float gla = attrf(a, "glide-angle", 0) * DEG2RAD;
|
||||
_airplane.setCruise(spd, alt, attrf(a, "fuel", 0.5),gla);
|
||||
_cruiseCurr = true;
|
||||
float spd, alt = 0;
|
||||
if (a->hasAttribute("speed")) { spd = attrf(a, "speed") * KTS2MPS; }
|
||||
else if (a->hasAttribute("speed-kt")) { spd = attrf(a, "speed-kt") * KTS2MPS; }
|
||||
else if (a->hasAttribute("speed-kmh")) { spd = attrf(a, "speed-kmh") * KMH2MPS; }
|
||||
else {
|
||||
SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, approach needs one of {speed-kt, speed-kmh}");
|
||||
exit(1);
|
||||
}
|
||||
if (a->hasAttribute("alt")) { alt = attrf(a, "alt") * FT2M; }
|
||||
else if (a->hasAttribute("alt-ft")) { alt = attrf(a, "alt-ft") * FT2M; }
|
||||
else if (a->hasAttribute("alt-m")) { alt = attrf(a, "alt-m"); }
|
||||
float gla = attrf(a, "glide-angle", 0) * DEG2RAD;
|
||||
_airplane.setCruise(spd, alt, attrf(a, "fuel", 0.5),gla);
|
||||
_cruiseCurr = true;
|
||||
} else if(eq(name, "solve-weight")) {
|
||||
int idx = attri(a, "idx");
|
||||
float wgt = attrf(a, "weight") * LBS2KG;
|
||||
_airplane.addSolutionWeight(!_cruiseCurr, idx, wgt);
|
||||
if(a->hasAttribute("weight")) { f = attrf(a, "weight") * LBS2KG; }
|
||||
else if(a->hasAttribute("weight-lbs")) { f = attrf(a, "weight-lbs") * LBS2KG; }
|
||||
else if(a->hasAttribute("weight-kg")) { f = attrf(a, "weight-kg"); }
|
||||
else {
|
||||
SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, solve-weight needs one of {weight-lbs, weight-kg}");
|
||||
exit(1);
|
||||
}
|
||||
_airplane.addSolutionWeight(!_cruiseCurr, idx, f);
|
||||
} else if(eq(name, "cockpit")) {
|
||||
v[0] = attrf(a, "x");
|
||||
v[1] = attrf(a, "y");
|
||||
|
@ -302,8 +348,15 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
|
|||
v[0] = attrf(a, "x");
|
||||
v[1] = attrf(a, "y");
|
||||
v[2] = attrf(a, "z");
|
||||
float mass = attrf(a, "mass") * LBS2KG;
|
||||
j->setMaxThrust(attrf(a, "thrust") * LBS2N,
|
||||
float mass;
|
||||
if(a->hasAttribute("mass")) { mass = attrf(a, "mass") * LBS2KG; }
|
||||
else if(a->hasAttribute("mass-lbs")) { mass = attrf(a, "mass-lbs") * LBS2KG; }
|
||||
else if(a->hasAttribute("mass-kg")) { mass = attrf(a, "mass-kg"); }
|
||||
else {
|
||||
SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, jet needs one of {mass-lbs, mass-kg}");
|
||||
exit(1);
|
||||
}
|
||||
j->setMaxThrust(attrf(a, "thrust") * LBS2N,
|
||||
attrf(a, "afterburner", 0) * LBS2N);
|
||||
j->setVectorAngle(attrf(a, "rotate", 0) * DEG2RAD);
|
||||
j->setReverseThrust(attrf(a, "reverse", 0.2));
|
||||
|
@ -470,12 +523,27 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
|
|||
float density = 6.0; // gasoline, in lbs/gal
|
||||
if(a->hasAttribute("jet")) density = 6.72;
|
||||
density *= LBS2KG*CM2GALS;
|
||||
_airplane.addTank(v, attrf(a, "capacity") * LBS2KG, density);
|
||||
float capacity = 0;
|
||||
if(a->hasAttribute("capacity")) { capacity = attrf(a, "capacity") * LBS2KG; }
|
||||
else if(a->hasAttribute("capacity-lbs")) { capacity = attrf(a, "capacity-lbs") * LBS2KG; }
|
||||
else if(a->hasAttribute("capacity-kg")) { capacity = attrf(a, "capacity-kg"); }
|
||||
else {
|
||||
SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, tank needs one of {capacity-lbs, capacity-kg}");
|
||||
exit(1);
|
||||
}
|
||||
_airplane.addTank(v, capacity, density);
|
||||
} else if(eq(name, "ballast")) {
|
||||
v[0] = attrf(a, "x");
|
||||
v[1] = attrf(a, "y");
|
||||
v[2] = attrf(a, "z");
|
||||
_airplane.addBallast(v, attrf(a, "mass") * LBS2KG);
|
||||
if(a->hasAttribute("mass")) { f = attrf(a, "mass") * LBS2KG; }
|
||||
else if (a->hasAttribute("mass-lbs")) { f = attrf(a, "mass-lbs") * LBS2KG; }
|
||||
else if (a->hasAttribute("mass-kg")) { f = attrf(a, "mass-kg"); }
|
||||
else {
|
||||
SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, airplane needs one of {mass-lbs, mass-kg}");
|
||||
exit(1);
|
||||
}
|
||||
_airplane.addBallast(v, f);
|
||||
} else if(eq(name, "weight")) {
|
||||
parseWeight(a);
|
||||
} else if(eq(name, "stall")) {
|
||||
|
@ -484,16 +552,16 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
|
|||
w->setStallWidth(attrf(a, "width", 2) * DEG2RAD);
|
||||
w->setStallPeak(attrf(a, "peak", 1.5));
|
||||
} else if(eq(name, "flap0")) {
|
||||
((Wing*)_currObj)->setFlap0(attrf(a, "start"), attrf(a, "end"),
|
||||
((Wing*)_currObj)->setFlap0Params(attrf(a, "start"), attrf(a, "end"),
|
||||
attrf(a, "lift"), attrf(a, "drag"));
|
||||
} else if(eq(name, "flap1")) {
|
||||
((Wing*)_currObj)->setFlap1(attrf(a, "start"), attrf(a, "end"),
|
||||
((Wing*)_currObj)->setFlap1Params(attrf(a, "start"), attrf(a, "end"),
|
||||
attrf(a, "lift"), attrf(a, "drag"));
|
||||
} else if(eq(name, "slat")) {
|
||||
((Wing*)_currObj)->setSlat(attrf(a, "start"), attrf(a, "end"),
|
||||
((Wing*)_currObj)->setSlatParams(attrf(a, "start"), attrf(a, "end"),
|
||||
attrf(a, "aoa"), attrf(a, "drag"));
|
||||
} else if(eq(name, "spoiler")) {
|
||||
((Wing*)_currObj)->setSpoiler(attrf(a, "start"), attrf(a, "end"),
|
||||
((Wing*)_currObj)->setSpoilerParams(attrf(a, "start"), attrf(a, "end"),
|
||||
attrf(a, "lift"), attrf(a, "drag"));
|
||||
/* } else if(eq(name, "collective")) {
|
||||
((Rotor*)_currObj)->setcollective(attrf(a, "min"), attrf(a, "max"));
|
||||
|
@ -510,33 +578,32 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
|
|||
v[1] = attrf(a, "y");
|
||||
v[2] = attrf(a, "z");
|
||||
((Thruster*)_currObj)->setDirection(v);
|
||||
} else if(eq(name, "control-setting")) {
|
||||
// A cruise or approach control setting
|
||||
const char* axis = a->getValue("axis");
|
||||
float value = attrf(a, "value", 0);
|
||||
if(_cruiseCurr)
|
||||
_airplane.addCruiseControl(parseAxis(axis), value);
|
||||
else
|
||||
_airplane.addApproachControl(parseAxis(axis), value);
|
||||
} else if(eq(name, "control-input")) {
|
||||
|
||||
// A mapping of input property to a control
|
||||
int axis = parseAxis(a->getValue("axis"));
|
||||
int control = parseOutput(a->getValue("control"));
|
||||
int opt = 0;
|
||||
opt |= a->hasAttribute("split") ? ControlMap::OPT_SPLIT : 0;
|
||||
opt |= a->hasAttribute("invert") ? ControlMap::OPT_INVERT : 0;
|
||||
opt |= a->hasAttribute("square") ? ControlMap::OPT_SQUARE : 0;
|
||||
|
||||
ControlMap* cm = _airplane.getControlMap();
|
||||
if(a->hasAttribute("src0")) {
|
||||
cm->addMapping(axis, control, _currObj, opt,
|
||||
} else if(eq(name, "control-setting")) {
|
||||
// A cruise or approach control setting
|
||||
const char* axis = a->getValue("axis");
|
||||
float value = attrf(a, "value", 0);
|
||||
ControlMap* cm = _airplane.getControlMap();
|
||||
if(_cruiseCurr)
|
||||
_airplane.addCruiseControl(cm->propertyHandle(axis), value);
|
||||
else
|
||||
_airplane.addApproachControl(cm->propertyHandle(axis), value);
|
||||
} else if(eq(name, "control-input")) {
|
||||
ControlMap* cm = _airplane.getControlMap();
|
||||
// A mapping of input property to a control
|
||||
int axis = cm->propertyHandle(a->getValue("axis"));
|
||||
int control = parseOutput(a->getValue("control"));
|
||||
int opt = 0;
|
||||
opt |= a->hasAttribute("split") ? ControlMap::OPT_SPLIT : 0;
|
||||
opt |= a->hasAttribute("invert") ? ControlMap::OPT_INVERT : 0;
|
||||
opt |= a->hasAttribute("square") ? ControlMap::OPT_SQUARE : 0;
|
||||
if(a->hasAttribute("src0")) {
|
||||
cm->addMapping(axis, control, _currObj, opt,
|
||||
attrf(a, "src0"), attrf(a, "src1"),
|
||||
attrf(a, "dst0"), attrf(a, "dst1"));
|
||||
} else {
|
||||
cm->addMapping(axis, control, _currObj, opt);
|
||||
}
|
||||
} else if(eq(name, "control-output")) {
|
||||
} else {
|
||||
cm->addMapping(axis, control, _currObj, opt);
|
||||
}
|
||||
} else if(eq(name, "control-output")) {
|
||||
// A property output for a control on the current object
|
||||
ControlMap* cm = _airplane.getControlMap();
|
||||
int type = parseOutput(a->getValue("control"));
|
||||
|
@ -577,10 +644,10 @@ void FGFDM::getExternalInput(float dt)
|
|||
ControlMap* cm = _airplane.getControlMap();
|
||||
cm->reset();
|
||||
|
||||
for(int i=0; i<_axes.size(); i++) {
|
||||
AxisRec* a = (AxisRec*)_axes.get(i);
|
||||
float val = fgGetFloat(a->name, 0);
|
||||
cm->setInput(a->handle, val);
|
||||
for(int i=0; i < cm->numProperties(); i++) {
|
||||
ControlMap::PropHandle *p = cm->getProperty(i);
|
||||
float val = fgGetFloat(p->name, 0);
|
||||
cm->setInput(p->handle, val);
|
||||
}
|
||||
cm->applyControls(dt);
|
||||
|
||||
|
@ -625,6 +692,26 @@ void FGFDM::setOutputProperties(float dt)
|
|||
_cg_y->setFloatValue(cg[1]);
|
||||
_cg_z->setFloatValue(cg[2]);
|
||||
|
||||
State* s = _airplane.getModel()->getState();
|
||||
float v[3], acc[3], rot[3], racc[3];
|
||||
Math::vmul33(s->orient, s->v, v);
|
||||
Math::vmul33(s->orient, s->acc, acc);
|
||||
Math::vmul33(s->orient, s->rot, rot);
|
||||
Math::vmul33(s->orient, s->racc, racc);
|
||||
|
||||
_vxN->setFloatValue(v[0]);
|
||||
_vyN->setFloatValue(v[1]);
|
||||
_vzN->setFloatValue(v[2]);
|
||||
_vrxN->setFloatValue(rot[0]);
|
||||
_vryN->setFloatValue(rot[1]);
|
||||
_vrzN->setFloatValue(rot[2]);
|
||||
_axN->setFloatValue(acc[0]);
|
||||
_ayN->setFloatValue(acc[1]);
|
||||
_azN->setFloatValue(acc[2]);
|
||||
_arxN->setFloatValue(racc[0]);
|
||||
_aryN->setFloatValue(racc[1]);
|
||||
_arzN->setFloatValue(racc[2]);
|
||||
|
||||
ControlMap* cm = _airplane.getControlMap();
|
||||
for(int i=0; i<_controlProps.size(); i++) {
|
||||
PropOut* p = (PropOut*)_controlProps.get(i);
|
||||
|
@ -745,7 +832,12 @@ Wing* FGFDM::parseWing(XMLAttributes* a, const char* type, Version * version)
|
|||
w->setSweep(attrf(a, "sweep", 0) * DEG2RAD);
|
||||
w->setTaper(attrf(a, "taper", 1));
|
||||
w->setDihedral(attrf(a, "dihedral", defDihed) * DEG2RAD);
|
||||
w->setCamber(attrf(a, "camber", 0));
|
||||
|
||||
float camber = attrf(a, "camber", 0);
|
||||
if (!version->isVersionOrNewer(Version::YASIM_VERSION_2017_2) && (camber == 0)) {
|
||||
SG_LOG(SG_FLIGHT, SG_DEV_WARN, "YASIM warning: versions before 2017.2 are buggy for wings with camber=0");
|
||||
}
|
||||
w->setCamber(camber);
|
||||
|
||||
// These come in with positive indicating positive AoA, but the
|
||||
// internals expect a rotation about the left-pointing Y axis, so
|
||||
|
@ -1007,26 +1099,7 @@ void FGFDM::parsePropeller(XMLAttributes* a)
|
|||
_currObj = thruster;
|
||||
}
|
||||
|
||||
// Turns a string axis name into an integer for use by the
|
||||
// ControlMap. Creates a new axis if this one hasn't been defined
|
||||
// yet.
|
||||
int FGFDM::parseAxis(const char* name)
|
||||
{
|
||||
for(int i=0; i<_axes.size(); i++) {
|
||||
AxisRec* a = (AxisRec*)_axes.get(i);
|
||||
if(eq(a->name, name))
|
||||
return a->handle;
|
||||
}
|
||||
|
||||
// Not there, make a new one.
|
||||
AxisRec* a = new AxisRec();
|
||||
a->name = dup(name);
|
||||
fgGetNode( a->name, true ); // make sure the property name exists
|
||||
a->handle = _airplane.getControlMap()->newInput();
|
||||
_axes.add(a);
|
||||
return a->handle;
|
||||
}
|
||||
|
||||
/// map identifier (string) to int (enum in ControlMap)
|
||||
int FGFDM::parseOutput(const char* name)
|
||||
{
|
||||
if(eq(name, "THROTTLE")) return ControlMap::THROTTLE;
|
||||
|
|
|
@ -31,7 +31,6 @@ public:
|
|||
float getVehicleRadius(void) const { return _vehicle_radius; }
|
||||
|
||||
private:
|
||||
struct AxisRec { char* name; int handle; };
|
||||
struct EngRec { char* prefix; Thruster* eng; };
|
||||
struct WeightRec { char* prop; float size; int handle; };
|
||||
struct PropOut { SGPropertyNode* prop; int handle, type; bool left;
|
||||
|
@ -41,7 +40,6 @@ private:
|
|||
|
||||
Rotor* parseRotor(XMLAttributes* a, const char* name);
|
||||
Wing* parseWing(XMLAttributes* a, const char* name, Version * version);
|
||||
int parseAxis(const char* name);
|
||||
int parseOutput(const char* name);
|
||||
void parseWeight(XMLAttributes* a);
|
||||
void parseTurbineEngine(XMLAttributes* a);
|
||||
|
@ -64,10 +62,6 @@ private:
|
|||
// Aerodynamic turbulence model
|
||||
Turbulence* _turb;
|
||||
|
||||
// The list of "axes" that we expect to find as input. These are
|
||||
// typically property names.
|
||||
Vector _axes;
|
||||
|
||||
// Settable weights
|
||||
Vector _weights;
|
||||
|
||||
|
@ -107,9 +101,23 @@ private:
|
|||
SGPropertyNode_ptr _cg_x;
|
||||
SGPropertyNode_ptr _cg_y;
|
||||
SGPropertyNode_ptr _cg_z;
|
||||
SGPropertyNode_ptr _yasimN;
|
||||
|
||||
std::vector<SGPropertyNode_ptr> _tank_level_lbs;
|
||||
std::vector<ThrusterProps> _thrust_props;
|
||||
std::vector<FuelProps> _fuel_props;
|
||||
SGPropertyNode_ptr _vxN;
|
||||
SGPropertyNode_ptr _vyN;
|
||||
SGPropertyNode_ptr _vzN;
|
||||
SGPropertyNode_ptr _vrxN;
|
||||
SGPropertyNode_ptr _vryN;
|
||||
SGPropertyNode_ptr _vrzN;
|
||||
SGPropertyNode_ptr _axN;
|
||||
SGPropertyNode_ptr _ayN;
|
||||
SGPropertyNode_ptr _azN;
|
||||
SGPropertyNode_ptr _arxN;
|
||||
SGPropertyNode_ptr _aryN;
|
||||
SGPropertyNode_ptr _arzN;
|
||||
};
|
||||
|
||||
}; // namespace yasim
|
||||
|
|
|
@ -53,98 +53,6 @@ Gear::Gear()
|
|||
_global_ground[3] = -1e3;
|
||||
}
|
||||
|
||||
void Gear::setPosition(float* position)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<3; i++) _pos[i] = position[i];
|
||||
}
|
||||
|
||||
void Gear::setCompression(float* compression)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<3; i++) _cmpr[i] = compression[i];
|
||||
}
|
||||
|
||||
void Gear::setSpring(float spring)
|
||||
{
|
||||
_spring = spring;
|
||||
}
|
||||
|
||||
void Gear::setDamping(float damping)
|
||||
{
|
||||
_damp = damping;
|
||||
}
|
||||
|
||||
void Gear::setStaticFriction(float sfric)
|
||||
{
|
||||
_sfric = sfric;
|
||||
}
|
||||
|
||||
void Gear::setDynamicFriction(float dfric)
|
||||
{
|
||||
_dfric = dfric;
|
||||
}
|
||||
|
||||
void Gear::setBrake(float brake)
|
||||
{
|
||||
_brake = Math::clamp(brake, 0, 1);
|
||||
}
|
||||
|
||||
void Gear::setRotation(float rotation)
|
||||
{
|
||||
_rot = rotation;
|
||||
}
|
||||
|
||||
void Gear::setExtension(float extension)
|
||||
{
|
||||
_extension = Math::clamp(extension, 0, 1);
|
||||
}
|
||||
|
||||
void Gear::setCastering(bool c)
|
||||
{
|
||||
_castering = c;
|
||||
}
|
||||
|
||||
void Gear::setContactPoint(bool c)
|
||||
{
|
||||
_isContactPoint=c;
|
||||
}
|
||||
|
||||
void Gear::setOnWater(bool c)
|
||||
{
|
||||
_onWater = c;
|
||||
}
|
||||
|
||||
void Gear::setOnSolid(bool c)
|
||||
{
|
||||
_onSolid = c;
|
||||
}
|
||||
|
||||
void Gear::setIgnoreWhileSolving(bool c)
|
||||
{
|
||||
_ignoreWhileSolving = c;
|
||||
}
|
||||
|
||||
void Gear::setSpringFactorNotPlaning(float f)
|
||||
{
|
||||
_spring_factor_not_planing = f;
|
||||
}
|
||||
|
||||
void Gear::setSpeedPlaning(float s)
|
||||
{
|
||||
_speed_planing = s;
|
||||
}
|
||||
|
||||
void Gear::setReduceFrictionByExtension(float s)
|
||||
{
|
||||
_reduceFrictionByExtension = s;
|
||||
}
|
||||
|
||||
void Gear::setInitialLoad(float l)
|
||||
{
|
||||
_initialLoad = l;
|
||||
}
|
||||
|
||||
void Gear::setGlobalGround(double *global_ground, float* global_vel,
|
||||
double globalX, double globalY,
|
||||
const simgear::BVHMaterial *material)
|
||||
|
@ -183,57 +91,9 @@ void Gear::setGlobalGround(double *global_ground, float* global_vel,
|
|||
|
||||
}
|
||||
|
||||
void Gear::getPosition(float* out)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<3; i++) out[i] = _pos[i];
|
||||
}
|
||||
|
||||
void Gear::getCompression(float* out)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<3; i++) out[i] = _cmpr[i];
|
||||
}
|
||||
|
||||
void Gear::getGlobalGround(double* global_ground)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<4; i++) global_ground[i] = _global_ground[i];
|
||||
}
|
||||
|
||||
float Gear::getSpring()
|
||||
{
|
||||
return _spring;
|
||||
}
|
||||
|
||||
float Gear::getDamping()
|
||||
{
|
||||
return _damp;
|
||||
}
|
||||
|
||||
float Gear::getStaticFriction()
|
||||
{
|
||||
return _sfric;
|
||||
}
|
||||
|
||||
float Gear::getDynamicFriction()
|
||||
{
|
||||
return _dfric;
|
||||
}
|
||||
|
||||
float Gear::getBrake()
|
||||
{
|
||||
return _brake;
|
||||
}
|
||||
|
||||
float Gear::getRotation()
|
||||
{
|
||||
return _rot;
|
||||
}
|
||||
|
||||
float Gear::getExtension()
|
||||
{
|
||||
return _extension;
|
||||
for(int i=0; i<4; i++) global_ground[i] = _global_ground[i];
|
||||
}
|
||||
|
||||
void Gear::getForce(float* force, float* contact)
|
||||
|
@ -242,25 +102,6 @@ void Gear::getForce(float* force, float* contact)
|
|||
Math::set3(_contact, contact);
|
||||
}
|
||||
|
||||
float Gear::getWoW()
|
||||
{
|
||||
return _wow;
|
||||
}
|
||||
|
||||
float Gear::getCompressFraction()
|
||||
{
|
||||
return _frac;
|
||||
}
|
||||
|
||||
bool Gear::getCastering()
|
||||
{
|
||||
return _castering;
|
||||
}
|
||||
|
||||
bool Gear::getGroundIsSolid()
|
||||
{
|
||||
return _ground_isSolid;
|
||||
}
|
||||
|
||||
float Gear::getBumpAltitude()
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef _GEAR_HPP
|
||||
#define _GEAR_HPP
|
||||
#include "Math.hpp"
|
||||
|
||||
namespace simgear {
|
||||
class BVHMaterial;
|
||||
|
@ -33,42 +34,43 @@ public:
|
|||
Gear();
|
||||
|
||||
// Externally set values
|
||||
void setPosition(float* position);
|
||||
void setCompression(float* compression);
|
||||
void setSpring(float spring);
|
||||
void setDamping(float damping);
|
||||
void setStaticFriction(float sfric);
|
||||
void setDynamicFriction(float dfric);
|
||||
void setBrake(float brake);
|
||||
void setRotation(float rotation);
|
||||
void setExtension(float extension);
|
||||
void setCastering(bool castering);
|
||||
void setOnWater(bool c);
|
||||
void setOnSolid(bool c);
|
||||
void setSpringFactorNotPlaning(float f);
|
||||
void setSpeedPlaning(float s);
|
||||
void setReduceFrictionByExtension(float s);
|
||||
void setInitialLoad(float l);
|
||||
void setIgnoreWhileSolving(bool c);
|
||||
void setPosition(float* position) { Math::set3(position, _pos); }
|
||||
void getPosition(float* out) { Math::set3(_pos, out); }
|
||||
void setCompression(float* compression) { Math::set3(compression, _cmpr); }
|
||||
void getCompression(float* out) { Math::set3(_cmpr, out); }
|
||||
void setSpring(float spring) { _spring = spring; }
|
||||
float getSpring() { return _spring; }
|
||||
void setDamping(float damping) { _damp = damping; }
|
||||
float getDamping() {return _damp; }
|
||||
void setStaticFriction(float sfric) { _sfric = sfric; }
|
||||
float getStaticFriction() { return _sfric; }
|
||||
void setDynamicFriction(float dfric) { _dfric = dfric; }
|
||||
float getDynamicFriction() { return _dfric; }
|
||||
void setBrake(float brake) { _brake = Math::clamp(brake, 0, 1); }
|
||||
float getBrake() { return _brake; }
|
||||
void setRotation(float rotation) { _rot = rotation; }
|
||||
float getRotation() { return _rot; }
|
||||
void setExtension(float extension) { _extension = Math::clamp(extension, 0, 1); }
|
||||
float getExtension() { return _extension; }
|
||||
void setCastering(bool c) { _castering = c; }
|
||||
bool getCastering() { return _castering; }
|
||||
void setOnWater(bool c) { _onWater = c; }
|
||||
void setOnSolid(bool c) { _onSolid = c; }
|
||||
void setSpringFactorNotPlaning(float f) { _spring_factor_not_planing = f; }
|
||||
void setSpeedPlaning(float s) { _speed_planing = s; }
|
||||
void setReduceFrictionByExtension(float s) { _reduceFrictionByExtension = s; }
|
||||
void setInitialLoad(float l) { _initialLoad = l; }
|
||||
float getInitialLoad() {return _initialLoad; }
|
||||
void setIgnoreWhileSolving(bool c) { _ignoreWhileSolving = c; }
|
||||
|
||||
void setGlobalGround(double* global_ground, float* global_vel,
|
||||
double globalX, double globalY,
|
||||
const simgear::BVHMaterial *material);
|
||||
void getPosition(float* out);
|
||||
void getCompression(float* out);
|
||||
const simgear::BVHMaterial *material);
|
||||
void getGlobalGround(double* global_ground);
|
||||
float getSpring();
|
||||
float getDamping();
|
||||
float getStaticFriction();
|
||||
float getDynamicFriction();
|
||||
float getBrake();
|
||||
float getRotation();
|
||||
float getExtension();
|
||||
float getInitialLoad() {return _initialLoad; }
|
||||
bool getCastering();
|
||||
float getCasterAngle() { return _casterAngle; }
|
||||
float getRollSpeed() { return _rollSpeed; }
|
||||
float getBumpAltitude();
|
||||
bool getGroundIsSolid();
|
||||
bool getGroundIsSolid() { return _ground_isSolid; }
|
||||
float getGroundFrictionFactor() { return (float)_ground_frictionFactor; }
|
||||
void integrate(float dt);
|
||||
|
||||
|
@ -81,12 +83,12 @@ public:
|
|||
// Computed values: total force, weight-on-wheels (force normal to
|
||||
// ground) and compression fraction.
|
||||
void getForce(float* force, float* contact);
|
||||
float getWoW();
|
||||
float getCompressFraction();
|
||||
float getWoW() { return _wow; }
|
||||
float getCompressFraction() { return _frac; }
|
||||
float getCompressDist() { return _compressDist; }
|
||||
bool getSubmergable() {return (!_ground_isSolid)&&(!_isContactPoint); }
|
||||
bool getIgnoreWhileSolving() {return _ignoreWhileSolving; }
|
||||
void setContactPoint(bool c);
|
||||
void setContactPoint(bool c) { _isContactPoint=c; }
|
||||
|
||||
private:
|
||||
float calcFriction(float wgt, float v);
|
||||
|
|
|
@ -44,17 +44,17 @@ public:
|
|||
|
||||
// Some 3D vector stuff. In all cases, it is permissible for the
|
||||
// "out" vector to be the same as one of the inputs.
|
||||
static inline void set3(float* v, float* out) {
|
||||
static inline void set3(const float* v, float* out) {
|
||||
out[0] = v[0];
|
||||
out[1] = v[1];
|
||||
out[2] = v[2];
|
||||
}
|
||||
|
||||
static inline float dot3(float* a, float* b) {
|
||||
static inline float dot3(const float* a, const float* b) {
|
||||
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
|
||||
}
|
||||
|
||||
static inline void cross3(float* a, float* b, float* out) {
|
||||
static inline void cross3(const float* a, const float* b, float* out) {
|
||||
float ax=a[0], ay=a[1], az=a[2];
|
||||
float bx=b[0], by=b[1], bz=b[2];
|
||||
out[0] = ay*bz - by*az;
|
||||
|
@ -62,30 +62,30 @@ public:
|
|||
out[2] = ax*by - bx*ay;
|
||||
}
|
||||
|
||||
static inline void mul3(float scalar, float* v, float* out)
|
||||
static inline void mul3(const float scalar, const float* v, float* out)
|
||||
{
|
||||
out[0] = scalar * v[0];
|
||||
out[1] = scalar * v[1];
|
||||
out[2] = scalar * v[2];
|
||||
}
|
||||
|
||||
static inline void add3(float* a, float* b, float* out){
|
||||
static inline void add3(const float* a, const float* b, float* out){
|
||||
out[0] = a[0] + b[0];
|
||||
out[1] = a[1] + b[1];
|
||||
out[2] = a[2] + b[2];
|
||||
}
|
||||
|
||||
static inline void sub3(float* a, float* b, float* out) {
|
||||
static inline void sub3(const float* a, const float* b, float* out) {
|
||||
out[0] = a[0] - b[0];
|
||||
out[1] = a[1] - b[1];
|
||||
out[2] = a[2] - b[2];
|
||||
}
|
||||
|
||||
static inline float mag3(float* v) {
|
||||
static inline float mag3(const float* v) {
|
||||
return sqrt(dot3(v, v));
|
||||
}
|
||||
|
||||
static inline void unit3(float* v, float* out) {
|
||||
static inline void unit3(const float* v, float* out) {
|
||||
float imag = 1/mag3(v);
|
||||
mul3(imag, v, out);
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ public:
|
|||
// 6 7 8
|
||||
|
||||
// Multiply two matrices
|
||||
static void mmul33(float* a, float* b, float* out) {
|
||||
static void mmul33(const float* a, const float* b, float* out) {
|
||||
float tmp[9];
|
||||
tmp[0] = a[0]*b[0] + a[1]*b[3] + a[2]*b[6];
|
||||
tmp[3] = a[3]*b[0] + a[4]*b[3] + a[5]*b[6];
|
||||
|
@ -114,7 +114,7 @@ public:
|
|||
}
|
||||
|
||||
// Multiply by vector
|
||||
static inline void vmul33(float* m, float* v, float* out) {
|
||||
static inline void vmul33(const float* m, const float* v, float* out) {
|
||||
float x = v[0], y = v[1], z = v[2];
|
||||
out[0] = x*m[0] + y*m[1] + z*m[2];
|
||||
out[1] = x*m[3] + y*m[4] + z*m[5];
|
||||
|
@ -123,43 +123,41 @@ public:
|
|||
|
||||
// Multiply the vector by the matrix transpose. Or pre-multiply the
|
||||
// matrix by v as a row vector. Same thing.
|
||||
static inline void tmul33(float* m, float* v, float* out) {
|
||||
static inline void tmul33(const float* m, const float* v, float* out) {
|
||||
float x = v[0], y = v[1], z = v[2];
|
||||
out[0] = x*m[0] + y*m[3] + z*m[6];
|
||||
out[1] = x*m[1] + y*m[4] + z*m[7];
|
||||
out[2] = x*m[2] + y*m[5] + z*m[8];
|
||||
}
|
||||
|
||||
// Invert matrix
|
||||
static void invert33(float* m, float* out) {
|
||||
/// Invert symmetric matrix; ~1/3 less calculations due to symmetry
|
||||
static void invert33_sym(const float* m, float* out) {
|
||||
// Compute the inverse as the adjoint matrix times 1/(det M).
|
||||
// A, B ... I are the cofactors of a b c
|
||||
// d e f
|
||||
// g h i
|
||||
// symetric: d=b, g=c, h=f
|
||||
float a=m[0], b=m[1], c=m[2];
|
||||
float d=m[3], e=m[4], f=m[5];
|
||||
float g=m[6], h=m[7], i=m[8];
|
||||
float e=m[4], f=m[5];
|
||||
float i=m[8];
|
||||
|
||||
float A = (e*i - h*f);
|
||||
float B = -(d*i - g*f);
|
||||
float C = (d*h - g*e);
|
||||
float D = -(b*i - h*c);
|
||||
float E = (a*i - g*c);
|
||||
float F = -(a*h - g*b);
|
||||
float G = (b*f - e*c);
|
||||
float H = -(a*f - d*c);
|
||||
float I = (a*e - d*b);
|
||||
float A = (e*i - f*f);
|
||||
float B = -(b*i - c*f);
|
||||
float C = (b*f - c*e);
|
||||
float E = (a*i - c*c);
|
||||
float F = -(a*f - c*b);
|
||||
float I = (a*e - b*b);
|
||||
|
||||
float id = 1/(a*A + b*B + c*C);
|
||||
|
||||
out[0] = id*A; out[1] = id*D; out[2] = id*G;
|
||||
out[3] = id*B; out[4] = id*E; out[5] = id*H;
|
||||
out[6] = id*C; out[7] = id*F; out[8] = id*I;
|
||||
out[0] = id*A; out[1] = id*B; out[2] = id*C;
|
||||
out[3] = out[1]; out[4] = id*E; out[5] = id*F;
|
||||
out[6] = out[2]; out[7] = out[5]; out[8] = id*I;
|
||||
}
|
||||
|
||||
// Transpose matrix (for an orthonormal orientation matrix, this
|
||||
// is the same as the inverse).
|
||||
static inline void trans33(float* m, float* out) {
|
||||
static inline void trans33(const float* m, float* out) {
|
||||
// 0 1 2 Elements 0, 4, and 8 are the same
|
||||
// 3 4 5 Swap elements 1/3, 2/6, and 5/7
|
||||
// 6 7 8
|
||||
|
@ -184,7 +182,7 @@ public:
|
|||
// xOut becomes the unit vector in the direction of x
|
||||
// yOut is perpendicular to xOut in the x/y plane
|
||||
// zOut becomes the unit vector: (xOut cross yOut)
|
||||
static void ortho33(float* x, float* y,
|
||||
static void ortho33(const float* x, const float* y,
|
||||
float* xOut, float* yOut, float* zOut) {
|
||||
float x0[3], y0[3];
|
||||
set3(x, x0);
|
||||
|
|
|
@ -66,13 +66,20 @@ Model::Model()
|
|||
_hook = 0;
|
||||
_launchbar = 0;
|
||||
|
||||
_groundEffectSpan = 0;
|
||||
_wingSpan = 0;
|
||||
_groundEffect = 0;
|
||||
for(i=0; i<3; i++) _wingCenter[i] = 0;
|
||||
for(i=0; i<3; i++) _geRefPoint[i] = 0;
|
||||
|
||||
_global_ground[0] = 0; _global_ground[1] = 0; _global_ground[2] = 1;
|
||||
_global_ground[3] = -100000;
|
||||
|
||||
_modelN = fgGetNode("/fdm/yasim/forces", true);
|
||||
_f0xN = _modelN->getNode("f0-aero-x-drag", true);
|
||||
_f0yN = _modelN->getNode("f0-aero-y-side", true);
|
||||
_f0zN = _modelN->getNode("f0-aero-z-lift", true);
|
||||
_gefxN = _modelN->getNode("gndeff-f-x", true);
|
||||
_gefyN = _modelN->getNode("gndeff-f-y", true);
|
||||
_gefzN = _modelN->getNode("gndeff-f-z", true);
|
||||
_wgdistN = _modelN->getNode("wing-gnd-dist", true);
|
||||
}
|
||||
|
||||
Model::~Model()
|
||||
|
@ -175,106 +182,12 @@ void Model::iterate()
|
|||
_integrator.calcNewInterval();
|
||||
}
|
||||
|
||||
bool Model::isCrashed()
|
||||
{
|
||||
return _crashed;
|
||||
}
|
||||
|
||||
void Model::setCrashed(bool crashed)
|
||||
{
|
||||
_crashed = crashed;
|
||||
}
|
||||
|
||||
float Model::getAGL()
|
||||
{
|
||||
return _agl;
|
||||
}
|
||||
|
||||
State* Model::getState()
|
||||
{
|
||||
return _s;
|
||||
}
|
||||
|
||||
void Model::setState(State* s)
|
||||
{
|
||||
_integrator.setState(s);
|
||||
_s = _integrator.getState();
|
||||
}
|
||||
|
||||
RigidBody* Model::getBody()
|
||||
{
|
||||
return &_body;
|
||||
}
|
||||
|
||||
Integrator* Model::getIntegrator()
|
||||
{
|
||||
return &_integrator;
|
||||
}
|
||||
|
||||
Surface* Model::getSurface(int handle)
|
||||
{
|
||||
return (Surface*)_surfaces.get(handle);
|
||||
}
|
||||
|
||||
Rotorgear* Model::getRotorgear(void)
|
||||
{
|
||||
return &_rotorgear;
|
||||
}
|
||||
|
||||
int Model::addThruster(Thruster* t)
|
||||
{
|
||||
return _thrusters.add(t);
|
||||
}
|
||||
|
||||
Hook* Model::getHook(void)
|
||||
{
|
||||
return _hook;
|
||||
}
|
||||
|
||||
Launchbar* Model::getLaunchbar(void)
|
||||
{
|
||||
return _launchbar;
|
||||
}
|
||||
|
||||
int Model::numThrusters()
|
||||
{
|
||||
return _thrusters.size();
|
||||
}
|
||||
|
||||
Thruster* Model::getThruster(int handle)
|
||||
{
|
||||
return (Thruster*)_thrusters.get(handle);
|
||||
}
|
||||
|
||||
void Model::setThruster(int handle, Thruster* t)
|
||||
{
|
||||
_thrusters.set(handle, t);
|
||||
}
|
||||
|
||||
int Model::addSurface(Surface* surf)
|
||||
{
|
||||
return _surfaces.add(surf);
|
||||
}
|
||||
|
||||
int Model::addGear(Gear* gear)
|
||||
{
|
||||
return _gears.add(gear);
|
||||
}
|
||||
|
||||
void Model::addHook(Hook* hook)
|
||||
{
|
||||
_hook = hook;
|
||||
}
|
||||
|
||||
void Model::addLaunchbar(Launchbar* launchbar)
|
||||
{
|
||||
_launchbar = launchbar;
|
||||
}
|
||||
|
||||
int Model::addHitch(Hitch* hitch)
|
||||
{
|
||||
return _hitches.add(hitch);
|
||||
}
|
||||
|
||||
void Model::setGroundCallback(Ground* ground_cb)
|
||||
{
|
||||
|
@ -282,30 +195,20 @@ void Model::setGroundCallback(Ground* ground_cb)
|
|||
_ground_cb = ground_cb;
|
||||
}
|
||||
|
||||
Ground* Model::getGroundCallback(void)
|
||||
void Model::setGroundEffect(const float* pos, const float span, const float mul)
|
||||
{
|
||||
return _ground_cb;
|
||||
}
|
||||
|
||||
void Model::setGroundEffect(float* pos, float span, float mul)
|
||||
{
|
||||
Math::set3(pos, _wingCenter);
|
||||
_groundEffectSpan = span;
|
||||
Math::set3(pos, _geRefPoint);
|
||||
_wingSpan = span;
|
||||
_groundEffect = mul;
|
||||
}
|
||||
|
||||
void Model::setAir(float pressure, float temp, float density)
|
||||
void Model::setAir(const float pressure, const float temp, const float density)
|
||||
{
|
||||
_pressure = pressure;
|
||||
_temp = temp;
|
||||
_rho = density;
|
||||
}
|
||||
|
||||
void Model::setWind(float* wind)
|
||||
{
|
||||
Math::set3(wind, _wind);
|
||||
}
|
||||
|
||||
void Model::updateGround(State* s)
|
||||
{
|
||||
float dummy[3];
|
||||
|
@ -390,11 +293,11 @@ void Model::calcForces(State* s)
|
|||
_body.addTorque(_torque);
|
||||
int i,j;
|
||||
for(i=0; i<_thrusters.size(); i++) {
|
||||
Thruster* t = (Thruster*)_thrusters.get(i);
|
||||
float thrust[3], pos[3];
|
||||
t->getThrust(thrust);
|
||||
t->getPosition(pos);
|
||||
_body.addForce(pos, thrust);
|
||||
Thruster* t = (Thruster*)_thrusters.get(i);
|
||||
float thrust[3], pos[3];
|
||||
t->getThrust(thrust);
|
||||
t->getPosition(pos);
|
||||
_body.addForce(pos, thrust);
|
||||
}
|
||||
|
||||
// Get a ground plane in local coordinates. The first three
|
||||
|
@ -417,20 +320,26 @@ void Model::calcForces(State* s)
|
|||
float faero[3];
|
||||
faero[0] = faero[1] = faero[2] = 0;
|
||||
for(i=0; i<_surfaces.size(); i++) {
|
||||
Surface* sf = (Surface*)_surfaces.get(i);
|
||||
Surface* sf = (Surface*)_surfaces.get(i);
|
||||
|
||||
// Vsurf = wind - velocity + (rot cross (cg - pos))
|
||||
float vs[3], pos[3];
|
||||
sf->getPosition(pos);
|
||||
localWind(pos, s, vs, alt);
|
||||
// Vsurf = wind - velocity + (rot cross (cg - pos))
|
||||
float vs[3], pos[3];
|
||||
sf->getPosition(pos);
|
||||
localWind(pos, s, vs, alt);
|
||||
|
||||
float force[3], torque[3];
|
||||
sf->calcForce(vs, _rho, force, torque);
|
||||
Math::add3(faero, force, faero);
|
||||
float force[3], torque[3];
|
||||
sf->calcForce(vs, _rho, force, torque);
|
||||
Math::add3(faero, force, faero);
|
||||
|
||||
_body.addForce(pos, force);
|
||||
_body.addTorque(torque);
|
||||
_body.addForce(pos, force);
|
||||
_body.addTorque(torque);
|
||||
}
|
||||
if (_modelN != 0) {
|
||||
_f0xN->setFloatValue(faero[0]);
|
||||
_f0yN->setFloatValue(faero[1]);
|
||||
_f0zN->setFloatValue(faero[2]);
|
||||
}
|
||||
|
||||
for (j=0; j<_rotorgear.getRotors()->size();j++)
|
||||
{
|
||||
Rotor* r = (Rotor *)_rotorgear.getRotors()->get(j);
|
||||
|
@ -470,18 +379,30 @@ void Model::calcForces(State* s)
|
|||
// Account for ground effect by multiplying the vertical force
|
||||
// component by an amount linear with the fraction of the wingspan
|
||||
// above the ground.
|
||||
if ((_groundEffectSpan != 0) && (_groundEffect != 0 ))
|
||||
if ((_wingSpan != 0) && (_groundEffect != 0 ))
|
||||
{
|
||||
float dist = ground[3] - Math::dot3(ground, _wingCenter);
|
||||
if(dist > 0 && dist < _groundEffectSpan) {
|
||||
float fz = Math::dot3(faero, ground);
|
||||
fz *= (_groundEffectSpan - dist) / _groundEffectSpan;
|
||||
fz *= _groundEffect;
|
||||
Math::mul3(fz, ground, faero);
|
||||
_body.addForce(faero);
|
||||
}
|
||||
}
|
||||
// distance between ground and wing ref. point
|
||||
float dist = ground[3] - Math::dot3(ground, _geRefPoint);
|
||||
float fz = 0;
|
||||
float geForce[3];
|
||||
if(dist > 0 && dist < _wingSpan) {
|
||||
fz = Math::dot3(faero, ground);
|
||||
fz *= (_wingSpan - dist) / _wingSpan;
|
||||
fz *= _groundEffect;
|
||||
Math::mul3(fz, ground, geForce);
|
||||
_body.addForce(geForce);
|
||||
}
|
||||
if (_modelN != 0) {
|
||||
_gefxN->setFloatValue(geForce[0]);
|
||||
_gefyN->setFloatValue(geForce[1]);
|
||||
_gefzN->setFloatValue(geForce[2]);
|
||||
_wgdistN->setFloatValue(dist);
|
||||
//float ld0 = faero[2]/faero[0];
|
||||
//float ld = (geForce[2]+faero[2])/(geForce[0]+faero[0]);
|
||||
//n->getNode("gndeff-ld-ld0", true)->setFloatValue(ld/ld0);
|
||||
|
||||
}
|
||||
}
|
||||
// Convert the velocity and rotation vectors to local coordinates
|
||||
float lrot[3], lv[3];
|
||||
Math::vmul33(s->orient, s->rot, lrot);
|
||||
|
@ -561,7 +482,7 @@ void Model::newState(State* s)
|
|||
|
||||
// Calculates the airflow direction at the given point and for the
|
||||
// specified aircraft velocity.
|
||||
void Model::localWind(float* pos, State* s, float* out, float alt, bool is_rotor)
|
||||
void Model::localWind(const float* pos, yasim::State* s, float* out, float alt, bool is_rotor)
|
||||
{
|
||||
float tmp[3], lwind[3], lrot[3], lv[3];
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "Vector.hpp"
|
||||
#include "Turbulence.hpp"
|
||||
#include "Rotor.hpp"
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
namespace yasim {
|
||||
|
||||
|
@ -26,49 +27,49 @@ public:
|
|||
Model();
|
||||
virtual ~Model();
|
||||
|
||||
RigidBody* getBody();
|
||||
Integrator* getIntegrator();
|
||||
RigidBody* getBody() { return &_body; }
|
||||
Integrator* getIntegrator() { return &_integrator; }
|
||||
|
||||
void setTurbulence(Turbulence* turb) { _turb = turb; }
|
||||
|
||||
State* getState();
|
||||
State* getState() { return _s; }
|
||||
void setState(State* s);
|
||||
|
||||
bool isCrashed();
|
||||
void setCrashed(bool crashed);
|
||||
float getAGL();
|
||||
bool isCrashed() { return _crashed; }
|
||||
void setCrashed(bool crashed) { _crashed = crashed; }
|
||||
float getAGL() { return _agl; }
|
||||
|
||||
void iterate();
|
||||
|
||||
// Externally-managed subcomponents
|
||||
int addThruster(Thruster* t);
|
||||
int addSurface(Surface* surf);
|
||||
int addGear(Gear* gear);
|
||||
void addHook(Hook* hook);
|
||||
void addLaunchbar(Launchbar* launchbar);
|
||||
Surface* getSurface(int handle);
|
||||
Rotorgear* getRotorgear(void);
|
||||
int addThruster(Thruster* t) { return _thrusters.add(t); }
|
||||
int addSurface(Surface* surf) { return _surfaces.add(surf); }
|
||||
int addGear(Gear* gear) { return _gears.add(gear); }
|
||||
void addHook(Hook* hook) { _hook = hook; }
|
||||
void addLaunchbar(Launchbar* launchbar) { _launchbar = launchbar; }
|
||||
Surface* getSurface(int handle) { return (Surface*)_surfaces.get(handle); }
|
||||
Rotorgear* getRotorgear(void) { return &_rotorgear; }
|
||||
Gear* getGear(int handle);
|
||||
Hook* getHook(void);
|
||||
int addHitch(Hitch* hitch);
|
||||
Launchbar* getLaunchbar(void);
|
||||
Hook* getHook(void) { return _hook; }
|
||||
int addHitch(Hitch* hitch) { return _hitches.add(hitch); }
|
||||
Launchbar* getLaunchbar(void) { return _launchbar; }
|
||||
|
||||
// Semi-private methods for use by the Airplane solver.
|
||||
int numThrusters();
|
||||
Thruster* getThruster(int handle);
|
||||
void setThruster(int handle, Thruster* t);
|
||||
int numThrusters() { return _thrusters.size(); }
|
||||
Thruster* getThruster(int handle) { return (Thruster*)_thrusters.get(handle); }
|
||||
void setThruster(int handle, Thruster* t) { _thrusters.set(handle, t); }
|
||||
void initIteration();
|
||||
void getThrust(float* out);
|
||||
|
||||
void setGroundCallback(Ground* ground_cb);
|
||||
Ground* getGroundCallback(void);
|
||||
Ground* getGroundCallback(void) { return _ground_cb; }
|
||||
|
||||
//
|
||||
// Per-iteration settables
|
||||
//
|
||||
void setGroundEffect(float* pos, float span, float mul);
|
||||
void setWind(float* wind);
|
||||
void setAir(float pressure, float temp, float density);
|
||||
void setGroundEffect(const float* pos, const float span, const float mul);
|
||||
void setWind(float* wind) { Math::set3(wind, _wind); }
|
||||
void setAir(const float pressure, const float temp, const float density);
|
||||
|
||||
void updateGround(State* s);
|
||||
|
||||
|
@ -80,8 +81,7 @@ private:
|
|||
void initRotorIteration();
|
||||
void calcGearForce(Gear* g, float* v, float* rot, float* ground);
|
||||
float gearFriction(float wgt, float v, Gear* g);
|
||||
void localWind(float* pos, State* s, float* out, float alt,
|
||||
bool is_rotor = false);
|
||||
void localWind(const float* pos, State* s, float* out, float alt, bool is_rotor = false);
|
||||
|
||||
Integrator _integrator;
|
||||
RigidBody _body;
|
||||
|
@ -96,9 +96,9 @@ private:
|
|||
Launchbar* _launchbar;
|
||||
Vector _hitches;
|
||||
|
||||
float _groundEffectSpan;
|
||||
float _wingSpan;
|
||||
float _groundEffect;
|
||||
float _wingCenter[3];
|
||||
float _geRefPoint[3];
|
||||
|
||||
Ground* _ground_cb;
|
||||
double _global_ground[4];
|
||||
|
@ -114,6 +114,14 @@ private:
|
|||
State* _s;
|
||||
bool _crashed;
|
||||
float _agl;
|
||||
SGPropertyNode_ptr _modelN;
|
||||
SGPropertyNode_ptr _f0xN;
|
||||
SGPropertyNode_ptr _f0yN;
|
||||
SGPropertyNode_ptr _f0zN;
|
||||
SGPropertyNode_ptr _gefxN;
|
||||
SGPropertyNode_ptr _gefyN;
|
||||
SGPropertyNode_ptr _gefzN;
|
||||
SGPropertyNode_ptr _wgdistN;
|
||||
};
|
||||
|
||||
}; // namespace yasim
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "Math.hpp"
|
||||
#include <Main/fg_props.hxx>
|
||||
#include "RigidBody.hpp"
|
||||
|
||||
namespace yasim {
|
||||
|
||||
RigidBody::RigidBody()
|
||||
|
@ -11,6 +12,7 @@ RigidBody::RigidBody()
|
|||
_masses = new Mass[_massesAlloced];
|
||||
_gyro[0] = _gyro[1] = _gyro[2] = 0;
|
||||
_spin[0] = _spin[1] = _spin[2] = 0;
|
||||
_bodyN = fgGetNode("/fdm/yasim/model/masses", true);
|
||||
}
|
||||
|
||||
RigidBody::~RigidBody()
|
||||
|
@ -18,7 +20,9 @@ RigidBody::~RigidBody()
|
|||
delete[] _masses;
|
||||
}
|
||||
|
||||
int RigidBody::addMass(float mass, float* pos)
|
||||
/// add new point mass to body
|
||||
/// isStatic: set to true for masses that do not change per iteration (everything but fuel?)
|
||||
int RigidBody::addMass(float mass, float* pos, bool isStatic)
|
||||
{
|
||||
// If out of space, reallocate twice as much
|
||||
if(_nMasses == _massesAlloced) {
|
||||
|
@ -30,31 +34,37 @@ int RigidBody::addMass(float mass, float* pos)
|
|||
delete[] _masses;
|
||||
_masses = m2;
|
||||
}
|
||||
|
||||
_masses[_nMasses].m = mass;
|
||||
Math::set3(pos, _masses[_nMasses].p);
|
||||
setMass(_nMasses, mass, pos, isStatic);
|
||||
return _nMasses++;
|
||||
}
|
||||
|
||||
/// change mass
|
||||
/// handle: returned by addMass
|
||||
void RigidBody::setMass(int handle, float mass)
|
||||
{
|
||||
if (_masses[handle].m == mass)
|
||||
return;
|
||||
_masses[handle].m = mass;
|
||||
// if static mass is changed, reset pre-calculated mass
|
||||
// may apply to weights like cargo, pax, that usually do not change with FDM rate
|
||||
if (_masses[handle].isStatic)
|
||||
_staticMass.m = 0;
|
||||
if (_bodyN != 0)
|
||||
_bodyN->getChild("mass", handle, true)->getNode("mass", true)->setFloatValue(mass);
|
||||
}
|
||||
|
||||
void RigidBody::setMass(int handle, float mass, float* pos)
|
||||
void RigidBody::setMass(int handle, float mass, const float* pos, bool isStatic)
|
||||
{
|
||||
_masses[handle].m = mass;
|
||||
_masses[handle].isStatic = isStatic;
|
||||
Math::set3(pos, _masses[handle].p);
|
||||
}
|
||||
|
||||
int RigidBody::numMasses()
|
||||
{
|
||||
return _nMasses;
|
||||
}
|
||||
|
||||
float RigidBody::getMass(int handle)
|
||||
{
|
||||
return _masses[handle].m;
|
||||
setMass(handle, mass);
|
||||
if (_bodyN != 0) {
|
||||
SGPropertyNode_ptr n = _bodyN->getChild("mass", handle, true);
|
||||
n->getNode("isStatic", true)->setValue(isStatic);
|
||||
n->getNode("pos-x", true)->setFloatValue(pos[0]);
|
||||
n->getNode("pos-y", true)->setFloatValue(pos[1]);
|
||||
n->getNode("pos-z", true)->setFloatValue(pos[2]);
|
||||
}
|
||||
}
|
||||
|
||||
void RigidBody::getMassPosition(int handle, float* out)
|
||||
|
@ -64,60 +74,129 @@ void RigidBody::getMassPosition(int handle, float* out)
|
|||
out[2] = _masses[handle].p[2];
|
||||
}
|
||||
|
||||
float RigidBody::getTotalMass()
|
||||
{
|
||||
return _totalMass;
|
||||
}
|
||||
|
||||
// Calcualtes the rotational velocity of a particular point. All
|
||||
// coordinates are local!
|
||||
void RigidBody::pointVelocity(float* pos, float* rot, float* out)
|
||||
void RigidBody::pointVelocity(const float* pos, const float* rot, float* out)
|
||||
{
|
||||
Math::sub3(pos, _cg, out); // out = pos-cg
|
||||
Math::cross3(rot, out, out); // = rot cross (pos-cg)
|
||||
}
|
||||
|
||||
void RigidBody::setGyro(float* angularMomentum)
|
||||
void RigidBody::_recalcStatic()
|
||||
{
|
||||
Math::set3(angularMomentum, _gyro);
|
||||
// aggregate all masses that do not change (e.g. fuselage, wings) into one point mass
|
||||
_staticMass.m = 0;
|
||||
_staticMass.p[0] = 0;
|
||||
_staticMass.p[1] = 0;
|
||||
_staticMass.p[2] = 0;
|
||||
int i;
|
||||
int s = 0;
|
||||
for(i=0; i<_nMasses; i++) {
|
||||
if (_masses[i].isStatic) {
|
||||
s++;
|
||||
float m = _masses[i].m;
|
||||
_staticMass.m += m;
|
||||
_staticMass.p[0] += m * _masses[i].p[0];
|
||||
_staticMass.p[1] += m * _masses[i].p[1];
|
||||
_staticMass.p[2] += m * _masses[i].p[2];
|
||||
}
|
||||
}
|
||||
Math::mul3(1/_staticMass.m, _staticMass.p, _staticMass.p);
|
||||
if (_bodyN != 0) {
|
||||
_bodyN->getNode("aggregated-mass", true)->setFloatValue(_staticMass.m);
|
||||
_bodyN->getNode("aggregated-count", true)->setIntValue(s);
|
||||
_bodyN->getNode("aggregated-pos-x", true)->setFloatValue(_staticMass.p[0]);
|
||||
_bodyN->getNode("aggregated-pos-y", true)->setFloatValue(_staticMass.p[1]);
|
||||
_bodyN->getNode("aggregated-pos-z", true)->setFloatValue(_staticMass.p[2]);
|
||||
}
|
||||
// Now the inertia tensor:
|
||||
for(i=0; i<9; i++)
|
||||
_tI_static[i] = 0;
|
||||
|
||||
for(i=0; i<_nMasses; i++) {
|
||||
if (_masses[i].isStatic) {
|
||||
float m = _masses[i].m;
|
||||
|
||||
float x = _masses[i].p[0] - _staticMass.p[0];
|
||||
float y = _masses[i].p[1] - _staticMass.p[1];
|
||||
float z = _masses[i].p[2] - _staticMass.p[2];
|
||||
|
||||
float xy = m*x*y; float yz = m*y*z; float zx = m*z*x;
|
||||
float x2 = m*x*x; float y2 = m*y*y; float z2 = m*z*z;
|
||||
|
||||
// tensor is symmetric, so we can save some calculations in the loop
|
||||
_tI_static[0] += y2+z2; _tI_static[1] -= xy; _tI_static[2] -= zx;
|
||||
_tI_static[4] += x2+z2; _tI_static[5] -= yz;
|
||||
_tI_static[8] += x2+y2;
|
||||
}
|
||||
}
|
||||
// copy symmetric elements
|
||||
_tI_static[3] = _tI_static[1];
|
||||
_tI_static[6] = _tI_static[2];
|
||||
_tI_static[7] = _tI_static[5];
|
||||
}
|
||||
|
||||
/// calculate the total mass, centre of gravity and inertia tensor
|
||||
/**
|
||||
recalc is used when compiling the model but more important it is called in
|
||||
Model::iterate() e.g. at FDM rate (120 Hz)
|
||||
We can save some CPU due to the symmetry of the tensor and by aggregating
|
||||
masses that do not change during flight.
|
||||
*/
|
||||
void RigidBody::recalc()
|
||||
{
|
||||
// Calculate the c.g and total mass:
|
||||
_totalMass = 0;
|
||||
_cg[0] = _cg[1] = _cg[2] = 0;
|
||||
//aggregate static masses into one mass
|
||||
if (_staticMass.m == 0) _recalcStatic();
|
||||
|
||||
// Calculate the c.g and total mass
|
||||
// init with pre-calculated static mass
|
||||
_totalMass = _staticMass.m;
|
||||
_cg[0] = _staticMass.m * _staticMass.p[0];
|
||||
_cg[1] = _staticMass.m * _staticMass.p[1];
|
||||
_cg[2] = _staticMass.m * _staticMass.p[2];
|
||||
int i;
|
||||
for(i=0; i<_nMasses; i++) {
|
||||
// only masses we did not aggregate
|
||||
if (!_masses[i].isStatic) {
|
||||
float m = _masses[i].m;
|
||||
_totalMass += m;
|
||||
_cg[0] += m * _masses[i].p[0];
|
||||
_cg[1] += m * _masses[i].p[1];
|
||||
_cg[2] += m * _masses[i].p[2];
|
||||
}
|
||||
}
|
||||
Math::mul3(1/_totalMass, _cg, _cg);
|
||||
|
||||
// Now the inertia tensor:
|
||||
for(i=0; i<9; i++)
|
||||
_tI[i] = 0;
|
||||
_tI[i] = _tI_static[i];
|
||||
|
||||
for(i=0; i<_nMasses; i++) {
|
||||
float m = _masses[i].m;
|
||||
if (!_masses[i].isStatic) {
|
||||
float m = _masses[i].m;
|
||||
|
||||
float x = _masses[i].p[0] - _cg[0];
|
||||
float y = _masses[i].p[1] - _cg[1];
|
||||
float z = _masses[i].p[2] - _cg[2];
|
||||
float x = _masses[i].p[0] - _cg[0];
|
||||
float y = _masses[i].p[1] - _cg[1];
|
||||
float z = _masses[i].p[2] - _cg[2];
|
||||
float mx = m*x;
|
||||
float my = m*y;
|
||||
float mz = m*z;
|
||||
|
||||
float xy = m*x*y; float yz = m*y*z; float zx = m*z*x;
|
||||
float x2 = m*x*x; float y2 = m*y*y; float z2 = m*z*z;
|
||||
float xy = mx*y; float yz = my*z; float zx = mz*x;
|
||||
float x2 = mx*x; float y2 = my*y; float z2 = mz*z;
|
||||
|
||||
_tI[0] += y2+z2; _tI[1] -= xy; _tI[2] -= zx;
|
||||
_tI[3] -= xy; _tI[4] += x2+z2; _tI[5] -= yz;
|
||||
_tI[6] -= zx; _tI[7] -= yz; _tI[8] += x2+y2;
|
||||
_tI[0] += y2+z2; _tI[1] -= xy; _tI[2] -= zx;
|
||||
_tI[4] += x2+z2; _tI[5] -= yz;
|
||||
_tI[8] += x2+y2;
|
||||
}
|
||||
}
|
||||
// copy symmetric elements
|
||||
_tI[3] = _tI[1];
|
||||
_tI[6] = _tI[2];
|
||||
_tI[7] = _tI[5];
|
||||
|
||||
// And its inverse
|
||||
Math::invert33(_tI, _invI);
|
||||
//calculate inverse
|
||||
Math::invert33_sym(_tI, _invI);
|
||||
}
|
||||
|
||||
void RigidBody::reset()
|
||||
|
@ -126,17 +205,7 @@ void RigidBody::reset()
|
|||
_force[0] = _force[1] = _force[2] = 0;
|
||||
}
|
||||
|
||||
void RigidBody::addForce(float* force)
|
||||
{
|
||||
Math::add3(_force, force, _force);
|
||||
}
|
||||
|
||||
void RigidBody::addTorque(float* torque)
|
||||
{
|
||||
Math::add3(_torque, torque, _torque);
|
||||
}
|
||||
|
||||
void RigidBody::addForce(float* pos, float* force)
|
||||
void RigidBody::addForce(const float* pos, const float* force)
|
||||
{
|
||||
addForce(force);
|
||||
|
||||
|
@ -148,21 +217,6 @@ void RigidBody::addForce(float* pos, float* force)
|
|||
addTorque(t);
|
||||
}
|
||||
|
||||
void RigidBody::setBodySpin(float* rotation)
|
||||
{
|
||||
Math::set3(rotation, _spin);
|
||||
}
|
||||
|
||||
void RigidBody::getCG(float* cgOut)
|
||||
{
|
||||
Math::set3(_cg, cgOut);
|
||||
}
|
||||
|
||||
void RigidBody::getAccel(float* accelOut)
|
||||
{
|
||||
Math::mul3(1/_totalMass, _force, accelOut);
|
||||
}
|
||||
|
||||
void RigidBody::getAccel(float* pos, float* accelOut)
|
||||
{
|
||||
getAccel(accelOut);
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#ifndef _RIGIDBODY_HPP
|
||||
#define _RIGIDBODY_HPP
|
||||
#include <simgear/props/props.hxx>
|
||||
#include "Vector.hpp"
|
||||
#include "Math.hpp"
|
||||
|
||||
namespace yasim {
|
||||
|
||||
|
@ -20,27 +23,28 @@ namespace yasim {
|
|||
//
|
||||
class RigidBody
|
||||
{
|
||||
SGPropertyNode_ptr _bodyN;
|
||||
public:
|
||||
RigidBody();
|
||||
~RigidBody();
|
||||
|
||||
// Adds a point mass to the system. Returns a handle so the gyro
|
||||
// can be later modified via setMass().
|
||||
int addMass(float mass, float* pos);
|
||||
int addMass(float mass, float* pos, bool isStatic = false);
|
||||
|
||||
// Modifies a previously-added point mass (fuel tank running dry,
|
||||
// gear going up, swing wing swinging, pilot bailing out, etc...)
|
||||
void setMass(int handle, float mass);
|
||||
void setMass(int handle, float mass, float* pos);
|
||||
void setMass(int handle, float mass, const float* pos, bool isStatic = false);
|
||||
|
||||
int numMasses();
|
||||
float getMass(int handle);
|
||||
int numMasses() { return _nMasses; }
|
||||
float getMass(int handle) { return _masses[handle].m; }
|
||||
void getMassPosition(int handle, float* out);
|
||||
float getTotalMass();
|
||||
float getTotalMass() { return _totalMass; }
|
||||
|
||||
// The velocity, in local coordinates, of the specified point on a
|
||||
// body rotating about its c.g. with velocity rot.
|
||||
void pointVelocity(float* pos, float* rot, float* out);
|
||||
void pointVelocity(const float* pos, const float* rot, float* out);
|
||||
|
||||
// Sets the "gyroscope" for the body. This is the total
|
||||
// "intrinsic" angular momentum of the body; that is, rotations of
|
||||
|
@ -48,27 +52,26 @@ public:
|
|||
// frame. Because angular momentum is additive in this way, we
|
||||
// don't need to specify specific gyro objects; just add all their
|
||||
// momenta together and set it here.
|
||||
void setGyro(float* angularMomentum);
|
||||
void setGyro(const float* angularMomentum) { Math::set3(angularMomentum, _gyro); }
|
||||
|
||||
|
||||
// When masses are moved or changed, this object needs to
|
||||
// regenerate its internal tables. This step is expensive, so
|
||||
// it's exposed to the client who can amortize the call across
|
||||
// multiple changes.
|
||||
// multiple changes. see also _recalcStatic()
|
||||
void recalc();
|
||||
|
||||
// Resets the current force/torque parameters to zero.
|
||||
void reset();
|
||||
|
||||
// Applies a force at the center of gravity.
|
||||
void addForce(const float* force) { Math::add3(_force, force, _force); }
|
||||
|
||||
// Applies a force at the specified position.
|
||||
void addForce(float* pos, float* force);
|
||||
|
||||
// Applies a force at the center of gravity.
|
||||
void addForce(float* force);
|
||||
void addForce(const float* pos, const float* force);
|
||||
|
||||
// Adds a torque with the specified axis and magnitude
|
||||
void addTorque(float* torque);
|
||||
void addTorque(const float* torque) { Math::add3(_torque, torque, _torque); }
|
||||
|
||||
// Sets the rotation rate of the body (about its c.g.) within the
|
||||
// surrounding environment. This is needed to compute torque on
|
||||
|
@ -76,17 +79,15 @@ public:
|
|||
// rotation. NOTE: the rotation vector, like all other
|
||||
// coordinates used here, is specified IN THE LOCAL COORDINATE
|
||||
// SYSTEM.
|
||||
void setBodySpin(float* rotation);
|
||||
|
||||
|
||||
void setBodySpin(const float* rotation) { Math::set3(rotation, _spin); }
|
||||
|
||||
// Returns the center of gravity of the masses, in the body
|
||||
// coordinate system.
|
||||
void getCG(float* cgOut);
|
||||
// coordinate system. valid only after recalc()
|
||||
void getCG(float* cgOut) { Math::set3(_cg, cgOut); }
|
||||
|
||||
// Returns the acceleration of the body's c.g. relative to the
|
||||
// rest of the world, specified in local coordinates.
|
||||
void getAccel(float* accelOut);
|
||||
void getAccel(float* accelOut) { Math::mul3(1/_totalMass, _force, accelOut); }
|
||||
|
||||
// Returns the acceleration of a specific location in local
|
||||
// coordinates. If the body is rotating, this will be different
|
||||
|
@ -102,17 +103,24 @@ public:
|
|||
void getInertiaMatrix(float* inertiaOut);
|
||||
|
||||
private:
|
||||
struct Mass { float m; float p[3]; };
|
||||
/**
|
||||
Most of the mass points do not change after compilation of the aircraft so
|
||||
they can be replaced by one aggregated mass at the c.g. of the static masses.
|
||||
The isStatic flag is used to mark those masses.
|
||||
*/
|
||||
struct Mass { float m; float p[3]; bool isStatic; };
|
||||
void _recalcStatic(); /// aggregate static masses
|
||||
Mass _staticMass; /// aggregated static masses, calculated once
|
||||
Mass* _masses; /// mass elements
|
||||
int _nMasses; /// number of masses
|
||||
int _massesAlloced; /// counter for memory allocation
|
||||
|
||||
// Internal "rotational structure"
|
||||
Mass* _masses;
|
||||
int _nMasses;
|
||||
int _massesAlloced;
|
||||
float _totalMass;
|
||||
float _cg[3];
|
||||
float _gyro[3];
|
||||
|
||||
// Inertia tensor, and its inverse. Computed from the above.
|
||||
float _tI_static[9];
|
||||
float _tI[9];
|
||||
float _invI[9];
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include "Math.hpp"
|
||||
#include <Main/fg_props.hxx>
|
||||
#include "Surface.hpp"
|
||||
//#include "Surface.hpp"
|
||||
#include "Rotorpart.hpp"
|
||||
#include "Glue.hpp"
|
||||
#include "Ground.hpp"
|
||||
|
@ -962,7 +962,7 @@ float Rotor::findGroundEffectAltitude(Ground * ground_cb,State *s,
|
|||
);
|
||||
}
|
||||
|
||||
void Rotor::getDownWash(float *pos, float *v_heli, float *downwash)
|
||||
void Rotor::getDownWash(const float *pos, const float *v_heli, float *downwash)
|
||||
{
|
||||
float pos2rotor[3],tmp[3];
|
||||
Math::sub3(_base,pos,pos2rotor);
|
||||
|
@ -1632,7 +1632,7 @@ void Rotorgear::compile()
|
|||
}
|
||||
}
|
||||
|
||||
void Rotorgear::getDownWash(float *pos, float * v_heli, float *downwash)
|
||||
void Rotorgear::getDownWash(const float *pos, const float * v_heli, float *downwash)
|
||||
{
|
||||
float tmp[3];
|
||||
downwash[0]=downwash[1]=downwash[2]=0;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
namespace yasim {
|
||||
|
||||
class Surface;
|
||||
//class Surface;
|
||||
class Rotorpart;
|
||||
class Ground;
|
||||
const float rho_null=1.184f; //25DegC, 101325Pa
|
||||
|
@ -107,7 +107,7 @@ public:
|
|||
void updateDirectionsAndPositions(float *rot);
|
||||
void getTip(float* tip);
|
||||
void calcLiftFactor(float* v, float rho, State *s);
|
||||
void getDownWash(float *pos, float * v_heli, float *downwash);
|
||||
void getDownWash(const float* pos, const float* v_heli, float* downwash);
|
||||
int getNumberOfBlades(){return _number_of_blades;}
|
||||
void setDownwashFactor(float value);
|
||||
|
||||
|
@ -287,7 +287,7 @@ public:
|
|||
float getEnginePropFactor() {return _engine_prop_factor;}
|
||||
Vector* getRotors() { return &_rotors;}
|
||||
void initRotorIteration(float *lrot,float dt);
|
||||
void getDownWash(float *pos, float * v_heli, float *downwash);
|
||||
void getDownWash(const float* pos, const float* v_heli, float* downwash);
|
||||
int getValueforFGSet(int j,char *b,float *f);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
#include "Math.hpp"
|
||||
#include <Main/fg_props.hxx>
|
||||
#include "Surface.hpp"
|
||||
|
||||
namespace yasim {
|
||||
int Surface::s_idGenerator = 0;
|
||||
|
||||
Surface::Surface( Version * version ) :
|
||||
_version(version)
|
||||
{
|
||||
// create id for surface
|
||||
_id = s_idGenerator++;
|
||||
// Start in a "sane" mode, so unset stuff doesn't freak us out
|
||||
_c0 = 1;
|
||||
_cx = _cy = _cz = 1;
|
||||
|
@ -30,91 +34,40 @@ Surface::Surface( Version * version ) :
|
|||
_slatAlpha = 0;
|
||||
_spoilerLift = 1;
|
||||
_inducedDrag = 1;
|
||||
_stallAlpha = 0;
|
||||
_alpha = 0;
|
||||
_surfN = fgGetNode("/fdm/yasim/surfaces", true);
|
||||
if (_surfN != 0) {
|
||||
_surfN = _surfN->getChild("surface", _id, true);
|
||||
_fxN = _surfN->getNode("f-x", true);
|
||||
_fyN = _surfN->getNode("f-y", true);
|
||||
_fzN = _surfN->getNode("f-z", true);
|
||||
_fabsN = _surfN->getNode("f-abs", true);
|
||||
_alphaN = _surfN->getNode("alpha", true);
|
||||
_stallAlphaN = _surfN->getNode("stall-alpha", true);
|
||||
_flapN = _surfN->getNode("flap-pos", true);
|
||||
_slatN = _surfN->getNode("slat-pos", true);
|
||||
_spoilerN = _surfN->getNode("spoiler-pos", true);
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::setPosition(float* p)
|
||||
|
||||
void Surface::setPosition(const float* p)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<3; i++) _pos[i] = p[i];
|
||||
if (_surfN != 0) {
|
||||
_surfN->getNode("pos-x", true)->setFloatValue(p[0]);
|
||||
_surfN->getNode("pos-y", true)->setFloatValue(p[1]);
|
||||
_surfN->getNode("pos-z", true)->setFloatValue(p[2]);
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::getPosition(float* out)
|
||||
void Surface::setOrientation(const float* o)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<3; i++) out[i] = _pos[i];
|
||||
for(int i=0; i<9; i++) _orient[i] = o[i];
|
||||
}
|
||||
|
||||
void Surface::setChord(float chord)
|
||||
{
|
||||
_chord = chord;
|
||||
}
|
||||
|
||||
void Surface::setTotalDrag(float c0)
|
||||
{
|
||||
_c0 = c0;
|
||||
}
|
||||
|
||||
float Surface::getTotalDrag()
|
||||
{
|
||||
return _c0;
|
||||
}
|
||||
|
||||
void Surface::setXDrag(float cx)
|
||||
{
|
||||
_cx = cx;
|
||||
}
|
||||
|
||||
void Surface::setYDrag(float cy)
|
||||
{
|
||||
_cy = cy;
|
||||
}
|
||||
|
||||
void Surface::setZDrag(float cz)
|
||||
{
|
||||
_cz = cz;
|
||||
}
|
||||
|
||||
float Surface::getXDrag()
|
||||
{
|
||||
return _cx;
|
||||
}
|
||||
|
||||
void Surface::setBaseZDrag(float cz0)
|
||||
{
|
||||
_cz0 = cz0;
|
||||
}
|
||||
|
||||
void Surface::setStallPeak(int i, float peak)
|
||||
{
|
||||
_peaks[i] = peak;
|
||||
}
|
||||
|
||||
void Surface::setStall(int i, float alpha)
|
||||
{
|
||||
_stalls[i] = alpha;
|
||||
}
|
||||
|
||||
void Surface::setStallWidth(int i, float width)
|
||||
{
|
||||
_widths[i] = width;
|
||||
}
|
||||
|
||||
void Surface::setOrientation(float* o)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<9; i++)
|
||||
_orient[i] = o[i];
|
||||
}
|
||||
|
||||
void Surface::setIncidence(float angle)
|
||||
{
|
||||
_incidence = angle;
|
||||
}
|
||||
|
||||
void Surface::setTwist(float angle)
|
||||
{
|
||||
_twist = angle;
|
||||
}
|
||||
|
||||
void Surface::setSlatParams(float stallDelta, float dragPenalty)
|
||||
{
|
||||
|
@ -134,42 +87,39 @@ void Surface::setSpoilerParams(float liftPenalty, float dragPenalty)
|
|||
_spoilerDrag = dragPenalty;
|
||||
}
|
||||
|
||||
void Surface::setFlap(float pos)
|
||||
void Surface::setFlapPos(float pos)
|
||||
{
|
||||
_flapPos = pos;
|
||||
if (_flapPos != pos) {
|
||||
_flapPos = pos;
|
||||
if (_surfN != 0) _flapN->setFloatValue(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::setFlapEffectiveness(float effectiveness)
|
||||
{
|
||||
_flapEffectiveness = effectiveness;
|
||||
}
|
||||
|
||||
double Surface::getFlapEffectiveness()
|
||||
{
|
||||
return _flapEffectiveness;
|
||||
}
|
||||
|
||||
|
||||
void Surface::setSlat(float pos)
|
||||
void Surface::setSlatPos(float pos)
|
||||
{
|
||||
if (_slatPos != pos) {
|
||||
_slatPos = pos;
|
||||
if (_surfN != 0) _slatN->setFloatValue(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::setSpoiler(float pos)
|
||||
void Surface::setSpoilerPos(float pos)
|
||||
{
|
||||
if (_spoilerPos != pos) {
|
||||
_spoilerPos = pos;
|
||||
if (_surfN != 0) _spoilerN->setFloatValue(pos);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the aerodynamic force given a wind vector v (in the
|
||||
// aircraft's "local" coordinates) and an air density rho. Returns a
|
||||
// torque about the Y axis, too.
|
||||
void Surface::calcForce(float* v, float rho, float* out, float* torque)
|
||||
void Surface::calcForce(const float* v, const float rho, float* out, float* torque)
|
||||
{
|
||||
// Split v into magnitude and direction:
|
||||
float vel = Math::mag3(v);
|
||||
|
||||
// Handle the blowup condition. Zero velocity means zero force by
|
||||
// definition.
|
||||
// Zero velocity means zero force by definition (also prevents div0).
|
||||
if(vel == 0) {
|
||||
int i;
|
||||
for(i=0; i<3; i++) out[i] = torque[i] = 0;
|
||||
|
@ -183,9 +133,8 @@ void Surface::calcForce(float* v, float rho, float* out, float* torque)
|
|||
return;
|
||||
}
|
||||
|
||||
// Normalize wind and convert to the surface's coordinates
|
||||
Math::mul3(1/vel, v, out);
|
||||
|
||||
// Convert to the surface's coordinates
|
||||
Math::vmul33(_orient, out, out);
|
||||
|
||||
// "Rotate" by the incidence angle. Assume small angles, so we
|
||||
|
@ -247,6 +196,15 @@ void Surface::calcForce(float* v, float rho, float* out, float* torque)
|
|||
float scale = 0.5f*rho*vel*vel*_c0;
|
||||
Math::mul3(scale, out, out);
|
||||
Math::mul3(scale, torque, torque);
|
||||
// if we have a property tree, export info
|
||||
if (_surfN != 0) {
|
||||
_fabsN->setFloatValue(Math::mag3(out));
|
||||
_fxN->setFloatValue(out[0]);
|
||||
_fyN->setFloatValue(out[1]);
|
||||
_fzN->setFloatValue(out[2]);
|
||||
_alphaN->setFloatValue(_alpha);
|
||||
_stallAlphaN->setFloatValue(_stallAlpha);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -257,9 +215,9 @@ void Surface::test()
|
|||
float rho = Atmosphere::getStdDensity(0);
|
||||
float spd = 30;
|
||||
|
||||
setFlap(0);
|
||||
setSlat(0);
|
||||
setSpoiler(0);
|
||||
setFlapPos(0);
|
||||
setSlatPos(0);
|
||||
setSpoilerPos(0);
|
||||
|
||||
for(float angle = -90; angle<90; angle += 0.01) {
|
||||
float rad = angle * DEG2RAD;
|
||||
|
@ -281,39 +239,40 @@ float Surface::stallFunc(float* v)
|
|||
// Sanity check to treat FPU psychopathology
|
||||
if(v[0] == 0) return 1;
|
||||
|
||||
float alpha = Math::abs(v[2]/v[0]);
|
||||
_alpha = Math::abs(v[2]/v[0]);
|
||||
|
||||
// Wacky use of indexing, see setStall*() methods.
|
||||
int fwdBak = v[0] > 0; // set if this is "backward motion"
|
||||
int posNeg = v[2] < 0; // set if the airflow is toward -z
|
||||
int i = (fwdBak<<1) | posNeg;
|
||||
|
||||
float stallAlpha = _stalls[i];
|
||||
if(stallAlpha == 0)
|
||||
_stallAlpha = _stalls[i];
|
||||
if(_stallAlpha == 0)
|
||||
return 1;
|
||||
|
||||
// consider slat position, moves the stall aoa some degrees
|
||||
if(i == 0) {
|
||||
if( _version->isVersionOrNewer( Version::YASIM_VERSION_32 )) {
|
||||
stallAlpha += _slatPos * _slatAlpha;
|
||||
_stallAlpha += _slatPos * _slatAlpha;
|
||||
} else {
|
||||
stallAlpha += _slatAlpha;
|
||||
_stallAlpha += _slatAlpha;
|
||||
}
|
||||
}
|
||||
|
||||
// Beyond the stall
|
||||
if(alpha > stallAlpha+_widths[i])
|
||||
if(_alpha > _stallAlpha+_widths[i])
|
||||
return 1;
|
||||
|
||||
// (note mask: we want to use the "positive" stall angle here)
|
||||
float scale = 0.5f*_peaks[fwdBak]/_stalls[i&2];
|
||||
|
||||
// Before the stall
|
||||
if(alpha <= stallAlpha)
|
||||
if(_alpha <= _stallAlpha)
|
||||
return scale;
|
||||
|
||||
// Inside the stall. Compute a cubic interpolation between the
|
||||
// pre-stall "scale" value and the post-stall unity.
|
||||
float frac = (alpha - stallAlpha) / _widths[i];
|
||||
float frac = (_alpha - _stallAlpha) / _widths[i];
|
||||
frac = frac*frac*(3-2*frac);
|
||||
|
||||
return scale*(1-frac) + frac;
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#ifndef _SURFACE_HPP
|
||||
#define _SURFACE_HPP
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include "Version.hpp"
|
||||
#include "Math.hpp"
|
||||
|
||||
namespace yasim {
|
||||
|
||||
|
@ -10,15 +12,21 @@ namespace yasim {
|
|||
// front, and flaps act (in both lift and drag) toward the back.
|
||||
class Surface
|
||||
{
|
||||
static int s_idGenerator;
|
||||
int _id; //index for property tree
|
||||
|
||||
public:
|
||||
Surface( Version * version );
|
||||
|
||||
int getID() { return _id; };
|
||||
static void resetIDgen() { s_idGenerator = 0; };
|
||||
|
||||
// Position of this surface in local coords
|
||||
void setPosition(float* p);
|
||||
void getPosition(float* out);
|
||||
void setPosition(const float* p);
|
||||
void getPosition(float* out) { Math::set3(_pos, out); }
|
||||
|
||||
// Distance scale along the X axis
|
||||
void setChord(float chord);
|
||||
void setChord(float chord) { _chord = chord; }
|
||||
|
||||
// Slats act to move the stall peak by the specified angle, and
|
||||
// increase drag by the multiplier specified.
|
||||
|
@ -32,49 +40,54 @@ public:
|
|||
|
||||
// Positions for the controls, in the range [0:1]. [-1:1] for
|
||||
// flaps, with positive meaning "force goes towards positive Z"
|
||||
void setFlap(float pos);
|
||||
void setSlat(float pos);
|
||||
void setSpoiler(float pos);
|
||||
void setFlapPos(float pos);
|
||||
void setSlatPos(float pos);
|
||||
void setSpoilerPos(float pos);
|
||||
|
||||
// Modifier for flap lift coefficient, useful for simulating flap blowing etc.
|
||||
void setFlapEffectiveness(float effectiveness);
|
||||
double getFlapEffectiveness();
|
||||
void setFlapEffectiveness(float effectiveness) { _flapEffectiveness = effectiveness; }
|
||||
double getFlapEffectiveness() { return _flapEffectiveness; }
|
||||
|
||||
// local -> Surface coords
|
||||
void setOrientation(float* o);
|
||||
void setOrientation(const float* o);
|
||||
|
||||
// For variable-incidence control surfaces. The angle is a
|
||||
// negative rotation about the surface's Y axis, in radians, so
|
||||
// positive is "up" (i.e. "positive AoA")
|
||||
void setIncidence(float angle);
|
||||
void setIncidence(float angle) { _incidence = angle; }
|
||||
|
||||
// The offset from base incidence for this surface.
|
||||
void setTwist(float angle);
|
||||
void setTwist(float angle) { _twist = angle; }
|
||||
|
||||
void setTotalDrag(float c0);
|
||||
float getTotalDrag();
|
||||
void setTotalDrag(float c0) { _c0 = c0; }
|
||||
float getTotalDrag() { return _c0; }
|
||||
|
||||
void setXDrag(float cx);
|
||||
void setYDrag(float cy);
|
||||
void setZDrag(float cz);
|
||||
float getXDrag();
|
||||
void setXDrag(float cx) { _cx = cx; }
|
||||
void setYDrag(float cy) { _cy = cy; }
|
||||
void setZDrag(float cz) { _cz = cz; }
|
||||
float getXDrag() { return _cx; }
|
||||
|
||||
// zero-alpha Z drag ("camber") specified as a fraction of cz
|
||||
void setBaseZDrag(float cz0);
|
||||
void setBaseZDrag(float cz0) { _cz0 = cz0; }
|
||||
|
||||
// i: 0 == forward, 1 == backwards
|
||||
void setStallPeak(int i, float peak);
|
||||
void setStallPeak(int i, float peak) { _peaks[i] = peak; }
|
||||
|
||||
// i: 0 == fwd/+z, 1 == fwd/-z, 2 == rev/+z, 3 == rev/-z
|
||||
void setStall(int i, float alpha);
|
||||
void setStallWidth(int i, float width);
|
||||
void setStall(int i, float alpha) { _stalls[i] = alpha; }
|
||||
void setStallWidth(int i, float width) { _widths[i] = width; }
|
||||
|
||||
// Induced drag multiplier
|
||||
void setInducedDrag(float mul) { _inducedDrag = mul; }
|
||||
|
||||
void calcForce(float* v, float rho, float* forceOut, float* torqueOut);
|
||||
void calcForce(const float* v, const float rho, float* out, float* torque);
|
||||
|
||||
float getAlpha() { return _alpha; };
|
||||
float getStallAlpha() { return _stallAlpha; };
|
||||
|
||||
private:
|
||||
SGPropertyNode_ptr _surfN;
|
||||
|
||||
float stallFunc(float* v);
|
||||
float flapLift(float alpha);
|
||||
float controlDrag(float lift, float drag);
|
||||
|
@ -106,7 +119,20 @@ private:
|
|||
float _twist;
|
||||
float _inducedDrag;
|
||||
|
||||
// used during calculations
|
||||
float _stallAlpha;
|
||||
float _alpha;
|
||||
|
||||
Version * _version;
|
||||
SGPropertyNode* _fxN;
|
||||
SGPropertyNode* _fyN;
|
||||
SGPropertyNode* _fzN;
|
||||
SGPropertyNode* _stallAlphaN;
|
||||
SGPropertyNode* _alphaN;
|
||||
SGPropertyNode* _flapN;
|
||||
SGPropertyNode* _slatN;
|
||||
SGPropertyNode* _spoilerN;
|
||||
SGPropertyNode* _fabsN;
|
||||
};
|
||||
|
||||
}; // namespace yasim
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "Version.hpp"
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
namespace yasim {
|
||||
void Version::setVersion( const char * version )
|
||||
|
@ -15,11 +16,15 @@ void Version::setVersion( const char * version )
|
|||
_version = YASIM_VERSION_ORIGINAL;
|
||||
} else if( v == "YASIM_VERSION_32" ) {
|
||||
_version = YASIM_VERSION_32;
|
||||
} else if( v == "2017.2" ) {
|
||||
_version = YASIM_VERSION_2017_2;
|
||||
} else if( v == "YASIM_VERSION_CURRENT" ) {
|
||||
_version = YASIM_VERSION_CURRENT;
|
||||
} else {
|
||||
SG_LOG(SG_FLIGHT,SG_ALERT,"unknown yasim version '" << version << "' ignored, using YASIM_VERSION_ORIGINAL");
|
||||
return;
|
||||
}
|
||||
std::cout << "This aircraft uses yasim version '" << v << "'\n";
|
||||
}
|
||||
|
||||
} // namespace yasim
|
||||
|
|
|
@ -11,10 +11,12 @@ public:
|
|||
typedef enum {
|
||||
YASIM_VERSION_ORIGINAL = 0,
|
||||
YASIM_VERSION_32,
|
||||
YASIM_VERSION_CURRENT = YASIM_VERSION_32
|
||||
YASIM_VERSION_2017_2,
|
||||
YASIM_VERSION_CURRENT = YASIM_VERSION_2017_2
|
||||
} YASIM_VERSION;
|
||||
|
||||
void setVersion( const char * version );
|
||||
int getVersion() { return _version; }
|
||||
bool isVersion( YASIM_VERSION version );
|
||||
bool isVersionOrNewer( YASIM_VERSION version );
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "Math.hpp"
|
||||
#include "Surface.hpp"
|
||||
#include "Wing.hpp"
|
||||
|
||||
namespace yasim {
|
||||
static const float RAD2DEG = 57.2957795131;
|
||||
|
||||
Wing::Wing( Version * version ) :
|
||||
_version(version)
|
||||
|
@ -39,6 +39,9 @@ Wing::Wing( Version * version ) :
|
|||
_slatEnd = 0;
|
||||
_slatAoA = 0;
|
||||
_slatDrag = 0;
|
||||
_meanChord = 0;
|
||||
_wingspan = 0;
|
||||
_aspectRatio = 1;
|
||||
}
|
||||
|
||||
Wing::~Wing()
|
||||
|
@ -51,82 +54,6 @@ Wing::~Wing()
|
|||
}
|
||||
}
|
||||
|
||||
int Wing::numSurfaces()
|
||||
{
|
||||
return _surfs.size();
|
||||
}
|
||||
|
||||
Surface* Wing::getSurface(int n)
|
||||
{
|
||||
return ((SurfRec*)_surfs.get(n))->surface;
|
||||
}
|
||||
|
||||
float Wing::getSurfaceWeight(int n)
|
||||
{
|
||||
return ((SurfRec*)_surfs.get(n))->weight;
|
||||
}
|
||||
|
||||
void Wing::setMirror(bool mirror)
|
||||
{
|
||||
_mirror = mirror;
|
||||
}
|
||||
|
||||
void Wing::setBase(float* base)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<3; i++) _base[i] = base[i];
|
||||
}
|
||||
|
||||
void Wing::setLength(float length)
|
||||
{
|
||||
_length = length;
|
||||
}
|
||||
|
||||
void Wing::setChord(float chord)
|
||||
{
|
||||
_chord = chord;
|
||||
}
|
||||
|
||||
void Wing::setTaper(float taper)
|
||||
{
|
||||
_taper = taper;
|
||||
}
|
||||
|
||||
void Wing::setSweep(float sweep)
|
||||
{
|
||||
_sweep = sweep;
|
||||
}
|
||||
|
||||
void Wing::setDihedral(float dihedral)
|
||||
{
|
||||
_dihedral = dihedral;
|
||||
}
|
||||
|
||||
void Wing::setStall(float aoa)
|
||||
{
|
||||
_stall = aoa;
|
||||
}
|
||||
|
||||
void Wing::setStallWidth(float angle)
|
||||
{
|
||||
_stallWidth = angle;
|
||||
}
|
||||
|
||||
void Wing::setStallPeak(float fraction)
|
||||
{
|
||||
_stallPeak = fraction;
|
||||
}
|
||||
|
||||
void Wing::setTwist(float angle)
|
||||
{
|
||||
_twist = angle;
|
||||
}
|
||||
|
||||
void Wing::setCamber(float camber)
|
||||
{
|
||||
_camber = camber;
|
||||
}
|
||||
|
||||
void Wing::setIncidence(float incidence)
|
||||
{
|
||||
_incidence = incidence;
|
||||
|
@ -135,7 +62,7 @@ void Wing::setIncidence(float incidence)
|
|||
((SurfRec*)_surfs.get(i))->surface->setIncidence(incidence);
|
||||
}
|
||||
|
||||
void Wing::setFlap0(float start, float end, float lift, float drag)
|
||||
void Wing::setFlap0Params(float start, float end, float lift, float drag)
|
||||
{
|
||||
_flap0Start = start;
|
||||
_flap0End = end;
|
||||
|
@ -143,7 +70,7 @@ void Wing::setFlap0(float start, float end, float lift, float drag)
|
|||
_flap0Drag = drag;
|
||||
}
|
||||
|
||||
void Wing::setFlap1(float start, float end, float lift, float drag)
|
||||
void Wing::setFlap1Params(float start, float end, float lift, float drag)
|
||||
{
|
||||
_flap1Start = start;
|
||||
_flap1End = end;
|
||||
|
@ -151,7 +78,7 @@ void Wing::setFlap1(float start, float end, float lift, float drag)
|
|||
_flap1Drag = drag;
|
||||
}
|
||||
|
||||
void Wing::setSlat(float start, float end, float aoa, float drag)
|
||||
void Wing::setSlatParams(float start, float end, float aoa, float drag)
|
||||
{
|
||||
_slatStart = start;
|
||||
_slatEnd = end;
|
||||
|
@ -159,7 +86,7 @@ void Wing::setSlat(float start, float end, float aoa, float drag)
|
|||
_slatDrag = drag;
|
||||
}
|
||||
|
||||
void Wing::setSpoiler(float start, float end, float lift, float drag)
|
||||
void Wing::setSpoilerParams(float start, float end, float lift, float drag)
|
||||
{
|
||||
_spoilerStart = start;
|
||||
_spoilerEnd = end;
|
||||
|
@ -167,14 +94,14 @@ void Wing::setSpoiler(float start, float end, float lift, float drag)
|
|||
_spoilerDrag = drag;
|
||||
}
|
||||
|
||||
void Wing::setFlap0(float lval, float rval)
|
||||
void Wing::setFlap0Pos(float lval, float rval)
|
||||
{
|
||||
lval = Math::clamp(lval, -1, 1);
|
||||
rval = Math::clamp(rval, -1, 1);
|
||||
int i;
|
||||
for(i=0; i<_flap0Surfs.size(); i++) {
|
||||
((Surface*)_flap0Surfs.get(i))->setFlap(lval);
|
||||
if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlap(rval);
|
||||
((Surface*)_flap0Surfs.get(i))->setFlapPos(lval);
|
||||
if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlapPos(rval);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,18 +111,17 @@ void Wing::setFlap0Effectiveness(float lval)
|
|||
int i;
|
||||
for(i=0; i<_flap0Surfs.size(); i++) {
|
||||
((Surface*)_flap0Surfs.get(i))->setFlapEffectiveness(lval);
|
||||
// if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlapEffectiveness(rval);
|
||||
}
|
||||
}
|
||||
|
||||
void Wing::setFlap1(float lval, float rval)
|
||||
void Wing::setFlap1Pos(float lval, float rval)
|
||||
{
|
||||
lval = Math::clamp(lval, -1, 1);
|
||||
rval = Math::clamp(rval, -1, 1);
|
||||
int i;
|
||||
for(i=0; i<_flap1Surfs.size(); i++) {
|
||||
((Surface*)_flap1Surfs.get(i))->setFlap(lval);
|
||||
if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlap(rval);
|
||||
((Surface*)_flap1Surfs.get(i))->setFlapPos(lval);
|
||||
if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlapPos(rval);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,51 +131,26 @@ void Wing::setFlap1Effectiveness(float lval)
|
|||
int i;
|
||||
for(i=0; i<_flap1Surfs.size(); i++) {
|
||||
((Surface*)_flap1Surfs.get(i))->setFlapEffectiveness(lval);
|
||||
// if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlap(rval);
|
||||
}
|
||||
}
|
||||
|
||||
void Wing::setSpoiler(float lval, float rval)
|
||||
void Wing::setSpoilerPos(float lval, float rval)
|
||||
{
|
||||
lval = Math::clamp(lval, 0, 1);
|
||||
rval = Math::clamp(rval, 0, 1);
|
||||
int i;
|
||||
for(i=0; i<_spoilerSurfs.size(); i++) {
|
||||
((Surface*)_spoilerSurfs.get(i))->setSpoiler(lval);
|
||||
if(_mirror) ((Surface*)_spoilerSurfs.get(++i))->setSpoiler(rval);
|
||||
((Surface*)_spoilerSurfs.get(i))->setSpoilerPos(lval);
|
||||
if(_mirror) ((Surface*)_spoilerSurfs.get(++i))->setSpoilerPos(rval);
|
||||
}
|
||||
}
|
||||
|
||||
void Wing::setSlat(float val)
|
||||
void Wing::setSlatPos(float val)
|
||||
{
|
||||
val = Math::clamp(val, 0, 1);
|
||||
int i;
|
||||
for(i=0; i<_slatSurfs.size(); i++)
|
||||
((Surface*)_slatSurfs.get(i))->setSlat(val);
|
||||
}
|
||||
|
||||
float Wing::getGroundEffect(float* posOut)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<3; i++) posOut[i] = _base[i];
|
||||
float span = _length * Math::cos(_sweep) * Math::cos(_dihedral);
|
||||
span = 2*(span + Math::abs(_base[2]));
|
||||
return span;
|
||||
}
|
||||
|
||||
void Wing::getTip(float* tip)
|
||||
{
|
||||
tip[0] = -Math::tan(_sweep);
|
||||
tip[1] = Math::cos(_dihedral);
|
||||
tip[2] = Math::sin(_dihedral);
|
||||
Math::unit3(tip, tip);
|
||||
Math::mul3(_length, tip, tip);
|
||||
Math::add3(_base, tip, tip);
|
||||
}
|
||||
|
||||
bool Wing::isMirrored()
|
||||
{
|
||||
return _mirror;
|
||||
((Surface*)_slatSurfs.get(i))->setSlatPos(val);
|
||||
}
|
||||
|
||||
void Wing::compile()
|
||||
|
@ -272,17 +173,17 @@ void Wing::compile()
|
|||
// Sort in increasing order
|
||||
int i;
|
||||
for(i=0; i<10; i++) {
|
||||
int minIdx = i;
|
||||
float minVal = bounds[i];
|
||||
int j;
|
||||
for(j=i+1; j<10; j++) {
|
||||
if(bounds[j] < minVal) {
|
||||
minIdx = j;
|
||||
minVal = bounds[j];
|
||||
}
|
||||
}
|
||||
float tmp = bounds[i];
|
||||
bounds[i] = minVal; bounds[minIdx] = tmp;
|
||||
int minIdx = i;
|
||||
float minVal = bounds[i];
|
||||
int j;
|
||||
for(j=i+1; j<10; j++) {
|
||||
if(bounds[j] < minVal) {
|
||||
minIdx = j;
|
||||
minVal = bounds[j];
|
||||
}
|
||||
}
|
||||
float tmp = bounds[i];
|
||||
bounds[i] = minVal; bounds[minIdx] = tmp;
|
||||
}
|
||||
|
||||
// Uniqify
|
||||
|
@ -294,9 +195,8 @@ void Wing::compile()
|
|||
last = bounds[i];
|
||||
}
|
||||
|
||||
// Calculate a "nominal" segment length equal to an average chord,
|
||||
// normalized to lie within 0-1 over the length of the wing.
|
||||
float segLen = _chord * (0.5f*(_taper+1)) / _length;
|
||||
// prepare wing coordinate system, ignoring incidence and twist for now
|
||||
// (tail incidence is varied by the solver)
|
||||
|
||||
// Generating a unit vector pointing out the left wing.
|
||||
float left[3];
|
||||
|
@ -306,11 +206,12 @@ void Wing::compile()
|
|||
Math::unit3(left, left);
|
||||
|
||||
// Calculate coordinates for the root and tip of the wing
|
||||
float root[3], tip[3];
|
||||
Math::set3(_base, root);
|
||||
Math::set3(left, tip);
|
||||
Math::mul3(_length, tip, tip);
|
||||
Math::add3(root, tip, tip);
|
||||
Math::mul3(_length, left, _tip);
|
||||
Math::add3(_base, _tip, _tip);
|
||||
_meanChord = _chord*(_taper+1)*0.5f;
|
||||
// wingspan in y-direction (not for vstab)
|
||||
_wingspan = Math::abs(2*_tip[1]);
|
||||
_aspectRatio = _wingspan / _meanChord;
|
||||
|
||||
// The wing's Y axis will be the "left" vector. The Z axis will
|
||||
// be perpendicular to this and the local (!) X axis, because we
|
||||
|
@ -326,19 +227,23 @@ void Wing::compile()
|
|||
Math::cross3(y, z, x);
|
||||
|
||||
if(_mirror) {
|
||||
// Derive the right side orientation matrix from this one.
|
||||
int i;
|
||||
for(i=0; i<9; i++) rightOrient[i] = orient[i];
|
||||
// Derive the right side orientation matrix from this one.
|
||||
int i;
|
||||
for(i=0; i<9; i++) rightOrient[i] = orient[i];
|
||||
|
||||
// Negate all Y coordinates, this gets us a valid basis, but
|
||||
// it's left handed! So...
|
||||
for(i=1; i<9; i+=3) rightOrient[i] = -rightOrient[i];
|
||||
// Negate all Y coordinates, this gets us a valid basis, but
|
||||
// it's left handed! So...
|
||||
for(i=1; i<9; i+=3) rightOrient[i] = -rightOrient[i];
|
||||
|
||||
// Change the direction of the Y axis to get back to a
|
||||
// right-handed system.
|
||||
for(i=3; i<6; i++) rightOrient[i] = -rightOrient[i];
|
||||
// Change the direction of the Y axis to get back to a
|
||||
// right-handed system.
|
||||
for(i=3; i<6; i++) rightOrient[i] = -rightOrient[i];
|
||||
}
|
||||
|
||||
// Calculate a "nominal" segment length equal to an average chord,
|
||||
// normalized to lie within 0-1 over the length of the wing.
|
||||
float segLen = _meanChord / _length;
|
||||
|
||||
// Now go through each boundary and make segments
|
||||
for(i=0; i<(nbounds-1); i++) {
|
||||
float start = bounds[i];
|
||||
|
@ -363,7 +268,7 @@ void Wing::compile()
|
|||
for(j=0; j<nSegs; j++) {
|
||||
float frac = start + (j+0.5f) * (end-start)/nSegs;
|
||||
float pos[3];
|
||||
interp(root, tip, frac, pos);
|
||||
interp(_base, _tip, frac, pos);
|
||||
|
||||
float chord = _chord * (1 - (1-_taper)*frac);
|
||||
|
||||
|
@ -378,7 +283,7 @@ void Wing::compile()
|
|||
_surfs.add(sr);
|
||||
|
||||
if(_mirror) {
|
||||
pos[1] = -pos[1];
|
||||
pos[1] = -pos[1];
|
||||
s = newSurface(pos, rightOrient, chord,
|
||||
flap0, flap1, slat, spoiler);
|
||||
sr = new SurfRec();
|
||||
|
@ -390,22 +295,16 @@ void Wing::compile()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Last of all, re-set the incidence in case setIncidence() was
|
||||
// called before we were compiled.
|
||||
setIncidence(_incidence);
|
||||
}
|
||||
|
||||
float Wing::getDragScale()
|
||||
{
|
||||
return _dragScale;
|
||||
}
|
||||
|
||||
void Wing::setDragScale(float scale)
|
||||
{
|
||||
_dragScale = scale;
|
||||
int i;
|
||||
for(i=0; i<_surfs.size(); i++) {
|
||||
for(int i=0; i<_surfs.size(); i++) {
|
||||
SurfRec* s = (SurfRec*)_surfs.get(i);
|
||||
s->surface->setTotalDrag(scale * s->weight);
|
||||
}
|
||||
|
@ -414,16 +313,10 @@ void Wing::setDragScale(float scale)
|
|||
void Wing::setLiftRatio(float ratio)
|
||||
{
|
||||
_liftRatio = ratio;
|
||||
int i;
|
||||
for(i=0; i<_surfs.size(); i++)
|
||||
for(int i=0; i<_surfs.size(); i++)
|
||||
((SurfRec*)_surfs.get(i))->surface->setZDrag(ratio);
|
||||
}
|
||||
|
||||
float Wing::getLiftRatio()
|
||||
{
|
||||
return _liftRatio;
|
||||
}
|
||||
|
||||
Surface* Wing::newSurface(float* pos, float* orient, float chord,
|
||||
bool flap0, bool flap1, bool slat, bool spoiler)
|
||||
{
|
||||
|
@ -442,14 +335,20 @@ Surface* Wing::newSurface(float* pos, float* orient, float chord,
|
|||
s->setStallWidth(0, _stallWidth);
|
||||
s->setStallPeak(0, _stallPeak);
|
||||
|
||||
// The negative AoA stall is the same if we're using an uncambered
|
||||
// airfoil, otherwise a "little badder".
|
||||
// The negative AoA stall is the same if we're using an symmetric
|
||||
// airfoil, otherwise a "little worse".
|
||||
if(_camber > 0) {
|
||||
s->setStall(1, stallAoA * 0.8f);
|
||||
s->setStallWidth(1, _stallWidth * 0.5f);
|
||||
} else {
|
||||
s->setStall(1, stallAoA);
|
||||
s->setStall(1, stallAoA);
|
||||
if( _version->isVersionOrNewer( Version::YASIM_VERSION_2017_2 )) {
|
||||
// what was presumably meant
|
||||
s->setStallWidth(1, _stallWidth);
|
||||
} else {
|
||||
// old code; presumably a copy&paste error
|
||||
s->setStall(1, _stallWidth);
|
||||
}
|
||||
}
|
||||
|
||||
// The "reverse" stalls are unmeasurable junk. Just use 13deg and
|
||||
|
@ -476,7 +375,7 @@ Surface* Wing::newSurface(float* pos, float* orient, float chord,
|
|||
return s;
|
||||
}
|
||||
|
||||
void Wing::interp(float* v1, float* v2, float frac, float* out)
|
||||
void Wing::interp(const float* v1, const float* v2, const float frac, float* out)
|
||||
{
|
||||
out[0] = v1[0] + frac*(v2[0]-v1[0]);
|
||||
out[1] = v1[1] + frac*(v2[1]-v1[1]);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Vector.hpp"
|
||||
#include "Version.hpp"
|
||||
#include "Math.hpp"
|
||||
|
||||
namespace yasim {
|
||||
|
||||
|
@ -15,64 +16,81 @@ public:
|
|||
~Wing();
|
||||
|
||||
// Do we mirror ourselves about the XZ plane?
|
||||
void setMirror(bool mirror);
|
||||
void setMirror(bool mirror) { _mirror = mirror; }
|
||||
bool isMirrored() { return _mirror; };
|
||||
|
||||
// Wing geometry:
|
||||
void setBase(float* base); // in local coordinates
|
||||
void setLength(float length); // dist. ALONG wing (not span!)
|
||||
void setChord(float chord); // at base, measured along X axis
|
||||
void setTaper(float taper); // fraction, 0-1
|
||||
void setSweep(float sweep); // radians
|
||||
void setDihedral(float dihedral); // radians, positive is "up"
|
||||
// Wing geometry in local coordinates:
|
||||
|
||||
// base point of wing
|
||||
void setBase(const float* base) { Math::set3(base, _base); }
|
||||
void getBase(float* base) { Math::set3(_base, base); };
|
||||
// dist. ALONG wing (not span!)
|
||||
void setLength(float length) { _length = length; }
|
||||
float getLength() { return _length; };
|
||||
// at base, measured along X axis
|
||||
void setChord(float chord) { _chord = chord; }
|
||||
float getChord() { return _chord; };
|
||||
// fraction of chord at wing tip, 0..1
|
||||
void setTaper(float taper) { _taper = taper; }
|
||||
float getTaper() { return _taper; };
|
||||
// radians
|
||||
void setSweep(float sweep) { _sweep = sweep; }
|
||||
float getSweep() { return _sweep; };
|
||||
// radians, positive is "up"
|
||||
void setDihedral(float dihedral) { _dihedral = dihedral; }
|
||||
float getDihedral() { return _dihedral; };
|
||||
|
||||
void setStall(float aoa);
|
||||
void setStallWidth(float angle);
|
||||
void setStallPeak(float fraction);
|
||||
void setTwist(float angle);
|
||||
void setCamber(float camber);
|
||||
void setIncidence(float incidence);
|
||||
void setTwist(float angle) { _twist = angle; }
|
||||
|
||||
|
||||
// parameters for stall curve
|
||||
void setStall(float aoa) { _stall = aoa; }
|
||||
void setStallWidth(float angle) { _stallWidth = angle; }
|
||||
void setStallPeak(float fraction) { _stallPeak = fraction; }
|
||||
void setCamber(float camber) { _camber = camber; }
|
||||
void setInducedDrag(float drag) { _inducedDrag = drag; }
|
||||
|
||||
void setFlap0(float start, float end, float lift, float drag);
|
||||
void setFlap1(float start, float end, float lift, float drag);
|
||||
void setSpoiler(float start, float end, float lift, float drag);
|
||||
void setSlat(float start, float end, float aoa, float drag);
|
||||
|
||||
void setFlap0Params(float start, float end, float lift, float drag);
|
||||
void setFlap1Params(float start, float end, float lift, float drag);
|
||||
void setSpoilerParams(float start, float end, float lift, float drag);
|
||||
void setSlatParams(float start, float end, float aoa, float drag);
|
||||
|
||||
// Set the control axes for the sub-surfaces
|
||||
void setFlap0(float lval, float rval);
|
||||
void setFlap1(float lval, float rval);
|
||||
void setSpoiler(float lval, float rval);
|
||||
void setSlat(float val);
|
||||
void setFlap0Pos(float lval, float rval);
|
||||
void setFlap1Pos(float lval, float rval);
|
||||
void setSpoilerPos(float lval, float rval);
|
||||
void setSlatPos(float val);
|
||||
void setFlap0Effectiveness(float lval);
|
||||
void setFlap1Effectiveness(float lval);
|
||||
|
||||
// Compile the thing into a bunch of Surface objects
|
||||
void compile();
|
||||
void getTip(float* tip) { Math::set3(_tip, tip);};
|
||||
|
||||
void getTip(float* tip);
|
||||
// valid only after Wing::compile() was called
|
||||
float getSpan() { return _wingspan; };
|
||||
float getArea() { return _wingspan*_meanChord; };
|
||||
float getAspectRatio() { return _aspectRatio; };
|
||||
float getSMC() { return _meanChord; };
|
||||
|
||||
bool isMirrored();
|
||||
|
||||
// Ground effect information
|
||||
float getGroundEffect(float* posOut);
|
||||
|
||||
// Query the list of Surface objects
|
||||
int numSurfaces();
|
||||
Surface* getSurface(int n);
|
||||
float getSurfaceWeight(int n);
|
||||
int numSurfaces() { return _surfs.size(); }
|
||||
Surface* getSurface(int n) { return ((SurfRec*)_surfs.get(n))->surface; }
|
||||
float getSurfaceWeight(int n) { return ((SurfRec*)_surfs.get(n))->weight; }
|
||||
|
||||
// The overall drag coefficient for the wing as a whole. Units are
|
||||
// arbitrary.
|
||||
void setDragScale(float scale);
|
||||
float getDragScale();
|
||||
float getDragScale() { return _dragScale; }
|
||||
|
||||
// The ratio of force along the Z (lift) direction of each wing
|
||||
// segment to that along the X (drag) direction.
|
||||
void setLiftRatio(float ratio);
|
||||
float getLiftRatio();
|
||||
float getLiftRatio() { return _liftRatio; }
|
||||
|
||||
private:
|
||||
void interp(float* v1, float* v2, float frac, float* out);
|
||||
void interp(const float* v1, const float* v2, const float frac, float* out);
|
||||
Surface* newSurface(float* pos, float* orient, float chord,
|
||||
bool flap0, bool flap1, bool slat, bool spoiler);
|
||||
|
||||
|
@ -93,6 +111,12 @@ private:
|
|||
float _sweep;
|
||||
float _dihedral;
|
||||
|
||||
// calculated from above
|
||||
float _tip[3];
|
||||
float _meanChord; // std. mean chord
|
||||
float _wingspan;
|
||||
float _aspectRatio;
|
||||
|
||||
float _stall;
|
||||
float _stallWidth;
|
||||
float _stallPeak;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "FGFDM.hpp"
|
||||
#include "Atmosphere.hpp"
|
||||
#include "RigidBody.hpp"
|
||||
#include "Airplane.hpp"
|
||||
|
||||
using namespace yasim;
|
||||
|
@ -27,9 +28,17 @@ bool fgSetDouble (const char * name, double defaultValue = 0.0) { return 0; }
|
|||
|
||||
static const float RAD2DEG = 57.2957795131;
|
||||
static const float DEG2RAD = 0.0174532925199;
|
||||
/// knots 2 meters per second
|
||||
static const float KTS2MPS = 0.514444444444;
|
||||
|
||||
|
||||
enum Config
|
||||
{
|
||||
CONFIG_NONE,
|
||||
CONFIG_APPROACH,
|
||||
CONFIG_CRUISE,
|
||||
};
|
||||
|
||||
// Generate a graph of lift, drag and L/D against AoA at the specified
|
||||
// speed and altitude. The result is a space-separated file of
|
||||
// numbers: "aoa lift drag LD" (aoa in degrees, lift and drag in
|
||||
|
@ -40,92 +49,221 @@ static const float KTS2MPS = 0.514444444444;
|
|||
"dat" using 1:3 with lines title 'drag', \
|
||||
"dat" using 1:4 with lines title 'LD'
|
||||
*/
|
||||
void yasim_graph(Airplane* a, float alt, float kts)
|
||||
void yasim_graph(Airplane* a, const float alt, const float kts, int cfg = CONFIG_NONE)
|
||||
{
|
||||
Model* m = a->getModel();
|
||||
State s;
|
||||
Model* m = a->getModel();
|
||||
State s;
|
||||
|
||||
m->setAir(Atmosphere::getStdPressure(alt),
|
||||
Atmosphere::getStdTemperature(alt),
|
||||
Atmosphere::getStdDensity(alt));
|
||||
m->getBody()->recalc();
|
||||
m->setAir(Atmosphere::getStdPressure(alt),
|
||||
Atmosphere::getStdTemperature(alt),
|
||||
Atmosphere::getStdDensity(alt));
|
||||
|
||||
for(int deg=-179; deg<=179; deg++) {
|
||||
float aoa = deg * DEG2RAD;
|
||||
Airplane::setupState(aoa, kts * KTS2MPS, 0 ,&s);
|
||||
m->getBody()->reset();
|
||||
m->initIteration();
|
||||
m->calcForces(&s);
|
||||
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()
|
||||
|
||||
float acc[3];
|
||||
m->getBody()->getAccel(acc);
|
||||
Math::tmul33(s.orient, acc, acc);
|
||||
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;
|
||||
|
||||
float drag = acc[0] * (-1/9.8);
|
||||
float lift = 1 + acc[2] * (1/9.8);
|
||||
for(int deg=-15; deg<=90; deg++) {
|
||||
float aoa = deg * DEG2RAD;
|
||||
Airplane::setupState(aoa, kts * KTS2MPS, 0 ,&s);
|
||||
m->getBody()->reset();
|
||||
m->initIteration();
|
||||
m->calcForces(&s);
|
||||
|
||||
printf("%d %g %g %g\n", deg, lift, drag, lift/drag);
|
||||
float acc[3];
|
||||
m->getBody()->getAccel(acc);
|
||||
Math::tmul33(s.orient, acc, acc);
|
||||
|
||||
float drag = acc[0] * (-1/9.8);
|
||||
float lift = 1 + acc[2] * (1/9.8);
|
||||
float ld = lift/drag;
|
||||
|
||||
if (cd_min > drag) {
|
||||
cd_min = drag;
|
||||
cd_min_deg = deg;
|
||||
}
|
||||
if (cl_max < lift) {
|
||||
cl_max = lift;
|
||||
cl_max_deg = deg;
|
||||
}
|
||||
if (ld_max < ld) {
|
||||
ld_max= ld;
|
||||
ld_max_deg = deg;
|
||||
}
|
||||
printf("%d %g %g %g\n", deg, lift, drag, ld);
|
||||
}
|
||||
printf("# cl_max %g at %d deg\n", cl_max, cl_max_deg);
|
||||
printf("# cd_min %g at %d deg\n", cd_min, cd_min_deg);
|
||||
printf("# ld_max %g at %d deg\n", ld_max, ld_max_deg);
|
||||
}
|
||||
|
||||
void yasim_masses(Airplane* a)
|
||||
{
|
||||
RigidBody* body = a->getModel()->getBody();
|
||||
int i, N = body->numMasses();
|
||||
float pos[3];
|
||||
float m, mass = 0;
|
||||
printf("id posx posy posz mass\n");
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
body->getMassPosition(i, pos);
|
||||
m = body->getMass(i);
|
||||
printf("%d %.3f %.3f %.3f %.3f\n", i, pos[0], pos[1], pos[2], m);
|
||||
mass += m;
|
||||
}
|
||||
printf("Total mass: %g", mass);
|
||||
}
|
||||
|
||||
void yasim_drag(Airplane* a, const float aoa, const float alt, int cfg = CONFIG_NONE)
|
||||
{
|
||||
fprintf(stderr,"yasim_drag");
|
||||
Model* m = a->getModel();
|
||||
State s;
|
||||
|
||||
m->setAir(Atmosphere::getStdPressure(alt),
|
||||
Atmosphere::getStdTemperature(alt),
|
||||
Atmosphere::getStdDensity(alt));
|
||||
|
||||
switch (cfg) {
|
||||
case CONFIG_APPROACH:
|
||||
a->loadApproachControls();
|
||||
break;
|
||||
case CONFIG_CRUISE:
|
||||
a->loadCruiseControls();
|
||||
break;
|
||||
case CONFIG_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
m->getBody()->recalc();
|
||||
float cd_min = 1e6;
|
||||
int cd_min_kts = 0;
|
||||
printf("#kts, drag\n");
|
||||
|
||||
for(int kts=15; kts<=150; kts++) {
|
||||
Airplane::setupState(aoa, kts * KTS2MPS, 0 ,&s);
|
||||
m->getBody()->reset();
|
||||
m->initIteration();
|
||||
m->calcForces(&s);
|
||||
|
||||
float acc[3];
|
||||
m->getBody()->getAccel(acc);
|
||||
Math::tmul33(s.orient, acc, acc);
|
||||
|
||||
float drag = acc[0] * (-1/9.8);
|
||||
|
||||
if (cd_min > drag) {
|
||||
cd_min = drag;
|
||||
cd_min_kts = kts;
|
||||
}
|
||||
printf("%d %g\n", kts, drag);
|
||||
}
|
||||
printf("# cd_min %g at %d kts\n", cd_min, cd_min_kts);
|
||||
}
|
||||
|
||||
int usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: yasim <ac.xml> [-g [-a alt] [-s kts]]\n");
|
||||
return 1;
|
||||
fprintf(stderr, "Usage: \n");
|
||||
fprintf(stderr, " yasim <aircraft.xml> [-g [-a meters] [-s kts] [-approach | -cruise] ]\n");
|
||||
fprintf(stderr, " yasim <aircraft.xml> [-d [-a meters] [-approach | -cruise] ]\n");
|
||||
fprintf(stderr, " yasim <aircraft.xml> [-m]\n");
|
||||
fprintf(stderr, " -g print lift/drag table: aoa, lift, drag, lift/drag \n");
|
||||
fprintf(stderr, " -d print drag over TAS: kts, drag\n");
|
||||
fprintf(stderr, " -a set altitude in meters!\n");
|
||||
fprintf(stderr, " -s set speed in knots\n");
|
||||
fprintf(stderr, " -m print mass distribution table: id, x, y, z, mass \n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
FGFDM* fdm = new FGFDM();
|
||||
Airplane* a = fdm->getAirplane();
|
||||
FGFDM* fdm = new FGFDM();
|
||||
Airplane* a = fdm->getAirplane();
|
||||
|
||||
if(argc < 2) return usage();
|
||||
if(argc < 2) return usage();
|
||||
// Read
|
||||
try {
|
||||
string file = argv[1];
|
||||
readXML(SGPath(file), *fdm);
|
||||
}
|
||||
catch (const sg_exception &e) {
|
||||
printf("XML parse error: %s (%s)\n", e.getFormattedMessage().c_str(), e.getOrigin());
|
||||
}
|
||||
|
||||
// Read
|
||||
try {
|
||||
string file = argv[1];
|
||||
readXML(SGPath(file), *fdm);
|
||||
} catch (const sg_exception &e) {
|
||||
printf("XML parse error: %s (%s)\n",
|
||||
e.getFormattedMessage().c_str(), e.getOrigin());
|
||||
}
|
||||
|
||||
// ... and run
|
||||
a->compile();
|
||||
if(a->getFailureMsg())
|
||||
printf("SOLUTION FAILURE: %s\n", a->getFailureMsg());
|
||||
|
||||
if(!a->getFailureMsg() && argc > 2 && strcmp(argv[2], "-g") == 0) {
|
||||
float alt = 5000, kts = 100;
|
||||
for(int i=3; i<argc; i++) {
|
||||
if (std::strcmp(argv[i], "-a") == 0) alt = std::atof(argv[++i]);
|
||||
else if(std::strcmp(argv[i], "-s") == 0) kts = std::atof(argv[++i]);
|
||||
else return usage();
|
||||
// ... and run
|
||||
a->compile();
|
||||
if(a->getFailureMsg())
|
||||
printf("SOLUTION FAILURE: %s\n", a->getFailureMsg());
|
||||
if(!a->getFailureMsg() && argc > 2 ) {
|
||||
if(strcmp(argv[2], "-g") == 0) {
|
||||
float alt = 5000, kts = 100;
|
||||
int cfg = CONFIG_NONE;
|
||||
for(int i=3; i<argc; i++) {
|
||||
if (std::strcmp(argv[i], "-a") == 0) {
|
||||
if (i+1 < argc) alt = std::atof(argv[++i]);
|
||||
}
|
||||
yasim_graph(a, alt, kts);
|
||||
} else {
|
||||
float aoa = a->getCruiseAoA() * RAD2DEG;
|
||||
float tail = -1 * a->getTailIncidence() * RAD2DEG;
|
||||
float drag = 1000 * a->getDragCoefficient();
|
||||
float cg[3];
|
||||
a->getModel()->getBody()->getCG(cg);
|
||||
a->getModel()->getBody()->recalc();
|
||||
|
||||
float SI_inertia[9];
|
||||
a->getModel()->getBody()->getInertiaMatrix(SI_inertia);
|
||||
|
||||
printf("Solution results:");
|
||||
printf(" Iterations: %d\n", a->getSolutionIterations());
|
||||
printf(" Drag Coefficient: %f\n", drag);
|
||||
printf(" Lift Ratio: %f\n", a->getLiftRatio());
|
||||
printf(" Cruise AoA: %f\n", aoa);
|
||||
printf(" Tail Incidence: %f\n", tail);
|
||||
printf("Approach Elevator: %f\n", a->getApproachElevator());
|
||||
printf(" CG: x:%.3f, y:%.3f, z:%.3f\n\n", cg[0], cg[1], cg[2]);
|
||||
printf(" Inertia tensor : %.3f, %.3f, %.3f\n", SI_inertia[0], SI_inertia[1], SI_inertia[2]);
|
||||
printf(" [kg*m^2] %.3f, %.3f, %.3f\n", SI_inertia[3], SI_inertia[4], SI_inertia[5]);
|
||||
printf(" Origo at CG %.3f, %.3f, %.3f\n", SI_inertia[6], SI_inertia[7], SI_inertia[8]);
|
||||
else if(std::strcmp(argv[i], "-s") == 0) {
|
||||
if(i+1 < argc) kts = std::atof(argv[++i]);
|
||||
}
|
||||
else if(std::strcmp(argv[i], "-approach") == 0) cfg = CONFIG_APPROACH;
|
||||
else if(std::strcmp(argv[i], "-cruise") == 0) cfg = CONFIG_CRUISE;
|
||||
else return usage();
|
||||
}
|
||||
yasim_graph(a, alt, kts, cfg);
|
||||
}
|
||||
else if(strcmp(argv[2], "-d") == 0) {
|
||||
float alt = 2000, aoa = a->getCruiseAoA();
|
||||
int cfg = CONFIG_NONE;
|
||||
for(int i=3; i<argc; i++) {
|
||||
if (std::strcmp(argv[i], "-a") == 0) {
|
||||
if (i+1 < argc) alt = std::atof(argv[++i]);
|
||||
}
|
||||
else if(std::strcmp(argv[i], "-approach") == 0) cfg = CONFIG_APPROACH;
|
||||
else if(std::strcmp(argv[i], "-cruise") == 0) cfg = CONFIG_CRUISE;
|
||||
else return usage();
|
||||
}
|
||||
yasim_drag(a, aoa, alt, cfg);
|
||||
}
|
||||
else if(strcmp(argv[2], "-m") == 0) {
|
||||
yasim_masses(a);
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("Solution results:");
|
||||
float aoa = a->getCruiseAoA() * RAD2DEG;
|
||||
float tail = -1 * a->getTailIncidence() * RAD2DEG;
|
||||
float drag = 1000 * a->getDragCoefficient();
|
||||
float cg[3];
|
||||
a->getModel()->getBody()->getCG(cg);
|
||||
a->getModel()->getBody()->recalc();
|
||||
|
||||
float SI_inertia[9];
|
||||
a->getModel()->getBody()->getInertiaMatrix(SI_inertia);
|
||||
|
||||
printf(" Iterations: %d\n", a->getSolutionIterations());
|
||||
printf(" Drag Coefficient: %f\n", drag);
|
||||
printf(" Lift Ratio: %f\n", a->getLiftRatio());
|
||||
printf(" Cruise AoA: %f\n", aoa);
|
||||
printf(" Tail Incidence: %f\n", tail);
|
||||
printf("Approach Elevator: %f\n", a->getApproachElevator());
|
||||
printf(" CG: x:%.3f, y:%.3f, z:%.3f\n\n", cg[0], cg[1], cg[2]);
|
||||
printf("Inertia tensor [kg*m^2], origo at CG:\n");
|
||||
printf(" %7.3f, %7.3f, %7.3f\n", SI_inertia[0], SI_inertia[1], SI_inertia[2]);
|
||||
printf(" %7.3f, %7.3f, %7.3f\n", SI_inertia[3], SI_inertia[4], SI_inertia[5]);
|
||||
printf(" %7.3f, %7.3f, %7.3f\n", SI_inertia[6], SI_inertia[7], SI_inertia[8]);
|
||||
}
|
||||
delete fdm;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -67,7 +67,6 @@
|
|||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Scenery/scenery.hxx>
|
||||
#include <Scenery/tilemgr.hxx>
|
||||
|
||||
#include "flight.hxx"
|
||||
|
||||
|
@ -330,7 +329,7 @@ FGGroundCache::prepare_ground_cache(double startSimTime, double endSimTime,
|
|||
SGGeod geodPt = SGGeod::fromCart(pt);
|
||||
// Don't blow away the cache ground_radius and stuff if there's no
|
||||
// scenery
|
||||
if (!globals->get_tile_mgr()->schedule_scenery(geodPt, rad, 1.0)) {
|
||||
if (!globals->get_scenery()->schedule_scenery(geodPt, rad, 1.0)) {
|
||||
SG_LOG(SG_FLIGHT, SG_BULK, "prepare_ground_cache(): scenery_available "
|
||||
"returns false at " << geodPt << " " << pt << " " << rad);
|
||||
return false;
|
||||
|
|
|
@ -59,6 +59,12 @@ CatalogRef AddCatalogDialog::addedCatalog()
|
|||
return m_result;
|
||||
}
|
||||
|
||||
void AddCatalogDialog::setNonInteractiveMode()
|
||||
{
|
||||
m_nonInteractiveMode = true;
|
||||
ui->buttonBox->hide();
|
||||
}
|
||||
|
||||
void AddCatalogDialog::setUrlAndDownload(QUrl url)
|
||||
{
|
||||
m_catalogUrl = url;
|
||||
|
@ -199,6 +205,10 @@ void AddCatalogDialog::onCatalogStatusChanged(Catalog* cat)
|
|||
}
|
||||
|
||||
ui->stack->setCurrentIndex(STATE_FINISHED);
|
||||
if (m_nonInteractiveMode) {
|
||||
QDialog::accept(); // we're done
|
||||
}
|
||||
|
||||
updateUi();
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,13 @@ public:
|
|||
|
||||
simgear::pkg::CatalogRef addedCatalog();
|
||||
|
||||
/**
|
||||
* @brief setNonInteractiveMode - display progres but don't wait for user
|
||||
* interaction at all. (Hides the buttons, closes autoamtically on success
|
||||
* or failure)
|
||||
*/
|
||||
void setNonInteractiveMode();
|
||||
|
||||
void setUrlAndDownload(QUrl url);
|
||||
private slots:
|
||||
virtual void reject();
|
||||
|
@ -69,6 +76,7 @@ private:
|
|||
simgear::pkg::RootRef m_packageRoot;
|
||||
QUrl m_catalogUrl;
|
||||
simgear::pkg::CatalogRef m_result;
|
||||
bool m_nonInteractiveMode = false;
|
||||
};
|
||||
|
||||
#endif // FG_GUI_ADDCATALOGDIALOG_HXX
|
||||
|
|
|
@ -46,6 +46,8 @@ AircraftItemDelegate::AircraftItemDelegate(QListView* view) :
|
|||
|
||||
m_leftArrowIcon.load(":/left-arrow-icon");
|
||||
m_rightArrowIcon.load(":/right-arrow-icon");
|
||||
m_openPreviewsIcon.load(":/preview-icon");
|
||||
m_openPreviewsIcon = m_openPreviewsIcon.scaled(32, 32, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
void AircraftItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option,
|
||||
|
@ -79,15 +81,22 @@ void AircraftItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem
|
|||
painter->drawLine(option.rect.topLeft(), option.rect.topRight());
|
||||
}
|
||||
|
||||
|
||||
// thumbnail
|
||||
QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
|
||||
quint32 yPos = contentRect.center().y() - (thumbnail.height() / 2);
|
||||
painter->drawPixmap(contentRect.left(), yPos, thumbnail);
|
||||
|
||||
// draw 1px frame
|
||||
QRect thumbFrame(contentRect.left(), yPos, thumbnail.width(), thumbnail.height());
|
||||
painter->setPen(QColor(0x7f, 0x7f, 0x7f));
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawRect(contentRect.left(), yPos, thumbnail.width(), thumbnail.height());
|
||||
painter->drawRect(thumbFrame);
|
||||
|
||||
if (!index.data(AircraftPreviewsRole).toList().empty()) {
|
||||
QRect previewIconRect = m_openPreviewsIcon.rect();
|
||||
previewIconRect.moveBottomLeft(thumbFrame.bottomLeft());
|
||||
painter->drawPixmap(previewIconRect, m_openPreviewsIcon);
|
||||
}
|
||||
|
||||
// draw bottom dividing line
|
||||
painter->drawLine(contentRect.left(), contentRect.bottom() + MARGIN,
|
||||
|
@ -337,6 +346,13 @@ bool AircraftItemDelegate::eventFilter( QObject*, QEvent* event )
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((event->type() == QEvent::MouseButtonRelease) &&
|
||||
!index.data(AircraftPreviewsRole).toList().empty() &&
|
||||
showPreviewsRect(vr, index).contains(me->pos()))
|
||||
{
|
||||
emit showPreviews(index);
|
||||
}
|
||||
} else if ( event->type() == QEvent::MouseMove ) {
|
||||
|
||||
}
|
||||
|
@ -381,6 +397,18 @@ QRect AircraftItemDelegate::packageButtonRect(const QRect& visualRect, const QMo
|
|||
BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
}
|
||||
|
||||
QRect AircraftItemDelegate::showPreviewsRect(const QRect& visualRect, const QModelIndex& index) const
|
||||
{
|
||||
QRect contentRect = visualRect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
|
||||
QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
|
||||
const quint32 yPos = contentRect.center().y() - (thumbnail.height() / 2);
|
||||
QRect thumbFrame(contentRect.left(), yPos, thumbnail.width(), thumbnail.height());
|
||||
|
||||
QRect previewIconRect = m_openPreviewsIcon.rect();
|
||||
previewIconRect.moveBottomLeft(thumbFrame.bottomLeft());
|
||||
return previewIconRect;
|
||||
}
|
||||
|
||||
void AircraftItemDelegate::drawRating(QPainter* painter, QString label, const QRect& box, int value) const
|
||||
{
|
||||
QRect dotBox = box;
|
||||
|
|
|
@ -50,17 +50,23 @@ Q_SIGNALS:
|
|||
void requestUninstall(const QModelIndex& index);
|
||||
|
||||
void cancelDownload(const QModelIndex& index);
|
||||
|
||||
void showPreviews(const QModelIndex& index);
|
||||
|
||||
private:
|
||||
QRect leftCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const;
|
||||
QRect rightCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const;
|
||||
|
||||
QRect packageButtonRect(const QRect& visualRect, const QModelIndex& index) const;
|
||||
|
||||
QRect showPreviewsRect(const QRect& visualRect, const QModelIndex& index) const;
|
||||
|
||||
void drawRating(QPainter* painter, QString label, const QRect& box, int value) const;
|
||||
|
||||
QListView* m_view;
|
||||
QPixmap m_leftArrowIcon,
|
||||
m_rightArrowIcon;
|
||||
m_rightArrowIcon,
|
||||
m_openPreviewsIcon;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -40,28 +40,18 @@
|
|||
// FlightGear
|
||||
#include <Main/globals.hxx>
|
||||
|
||||
|
||||
const int STANDARD_THUMBNAIL_HEIGHT = 128;
|
||||
const int STANDARD_THUMBNAIL_WIDTH = 172;
|
||||
static quint32 CACHE_VERSION = 7;
|
||||
|
||||
using namespace simgear::pkg;
|
||||
|
||||
AircraftItem::AircraftItem() :
|
||||
excluded(false),
|
||||
usesHeliports(false),
|
||||
usesSeaports(false)
|
||||
AircraftItem::AircraftItem()
|
||||
{
|
||||
// oh for C++11 initialisers
|
||||
for (int i=0; i<4; ++i) ratings[i] = 0;
|
||||
}
|
||||
|
||||
AircraftItem::AircraftItem(QDir dir, QString filePath) :
|
||||
excluded(false),
|
||||
usesHeliports(false),
|
||||
usesSeaports(false)
|
||||
AircraftItem::AircraftItem(QDir dir, QString filePath)
|
||||
{
|
||||
for (int i=0; i<4; ++i) ratings[i] = 0;
|
||||
|
||||
SGPropertyNode root;
|
||||
readProperties(filePath.toStdString(), &root);
|
||||
|
||||
|
@ -97,6 +87,12 @@ AircraftItem::AircraftItem(QDir dir, QString filePath) :
|
|||
|
||||
if (sim->hasChild("variant-of")) {
|
||||
variantOf = sim->getStringValue("variant-of");
|
||||
} else {
|
||||
isPrimary = true;
|
||||
}
|
||||
|
||||
if (sim->hasChild("primary-set")) {
|
||||
isPrimary = sim->getBoolValue("primary-set");
|
||||
}
|
||||
|
||||
if (sim->hasChild("tags")) {
|
||||
|
@ -113,6 +109,22 @@ AircraftItem::AircraftItem(QDir dir, QString filePath) :
|
|||
}
|
||||
} // of tags iteration
|
||||
} // of set-xml has tags
|
||||
|
||||
if (sim->hasChild("previews")) {
|
||||
SGPropertyNode_ptr previewsNode = sim->getChild("previews");
|
||||
for (auto previewNode : previewsNode->getChildren("preview")) {
|
||||
// add file path as url
|
||||
QString pathInXml = QString::fromStdString(previewNode->getStringValue("path"));
|
||||
QString previewPath = dir.absoluteFilePath(pathInXml);
|
||||
previews.append(QUrl::fromLocalFile(previewPath));
|
||||
}
|
||||
}
|
||||
|
||||
if (sim->hasChild("thumbnail")) {
|
||||
thumbnailPath = sim->getStringValue("thumbnail");
|
||||
} else {
|
||||
thumbnailPath = "thumbnail.jpg";
|
||||
}
|
||||
}
|
||||
|
||||
QString AircraftItem::baseName() const
|
||||
|
@ -129,8 +141,10 @@ void AircraftItem::fromDataStream(QDataStream& ds)
|
|||
return;
|
||||
}
|
||||
|
||||
ds >> description >> longDescription >> authors >> variantOf;
|
||||
ds >> description >> longDescription >> authors >> variantOf >> isPrimary;
|
||||
for (int i=0; i<4; ++i) ds >> ratings[i];
|
||||
ds >> previews;
|
||||
ds >> thumbnailPath;
|
||||
}
|
||||
|
||||
void AircraftItem::toDataStream(QDataStream& ds) const
|
||||
|
@ -140,8 +154,10 @@ void AircraftItem::toDataStream(QDataStream& ds) const
|
|||
return;
|
||||
}
|
||||
|
||||
ds << description << longDescription << authors << variantOf;
|
||||
ds << description << longDescription << authors << variantOf << isPrimary;
|
||||
for (int i=0; i<4; ++i) ds << ratings[i];
|
||||
ds << previews;
|
||||
ds << thumbnailPath;
|
||||
}
|
||||
|
||||
QPixmap AircraftItem::thumbnail(bool loadIfRequired) const
|
||||
|
@ -149,8 +165,8 @@ QPixmap AircraftItem::thumbnail(bool loadIfRequired) const
|
|||
if (m_thumbnail.isNull() && loadIfRequired) {
|
||||
QFileInfo info(path);
|
||||
QDir dir = info.dir();
|
||||
if (dir.exists("thumbnail.jpg")) {
|
||||
m_thumbnail.load(dir.filePath("thumbnail.jpg"));
|
||||
if (dir.exists(thumbnailPath)) {
|
||||
m_thumbnail.load(dir.filePath(thumbnailPath));
|
||||
// resize to the standard size
|
||||
if (m_thumbnail.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
||||
m_thumbnail = m_thumbnail.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT, Qt::SmoothTransformation);
|
||||
|
@ -161,9 +177,6 @@ QPixmap AircraftItem::thumbnail(bool loadIfRequired) const
|
|||
return m_thumbnail;
|
||||
}
|
||||
|
||||
|
||||
static quint32 CACHE_VERSION = 5;
|
||||
|
||||
class AircraftScanThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -284,7 +297,7 @@ private:
|
|||
continue;
|
||||
}
|
||||
|
||||
if (item->variantOf.isNull()) {
|
||||
if (item->isPrimary) {
|
||||
baseAircraft.insert(item->baseName(), item);
|
||||
} else {
|
||||
variants.append(item);
|
||||
|
@ -402,14 +415,22 @@ protected:
|
|||
if (pix.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
||||
pix = pix.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT, Qt::SmoothTransformation);
|
||||
}
|
||||
m_model->m_thumbnailPixmapCache.insert(QString::fromStdString(aThumbnailUrl), pix);
|
||||
|
||||
// notify any affected items. Linear scan here avoids another map/dict
|
||||
// structure.
|
||||
m_model->m_downloadedPixmapCache.insert(QString::fromStdString(aThumbnailUrl), pix);
|
||||
|
||||
// notify any affected items. Linear scan here avoids another map/dict structure.
|
||||
for (auto pkg : m_model->m_packages) {
|
||||
const string_list& urls(pkg->thumbnailUrls());
|
||||
auto cit = std::find(urls.begin(), urls.end(), aThumbnailUrl);
|
||||
if (cit != urls.end()) {
|
||||
const int variantCount = pkg->variants().size();
|
||||
bool notifyChanged = false;
|
||||
|
||||
for (int v=0; v < variantCount; ++v) {
|
||||
const Package::Thumbnail& thumb(pkg->thumbnailForVariant(v));
|
||||
if (thumb.url == aThumbnailUrl) {
|
||||
notifyChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (notifyChanged) {
|
||||
QModelIndex mi = indexForPackage(pkg);
|
||||
m_model->dataChanged(mi, mi);
|
||||
}
|
||||
|
@ -432,7 +453,7 @@ private:
|
|||
AircraftItemModel* m_model;
|
||||
};
|
||||
|
||||
AircraftItemModel::AircraftItemModel(QObject* pr ) :
|
||||
AircraftItemModel::AircraftItemModel(QObject* pr) :
|
||||
QAbstractListModel(pr)
|
||||
{
|
||||
}
|
||||
|
@ -593,10 +614,6 @@ QVariant AircraftItemModel::data(const QModelIndex& index, int role) const
|
|||
return m_delegateStates.at(row).variant;
|
||||
}
|
||||
|
||||
if (role == AircraftCurrentThumbnailRole) {
|
||||
return m_delegateStates.at(row).thumbnail;
|
||||
}
|
||||
|
||||
if (row >= m_items.size()) {
|
||||
quint32 packageIndex = row - m_items.size();
|
||||
const PackageRef& pkg(m_packages[packageIndex]);
|
||||
|
@ -623,20 +640,7 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
|
|||
return item->variants.count();
|
||||
}
|
||||
|
||||
if (role == AircraftThumbnailCountRole) {
|
||||
QPixmap p = item->thumbnail();
|
||||
return p.isNull() ? 0 : 1;
|
||||
}
|
||||
|
||||
if (role == AircraftThumbnailSizeRole) {
|
||||
QPixmap pm = item->thumbnail(false);
|
||||
if (pm.isNull()) {
|
||||
return QSize(STANDARD_THUMBNAIL_WIDTH, STANDARD_THUMBNAIL_HEIGHT);
|
||||
}
|
||||
return pm.size();
|
||||
}
|
||||
|
||||
if ((role >= AircraftVariantDescriptionRole) && (role < AircraftThumbnailRole)) {
|
||||
if (role >= AircraftVariantDescriptionRole) {
|
||||
int variantIndex = role - AircraftVariantDescriptionRole;
|
||||
return item->variants.at(variantIndex)->description;
|
||||
}
|
||||
|
@ -648,6 +652,14 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
|
|||
}
|
||||
}
|
||||
|
||||
if (role == AircraftThumbnailSizeRole) {
|
||||
QPixmap pm = item->thumbnail(false);
|
||||
if (pm.isNull()) {
|
||||
return QSize(STANDARD_THUMBNAIL_WIDTH, STANDARD_THUMBNAIL_HEIGHT);
|
||||
}
|
||||
return pm.size();
|
||||
}
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
if (item->description.isEmpty()) {
|
||||
return tr("Missing description for: %1").arg(item->baseName());
|
||||
|
@ -662,7 +674,13 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
|
|||
return item->authors;
|
||||
} else if ((role >= AircraftRatingRole) && (role < AircraftVariantDescriptionRole)) {
|
||||
return item->ratings[role - AircraftRatingRole];
|
||||
} else if (role >= AircraftThumbnailRole) {
|
||||
} else if (role == AircraftPreviewsRole) {
|
||||
QVariantList result;
|
||||
Q_FOREACH(QUrl u, item->previews) {
|
||||
result.append(u);
|
||||
}
|
||||
return result;
|
||||
} else if (role == AircraftThumbnailRole) {
|
||||
return item->thumbnail();
|
||||
} else if (role == AircraftPackageIdRole) {
|
||||
// can we fake an ID? otherwise fall through to a null variant
|
||||
|
@ -692,10 +710,10 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
|
|||
QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, const DelegateState& state, int role) const
|
||||
{
|
||||
if (role == Qt::DecorationRole) {
|
||||
role = AircraftThumbnailRole; // use first thumbnail
|
||||
role = AircraftThumbnailRole;
|
||||
}
|
||||
|
||||
if ((role >= AircraftVariantDescriptionRole) && (role < AircraftThumbnailRole)) {
|
||||
if (role >= AircraftVariantDescriptionRole) {
|
||||
int variantIndex = role - AircraftVariantDescriptionRole;
|
||||
QString desc = QString::fromStdString(item->nameForVariant(variantIndex));
|
||||
if (desc.isEmpty()) {
|
||||
|
@ -743,11 +761,10 @@ QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, const Delega
|
|||
if (pm.isNull())
|
||||
return QSize(STANDARD_THUMBNAIL_WIDTH, STANDARD_THUMBNAIL_HEIGHT);
|
||||
return pm.size();
|
||||
} else if (role >= AircraftThumbnailRole) {
|
||||
DelegateState changedState(state);
|
||||
// override the current thumbnail as required
|
||||
changedState.thumbnail = (role - AircraftThumbnailRole);
|
||||
return packageThumbnail(item, changedState);
|
||||
} else if (role == AircraftThumbnailRole) {
|
||||
return packageThumbnail(item, state);
|
||||
} else if (role == AircraftPreviewsRole) {
|
||||
return packagePreviews(item, state);
|
||||
} else if (role == AircraftAuthorsRole) {
|
||||
std::string authors = item->getLocalisedProp("author", state.variant);
|
||||
if (!authors.empty()) {
|
||||
|
@ -776,46 +793,69 @@ QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, const Delega
|
|||
|
||||
QVariant AircraftItemModel::packageThumbnail(PackageRef p, const DelegateState& ds, bool download) const
|
||||
{
|
||||
const string_list& thumbnails(p->thumbnailUrls());
|
||||
if (ds.thumbnail >= static_cast<int>(thumbnails.size())) {
|
||||
const Package::Thumbnail& thumb(p->thumbnailForVariant(ds.variant));
|
||||
if (thumb.url.empty()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
std::string thumbnailUrl = thumbnails.at(ds.thumbnail);
|
||||
QString urlQString(QString::fromStdString(thumbnailUrl));
|
||||
if (m_thumbnailPixmapCache.contains(urlQString)) {
|
||||
QString urlQString(QString::fromStdString(thumb.url));
|
||||
if (m_downloadedPixmapCache.contains(urlQString)) {
|
||||
// cache hit, easy
|
||||
return m_thumbnailPixmapCache.value(urlQString);
|
||||
return m_downloadedPixmapCache.value(urlQString);
|
||||
}
|
||||
|
||||
// check the on-disk store. This relies on the order of thumbnails in the
|
||||
// results of thumbnailUrls and thumbnails corresponding
|
||||
// check the on-disk store.
|
||||
InstallRef ex = p->existingInstall();
|
||||
if (ex.valid()) {
|
||||
const string_list& thumbNames(p->thumbnails());
|
||||
if (!thumbNames.empty()) {
|
||||
SGPath path(ex->path());
|
||||
path.append(p->thumbnails()[ds.thumbnail]);
|
||||
if (path.exists()) {
|
||||
QPixmap pix;
|
||||
pix.load(QString::fromStdString(path.utf8Str()));
|
||||
// resize to the standard size
|
||||
if (pix.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
||||
pix = pix.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT);
|
||||
}
|
||||
m_thumbnailPixmapCache[urlQString] = pix;
|
||||
return pix;
|
||||
SGPath thumbPath = ex->path() / thumb.path;
|
||||
if (thumbPath.exists()) {
|
||||
QPixmap pix;
|
||||
pix.load(QString::fromStdString(thumbPath.utf8Str()));
|
||||
// resize to the standard size
|
||||
if (pix.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
||||
pix = pix.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT);
|
||||
}
|
||||
} // of have thumbnail file names
|
||||
m_downloadedPixmapCache[urlQString] = pix;
|
||||
return pix;
|
||||
}
|
||||
} // of have existing install
|
||||
|
||||
if (download) {
|
||||
m_packageRoot->requestThumbnailData(thumbnailUrl);
|
||||
m_packageRoot->requestThumbnailData(thumb.url);
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant AircraftItemModel::packagePreviews(PackageRef p, const DelegateState& ds) const
|
||||
{
|
||||
const Package::PreviewVec& previews = p->previewsForVariant(ds.variant);
|
||||
if (previews.empty()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariantList result;
|
||||
// if we have an install, return file URLs, not remote (http) ones
|
||||
InstallRef ex = p->existingInstall();
|
||||
if (ex.valid()) {
|
||||
for (auto p : previews) {
|
||||
SGPath localPreviewPath = ex->path() / p.path;
|
||||
if (!localPreviewPath.exists()) {
|
||||
qWarning() << "missing local preview" << QString::fromStdString(localPreviewPath.utf8Str());
|
||||
continue;
|
||||
}
|
||||
result.append(QUrl::fromLocalFile(QString::fromStdString(localPreviewPath.utf8Str())));
|
||||
}
|
||||
}
|
||||
|
||||
// return remote urls
|
||||
for (auto p : previews) {
|
||||
result.append(QUrl(QString::fromStdString(p.url)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AircraftItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
int row = index.row();
|
||||
|
@ -831,16 +871,6 @@ bool AircraftItemModel::setData(const QModelIndex &index, const QVariant &value,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (role == AircraftCurrentThumbnailRole) {
|
||||
if (m_delegateStates[row].thumbnail == newValue) {
|
||||
return true;
|
||||
}
|
||||
|
||||
m_delegateStates[row].thumbnail = newValue;
|
||||
emit dataChanged(index, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ const int AircraftPathRole = Qt::UserRole + 1;
|
|||
const int AircraftAuthorsRole = Qt::UserRole + 2;
|
||||
const int AircraftVariantRole = Qt::UserRole + 3;
|
||||
const int AircraftVariantCountRole = Qt::UserRole + 4;
|
||||
const int AircraftThumbnailCountRole = Qt::UserRole + 5;
|
||||
const int AircraftPackageIdRole = Qt::UserRole + 6;
|
||||
const int AircraftPackageStatusRole = Qt::UserRole + 7;
|
||||
const int AircraftPackageProgressRole = Qt::UserRole + 8;
|
||||
|
@ -51,12 +50,12 @@ const int AircraftURIRole = Qt::UserRole + 14;
|
|||
const int AircraftThumbnailSizeRole = Qt::UserRole + 15;
|
||||
const int AircraftIsHelicopterRole = Qt::UserRole + 16;
|
||||
const int AircraftIsSeaplaneRole = Qt::UserRole + 17;
|
||||
const int AircraftCurrentThumbnailRole = Qt::UserRole + 18;
|
||||
const int AircraftPackageRefRole = Qt::UserRole + 19;
|
||||
const int AircraftThumbnailRole = Qt::UserRole + 20;
|
||||
const int AircraftPreviewsRole = Qt::UserRole + 21;
|
||||
|
||||
const int AircraftRatingRole = Qt::UserRole + 100;
|
||||
const int AircraftVariantDescriptionRole = Qt::UserRole + 200;
|
||||
const int AircraftThumbnailRole = Qt::UserRole + 300;
|
||||
|
||||
class AircraftScanThread;
|
||||
class QDataStream;
|
||||
|
@ -81,17 +80,20 @@ struct AircraftItem
|
|||
|
||||
QPixmap thumbnail(bool loadIfRequired = true) const;
|
||||
|
||||
bool excluded;
|
||||
bool excluded = false;
|
||||
QString path;
|
||||
QString description;
|
||||
QString longDescription;
|
||||
QString authors;
|
||||
int ratings[4];
|
||||
int ratings[4] = {0, 0, 0, 0};
|
||||
QString variantOf;
|
||||
QDateTime pathModTime;
|
||||
QList<AircraftItemPtr> variants;
|
||||
bool usesHeliports;
|
||||
bool usesSeaports;
|
||||
bool usesHeliports = false;
|
||||
bool usesSeaports = false;
|
||||
QList<QUrl> previews;
|
||||
bool isPrimary = false;
|
||||
QString thumbnailPath;
|
||||
private:
|
||||
mutable QPixmap m_thumbnail;
|
||||
};
|
||||
|
@ -199,6 +201,8 @@ private:
|
|||
QVariant packageThumbnail(simgear::pkg::PackageRef p,
|
||||
const DelegateState& state, bool download = true) const;
|
||||
|
||||
QVariant packagePreviews(simgear::pkg::PackageRef p, const DelegateState &ds) const;
|
||||
|
||||
void abandonCurrentScan();
|
||||
void refreshPackages();
|
||||
|
||||
|
@ -217,7 +221,7 @@ private:
|
|||
simgear::pkg::RootRef m_packageRoot;
|
||||
simgear::pkg::PackageList m_packages;
|
||||
|
||||
mutable QHash<QString, QPixmap> m_thumbnailPixmapCache;
|
||||
mutable QHash<QString, QPixmap> m_downloadedPixmapCache;
|
||||
};
|
||||
|
||||
#endif // of FG_GUI_AIRCRAFT_MODEL
|
||||
|
|
|
@ -189,7 +189,8 @@ void AirportDiagram::addRunway(FGRunwayRef rwy)
|
|||
r.runway = rwy;
|
||||
m_runways.append(r);
|
||||
|
||||
recomputeBounds(false);
|
||||
extendBounds(r.p1);
|
||||
extendBounds(r.p2);
|
||||
update();
|
||||
}
|
||||
|
||||
|
@ -224,7 +225,7 @@ void AirportDiagram::addParking(FGParkingRef park)
|
|||
{
|
||||
ParkingData pd = { project(park->geod()), park };
|
||||
m_parking.push_back(pd);
|
||||
recomputeBounds(false);
|
||||
extendBounds(pd.pt);
|
||||
update();
|
||||
}
|
||||
|
||||
|
@ -232,7 +233,7 @@ void AirportDiagram::addHelipad(FGHelipadRef pad)
|
|||
{
|
||||
HelipadData pd = { project(pad->geod()), pad };
|
||||
m_helipads.push_back(pd);
|
||||
recomputeBounds(false);
|
||||
extendBounds(pd.pt);
|
||||
update();
|
||||
}
|
||||
|
||||
|
|
|
@ -587,6 +587,17 @@ void BaseDiagram::doComputeBounds()
|
|||
|
||||
void BaseDiagram::extendBounds(const QPointF& p)
|
||||
{
|
||||
// this check added after a bug where apt.dat reports SCSL as
|
||||
// https://airportguide.com/airport/info/AG0003 (British Columbia)
|
||||
// but the groundnet is for
|
||||
// https://en.wikipedia.org/wiki/Salar_de_Atacama_Airport
|
||||
// causing a rather large airport boundary.
|
||||
QPointF v = (p - m_bounds.center());
|
||||
if (v.manhattanLength() > 20000) {
|
||||
qWarning() << "Excessively distant point" << p << v.manhattanLength();
|
||||
return;
|
||||
}
|
||||
|
||||
extendRect(m_bounds, p);
|
||||
}
|
||||
|
||||
|
|
|
@ -117,11 +117,13 @@ if (HAVE_QT)
|
|||
InstallSceneryDialog.cxx
|
||||
EditCustomMPServerDialog.cxx
|
||||
EditCustomMPServerDialog.hxx
|
||||
previewwindow.cpp
|
||||
previewwindow.h
|
||||
${uic_sources}
|
||||
${qrc_sources})
|
||||
|
||||
set_property(TARGET fglauncher PROPERTY AUTOMOC ON)
|
||||
target_link_libraries(fglauncher Qt5::Core Qt5::Widgets SimGearCore)
|
||||
target_link_libraries(fglauncher Qt5::Core Qt5::Widgets Qt5::Network SimGearCore)
|
||||
target_include_directories(fglauncher PRIVATE ${PROJECT_BINARY_DIR}/src/GUI)
|
||||
|
||||
|
||||
|
|
1380
src/GUI/Launcher.ui
1380
src/GUI/Launcher.ui
File diff suppressed because it is too large
Load diff
|
@ -536,7 +536,7 @@ void LocationWidget::setLocationProperties()
|
|||
QStringList props = QStringList() << "vor-id" << "fix" << "ndb-id" <<
|
||||
"runway-requested" << "navaid-id" << "offset-azimuth-deg" <<
|
||||
"offset-distance-nm" << "glideslope-deg" <<
|
||||
"speed-set" << "on-ground" << "airspeed-kt" << "heading-deg" <<
|
||||
"speed-set" << "on-ground" << "airspeed-kt" <<
|
||||
"airport-id" << "runway" << "parkpos";
|
||||
|
||||
Q_FOREACH(QString s, props) {
|
||||
|
@ -556,10 +556,10 @@ void LocationWidget::setLocationProperties()
|
|||
return;
|
||||
}
|
||||
|
||||
fgSetDouble("/sim/presets/latitude-deg", -9999.0);
|
||||
fgSetDouble("/sim/presets/longitude-deg", -9999.0);
|
||||
fgSetDouble("/sim/presets/latitude-deg", 9999.0);
|
||||
fgSetDouble("/sim/presets/longitude-deg", 9999.0);
|
||||
fgSetDouble("/sim/presets/altitude-ft", -9999.0);
|
||||
|
||||
fgSetDouble("/sim/presets/heading-deg", 9999.0);
|
||||
|
||||
if (!m_location) {
|
||||
return;
|
||||
|
@ -569,6 +569,7 @@ void LocationWidget::setLocationProperties()
|
|||
FGAirport* apt = static_cast<FGAirport*>(m_location.ptr());
|
||||
fgSetString("/sim/presets/airport-id", apt->ident());
|
||||
fgSetBool("/sim/presets/on-ground", true);
|
||||
fgSetBool("/sim/presets/airport-requested", true);
|
||||
|
||||
if (m_ui->runwayRadio->isChecked()) {
|
||||
if (apt->type() == FGPositioned::AIRPORT) {
|
||||
|
|
|
@ -105,15 +105,24 @@ void AddOnsPage::onAddSceneryPath()
|
|||
// validation
|
||||
|
||||
SGPath p(path.toStdString());
|
||||
SGPath objectsPath = p / "Objects";
|
||||
SGPath terrainPath = p / "Terrain";
|
||||
bool isValid = false;
|
||||
|
||||
if (!objectsPath.exists() && !terrainPath.exists()) {
|
||||
for (const auto& dir: {"Objects", "Terrain", "Buildings", "Roads",
|
||||
"Pylons", "NavData"}) {
|
||||
if ((p / dir).exists()) {
|
||||
isValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
QMessageBox mb;
|
||||
mb.setText(QString("The folder '%1' doesn't appear to contain scenery - add anyway?").arg(path));
|
||||
mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
mb.setDefaultButton(QMessageBox::No);
|
||||
mb.setInformativeText("Added scenery should contain folders called 'Objects' and / or 'Terrain'");
|
||||
mb.setInformativeText(
|
||||
"Added scenery should contain at least one of the following "
|
||||
"folders: Objects, Terrain, Buildings, Roads, Pylons, NavData.");
|
||||
mb.exec();
|
||||
|
||||
if (mb.result() == QMessageBox::No) {
|
||||
|
@ -124,11 +133,6 @@ void AddOnsPage::onAddSceneryPath()
|
|||
m_ui->sceneryPathsList->addItem(path);
|
||||
saveSceneryPaths();
|
||||
}
|
||||
|
||||
// work around a Qt OS-X bug - this dialog is ending ordered
|
||||
// behind the main settings dialog (consequence of modal-dialog
|
||||
// showing a modla dialog showing a modial dialog)
|
||||
window()->raise();
|
||||
}
|
||||
|
||||
void AddOnsPage::onRemoveSceneryPath()
|
||||
|
@ -175,11 +179,8 @@ void AddOnsPage::onAddAircraftPath()
|
|||
}
|
||||
|
||||
saveAircraftPaths();
|
||||
emit aircraftPathsChanged();
|
||||
}
|
||||
// work around a Qt OS-X bug - this dialog is ending ordered
|
||||
// behind the main settings dialog (consequence of modal-dialog
|
||||
// showing a modla dialog showing a modial dialog)
|
||||
window()->raise();
|
||||
}
|
||||
|
||||
void AddOnsPage::onRemoveAircraftPath()
|
||||
|
@ -187,6 +188,7 @@ void AddOnsPage::onRemoveAircraftPath()
|
|||
if (m_ui->aircraftPathsList->currentItem()) {
|
||||
delete m_ui->aircraftPathsList->currentItem();
|
||||
saveAircraftPaths();
|
||||
emit aircraftPathsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,13 +239,13 @@ void AddOnsPage::onAddCatalog()
|
|||
|
||||
void AddOnsPage::onAddDefaultCatalog()
|
||||
{
|
||||
addDefaultCatalog(this);
|
||||
addDefaultCatalog(this, false /* not silent */);
|
||||
|
||||
m_catalogsModel->refresh();
|
||||
updateUi();
|
||||
}
|
||||
|
||||
void AddOnsPage::addDefaultCatalog(QWidget* pr)
|
||||
void AddOnsPage::addDefaultCatalog(QWidget* pr, bool silent)
|
||||
{
|
||||
// check it's not a duplicate somehow
|
||||
FGHTTPClient* http = globals->get_subsystem<FGHTTPClient>();
|
||||
|
@ -252,6 +254,9 @@ void AddOnsPage::addDefaultCatalog(QWidget* pr)
|
|||
|
||||
QScopedPointer<AddCatalogDialog> dlg(new AddCatalogDialog(pr, globals->packageRoot()));
|
||||
QUrl url(QString::fromStdString(http->getDefaultCatalogUrl()));
|
||||
if (silent) {
|
||||
dlg->setNonInteractiveMode();
|
||||
}
|
||||
dlg->setUrlAndDownload(url);
|
||||
dlg->exec();
|
||||
|
||||
|
|
|
@ -20,11 +20,12 @@ public:
|
|||
explicit AddOnsPage(QWidget *parent, simgear::pkg::RootRef root);
|
||||
~AddOnsPage();
|
||||
|
||||
static void addDefaultCatalog(QWidget* pr);
|
||||
static void addDefaultCatalog(QWidget* pr, bool silent);
|
||||
|
||||
signals:
|
||||
void downloadDirChanged();
|
||||
void sceneryPathsChanged();
|
||||
void aircraftPathsChanged();
|
||||
|
||||
private slots:
|
||||
void onAddSceneryPath();
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
#include "AircraftModel.hxx"
|
||||
#include "PathsDialog.hxx"
|
||||
#include "EditCustomMPServerDialog.hxx"
|
||||
#include "previewwindow.h"
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
@ -696,6 +697,20 @@ bool runLauncherDialog()
|
|||
// try to initialise various Cocoa structures.
|
||||
flightgear::WindowBuilder::setPoseAsStandaloneApp(false);
|
||||
|
||||
if (!settings.contains("initial-default-hangar-added")) {
|
||||
settings.setValue("initial-default-hangar-added", true);
|
||||
|
||||
// ensure subsystems get updated while the dialog is running; we don't
|
||||
// yet have the QtLauncher window's pump installed
|
||||
QTimer subsystemPump;
|
||||
subsystemPump.setInterval(0);
|
||||
QObject::connect(&subsystemPump, &QTimer::timeout, [](){ globals->get_subsystem_mgr()->update(0.0); });
|
||||
subsystemPump.start();
|
||||
|
||||
// will only add if needed
|
||||
AddOnsPage::addDefaultCatalog(nullptr, true /* silent */);
|
||||
}
|
||||
|
||||
QtLauncher dlg;
|
||||
dlg.show();
|
||||
|
||||
|
@ -840,6 +855,8 @@ QtLauncher::QtLauncher() :
|
|||
this, &QtLauncher::onRequestPackageUninstall);
|
||||
connect(delegate, &AircraftItemDelegate::cancelDownload,
|
||||
this, &QtLauncher::onCancelDownload);
|
||||
connect(delegate, &AircraftItemDelegate::showPreviews,
|
||||
this, &QtLauncher::onShowPreviews);
|
||||
|
||||
connect(m_aircraftModel, &AircraftItemModel::aircraftInstallCompleted,
|
||||
this, &QtLauncher::onAircraftInstalledCompleted);
|
||||
|
@ -856,6 +873,8 @@ QtLauncher::QtLauncher() :
|
|||
this, &QtLauncher::onDownloadDirChanged);
|
||||
connect(addOnsPage, &AddOnsPage::sceneryPathsChanged,
|
||||
this, &QtLauncher::setSceneryPaths);
|
||||
connect(addOnsPage, &AddOnsPage::aircraftPathsChanged,
|
||||
this, &QtLauncher::onAircraftPathsChanged);
|
||||
|
||||
m_ui->tabWidget->addTab(addOnsPage, tr("Add-ons"));
|
||||
// after any kind of reset, try to restore selection and scroll
|
||||
|
@ -1202,6 +1221,11 @@ void QtLauncher::onRun()
|
|||
if (a.arg.startsWith("prop:")) {
|
||||
QString v = a.arg.mid(5) + "=" + a.value;
|
||||
opt->addOption("prop", v.toStdString());
|
||||
} else if (a.arg == "console") {
|
||||
// this option is handled very early, in normal startup. If the user
|
||||
// requests it via the launcher, parseOptions never sees it, so
|
||||
// achieve the same result manually.
|
||||
simgear::requestConsole();
|
||||
} else {
|
||||
opt->addOption(a.arg.toStdString(), a.value.toStdString());
|
||||
}
|
||||
|
@ -1385,6 +1409,14 @@ void QtLauncher::onRequestPackageUninstall(const QModelIndex& index)
|
|||
}
|
||||
}
|
||||
|
||||
void QtLauncher::onShowPreviews(const QModelIndex &index)
|
||||
{
|
||||
QVariant urls = index.data(AircraftPreviewsRole);
|
||||
|
||||
PreviewWindow* previewWindow = new PreviewWindow;
|
||||
previewWindow->setUrls(urls.toList());
|
||||
}
|
||||
|
||||
void QtLauncher::onCancelDownload(const QModelIndex& index)
|
||||
{
|
||||
QString pkg = index.data(AircraftPackageIdRole).toString();
|
||||
|
@ -1621,8 +1653,9 @@ void QtLauncher::onDownloadDirChanged()
|
|||
|
||||
globals->get_subsystem<FGHTTPClient>()->init();
|
||||
|
||||
QSettings settings;
|
||||
// re-scan the aircraft list
|
||||
QSettings settings;
|
||||
|
||||
m_aircraftModel->setPackageRoot(globals->packageRoot());
|
||||
m_aircraftModel->setPaths(settings.value("aircraft-paths").toStringList());
|
||||
m_aircraftModel->scanDirs();
|
||||
|
@ -1633,6 +1666,13 @@ void QtLauncher::onDownloadDirChanged()
|
|||
setSceneryPaths();
|
||||
}
|
||||
|
||||
void QtLauncher::onAircraftPathsChanged()
|
||||
{
|
||||
QSettings settings;
|
||||
m_aircraftModel->setPaths(settings.value("aircraft-paths").toStringList());
|
||||
m_aircraftModel->scanDirs();
|
||||
}
|
||||
|
||||
bool QtLauncher::shouldShowOfficialCatalogMessage() const
|
||||
{
|
||||
QSettings settings;
|
||||
|
@ -1663,7 +1703,7 @@ void QtLauncher::onOfficialCatalogMessageLink(QUrl link)
|
|||
QSettings settings;
|
||||
settings.setValue("hide-official-catalog-message", true);
|
||||
} else if (s == "action:add-official") {
|
||||
AddOnsPage::addDefaultCatalog(this);
|
||||
AddOnsPage::addDefaultCatalog(this, false /* not silent */);
|
||||
}
|
||||
|
||||
checkOfficialCatalogMessage();
|
||||
|
|
|
@ -75,7 +75,7 @@ private slots:
|
|||
void onAircraftSelected(const QModelIndex& index);
|
||||
void onRequestPackageInstall(const QModelIndex& index);
|
||||
void onRequestPackageUninstall(const QModelIndex& index);
|
||||
|
||||
void onShowPreviews(const QModelIndex& index);
|
||||
void onCancelDownload(const QModelIndex& index);
|
||||
|
||||
void onPopupAircraftHistory();
|
||||
|
@ -109,6 +109,7 @@ private slots:
|
|||
|
||||
void onPackagesNeedUpdate(bool yes);
|
||||
|
||||
void onAircraftPathsChanged();
|
||||
private:
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,13 +17,13 @@ FGMenuBar::~FGMenuBar ()
|
|||
{
|
||||
}
|
||||
|
||||
const char*
|
||||
std::string
|
||||
FGMenuBar::getLocalizedLabel(SGPropertyNode* node)
|
||||
{
|
||||
const char* name = node->getStringValue("name", 0);
|
||||
|
||||
const char* translated = globals->get_locale()->getLocalizedString(name, "menu");
|
||||
if (translated)
|
||||
std::string translated = globals->get_locale()->getLocalizedString(name, "menu");
|
||||
if (!translated.empty())
|
||||
return translated;
|
||||
|
||||
// return default with fallback to name
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#ifndef __MENUBAR_HXX
|
||||
#define __MENUBAR_HXX 1
|
||||
|
||||
#include <string>
|
||||
|
||||
class SGPropertyNode;
|
||||
|
||||
/**
|
||||
|
@ -51,7 +53,7 @@ public:
|
|||
* Take care of mapping it to the appropriate translation, if available.
|
||||
* Returns an UTF-8 encoded string.
|
||||
*/
|
||||
static const char* getLocalizedLabel(SGPropertyNode* node);
|
||||
static std::string getLocalizedLabel(SGPropertyNode* node);
|
||||
|
||||
};
|
||||
|
||||
|
|
BIN
src/GUI/preview-close.png
Normal file
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…
Reference in a new issue