Merge branch 'next' of D:\Git_New\flightgear into next
This commit is contained in:
commit
87082859d8
85 changed files with 1977 additions and 1688 deletions
|
@ -224,6 +224,8 @@ include_directories(${PROJECT_BINARY_DIR}/src/Include)
|
|||
|
||||
add_definitions(-DHAVE_CONFIG_H)
|
||||
|
||||
check_function_exists(mkfifo HAVE_MKFIFO)
|
||||
|
||||
# configure a header file to pass some of the CMake settings
|
||||
# to the source code
|
||||
configure_file (
|
||||
|
|
|
@ -569,14 +569,6 @@
|
|||
RelativePath="..\..\..\src\ATCDCL\atis.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\ATCDCL\commlist.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\ATCDCL\commlist.hxx"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Lib_Autopilot"
|
||||
|
@ -2449,14 +2441,6 @@
|
|||
RelativePath="..\..\..\src\FDM\fdm_shell.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\FDM\TankProperties.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\FDM\TankProperties.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\FDM\flight.cxx"
|
||||
>
|
||||
|
@ -2489,6 +2473,14 @@
|
|||
RelativePath="..\..\..\src\FDM\NullFDM.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\FDM\TankProperties.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\FDM\TankProperties.hxx"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Lib_GUI"
|
||||
|
@ -2893,6 +2885,14 @@
|
|||
RelativePath="..\..\..\src\Navaids\positioned.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Navaids\PositionedBinding.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Navaids\PositionedBinding.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Navaids\procedure.cxx"
|
||||
>
|
||||
|
@ -3033,14 +3033,6 @@
|
|||
RelativePath="..\..\..\src\Network\jsclient.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Network\multiplay.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Network\multiplay.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Network\native.cxx"
|
||||
>
|
||||
|
@ -3228,7 +3220,7 @@
|
|||
<File
|
||||
RelativePath="..\..\..\src\Sound\voice.hxx"
|
||||
>
|
||||
</File>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Sound\voiceplayer.cxx"
|
||||
>
|
||||
|
@ -3389,6 +3381,14 @@
|
|||
RelativePath="..\..\..\src\Environment\fgwind.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\gravity.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\gravity.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\metarairportfilter.cxx"
|
||||
>
|
||||
|
@ -3413,6 +3413,14 @@
|
|||
RelativePath="..\..\..\src\Environment\precipitation_mgr.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\presets.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\presets.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\realwx_ctrl.cxx"
|
||||
>
|
||||
|
@ -3437,14 +3445,6 @@
|
|||
RelativePath="..\..\..\src\Environment\terrainsampler.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\presets.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\presets.hxx"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Lib_Model"
|
||||
|
@ -3769,6 +3769,14 @@
|
|||
RelativePath="..\..\..\src\Instrumentation\tacan.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Instrumentation\tcas.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Instrumentation\tcas.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Instrumentation\transponder.cxx"
|
||||
>
|
||||
|
@ -3800,14 +3808,6 @@
|
|||
<File
|
||||
RelativePath="..\..\..\src\Instrumentation\wxradar.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Instrumentation\tcas.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Instrumentation\tcas.hxx"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="Lib_HUD"
|
||||
|
@ -4310,11 +4310,11 @@
|
|||
Name="Lib_ATC"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\..\src\ATC\atis_mgr.cxx"
|
||||
RelativePath="..\..\..\src\ATC\CommStation.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\ATC\atis_mgr.hxx"
|
||||
RelativePath="..\..\..\src\ATC\CommStation.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
include(FlightGearComponent)
|
||||
|
||||
set(SOURCES
|
||||
atis_mgr.cxx
|
||||
trafficcontrol.cxx
|
||||
CommStation.cxx
|
||||
)
|
||||
|
||||
flightgear_component(ATC "${SOURCES}")
|
||||
|
|
67
src/ATC/CommStation.cxx
Normal file
67
src/ATC/CommStation.cxx
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "CommStation.hxx"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <Navaids/PositionedBinding.hxx>
|
||||
|
||||
namespace {
|
||||
|
||||
typedef std::multimap<int, flightgear::CommStation*> FrequencyMap;
|
||||
static FrequencyMap static_frequencies;
|
||||
|
||||
typedef std::pair<FrequencyMap::const_iterator, FrequencyMap::const_iterator> FrequencyMapRange;
|
||||
|
||||
} // of anonymous namespace
|
||||
|
||||
namespace flightgear {
|
||||
|
||||
CommStation::CommStation(const std::string& name, FGPositioned::Type t, const SGGeod& pos, int range, int freq) :
|
||||
FGPositioned(t, name, pos),
|
||||
mRangeNM(range),
|
||||
mFreqKhz(freq),
|
||||
mAirport(NULL)
|
||||
{
|
||||
static_frequencies.insert(std::make_pair(freq, this));
|
||||
|
||||
init(true);
|
||||
}
|
||||
|
||||
void CommStation::setAirport(FGAirport* apt)
|
||||
{
|
||||
mAirport = apt;
|
||||
}
|
||||
|
||||
double CommStation::freqMHz() const
|
||||
{
|
||||
return mFreqKhz / 100.0;
|
||||
}
|
||||
|
||||
PositionedBinding*
|
||||
CommStation::createBinding(SGPropertyNode* nd) const
|
||||
{
|
||||
return new CommStationBinding(this, nd);
|
||||
}
|
||||
|
||||
CommStation*
|
||||
CommStation::findByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt)
|
||||
{
|
||||
FrequencyMapRange range = static_frequencies.equal_range(freqKhz);
|
||||
FGPositioned::List results;
|
||||
for (; range.first != range.second; ++range.first) {
|
||||
CommStation* sta = range.first->second;
|
||||
if (filt && !filt->pass(sta)) {
|
||||
continue; // filtered out
|
||||
}
|
||||
|
||||
results.push_back(sta);
|
||||
}
|
||||
|
||||
if (results.empty()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FGPositioned::sortByRange(results, pos);
|
||||
return (CommStation*) results.front().ptr();
|
||||
}
|
||||
|
||||
} // of namespace flightgear
|
39
src/ATC/CommStation.hxx
Normal file
39
src/ATC/CommStation.hxx
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef FG_ATC_COMM_STATION_HXX
|
||||
#define FG_ATC_COMM_STATION_HXX
|
||||
|
||||
#include <Navaids/positioned.hxx>
|
||||
|
||||
class FGAirport;
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
|
||||
class CommStation : public FGPositioned
|
||||
{
|
||||
public:
|
||||
CommStation(const std::string& name, FGPositioned::Type t, const SGGeod& pos, int range, int freq);
|
||||
|
||||
void setAirport(FGAirport* apt);
|
||||
FGAirport* airport() const { return mAirport; }
|
||||
|
||||
virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const;
|
||||
|
||||
int rangeNm() const
|
||||
{ return mRangeNM; }
|
||||
|
||||
int freqKHz() const
|
||||
{ return mFreqKhz; }
|
||||
|
||||
double freqMHz() const;
|
||||
|
||||
static CommStation* findByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt = NULL);
|
||||
private:
|
||||
int mRangeNM;
|
||||
int mFreqKhz;
|
||||
FGAirport* mAirport;
|
||||
};
|
||||
|
||||
} // of namespace flightgear
|
||||
|
||||
#endif // of FG_ATC_COMM_STATION_HXX
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
noinst_LIBRARIES = libATC.a
|
||||
|
||||
libATC_a_SOURCES = \
|
||||
atis_mgr.cxx atis_mgr.hxx \
|
||||
CommStation.cxx CommStation.hxx \
|
||||
trafficcontrol.cxx trafficcontrol.hxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/******************************************************************************
|
||||
* atis.cxx
|
||||
* Written by Durk Talsma, started August 1, 2010.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include "atis_mgr.hxx"
|
||||
|
||||
FGAtisManager::FGAtisManager() {
|
||||
|
||||
}
|
||||
|
||||
FGAtisManager::~FGAtisManager() {
|
||||
|
||||
}
|
||||
|
||||
void FGAtisManager::init() {
|
||||
SGSubsystem::init();
|
||||
}
|
||||
|
||||
void FGAtisManager::update ( double time ) {
|
||||
//cerr << "ATIS code is running at time: " << time << endl;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/* -*- Mode: C++ -*- *****************************************************
|
||||
* atic.hxx
|
||||
* Written by Durk Talsma. Started August 1, 2010; based on earlier work
|
||||
* by David C. Luff
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef _ATIS_HXX_
|
||||
#define _ATIS_HXX_
|
||||
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
class FGAtisManager : public SGSubsystem
|
||||
{
|
||||
private:
|
||||
|
||||
public:
|
||||
FGAtisManager();
|
||||
~FGAtisManager();
|
||||
void init();
|
||||
void update(double time);
|
||||
};
|
||||
|
||||
#endif // _ATIS_HXX_
|
|
@ -494,7 +494,7 @@ void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId,
|
|||
getName() + "-Ground";
|
||||
atisInformation =
|
||||
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
|
||||
getDynamics()->getAtisInformation();
|
||||
getDynamics()->getAtisSequence();
|
||||
break;
|
||||
case 4:
|
||||
receiver =
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
|
||||
#include <ATC/CommStation.hxx>
|
||||
#include <Airports/simple.hxx>
|
||||
|
||||
FGATC::FGATC() :
|
||||
_playing(false),
|
||||
|
@ -181,14 +181,20 @@ void FGATC::NotifyTransmissionFinished(const string& rid) {
|
|||
}
|
||||
}
|
||||
|
||||
void FGATC::SetData(ATCData* d) {
|
||||
_type = d->type;
|
||||
_geod = d->geod;
|
||||
_cart = d->cart;
|
||||
range = d->range;
|
||||
ident = d->ident;
|
||||
name = d->name;
|
||||
freq = d->freq;
|
||||
void FGATC::SetStation(flightgear::CommStation* sta) {
|
||||
switch (sta->type()) {
|
||||
case FGPositioned::FREQ_ATIS: _type = ATIS; break;
|
||||
case FGPositioned::FREQ_AWOS: _type = AWOS; break;
|
||||
default:
|
||||
throw sg_exception("unsupported comm station type");
|
||||
}
|
||||
|
||||
_geod = sta->geod();
|
||||
_cart = sta->cart();
|
||||
range = sta->rangeNm();
|
||||
ident = sta->airport()->ident();
|
||||
name = sta->airport()->name();
|
||||
freq = sta->freqKHz();
|
||||
}
|
||||
|
||||
// Render a transmission
|
||||
|
|
|
@ -37,6 +37,11 @@
|
|||
|
||||
class SGSampleGroup;
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
class CommStation;
|
||||
}
|
||||
|
||||
// Convert a frequency in MHz to tens of kHz
|
||||
// so we can use it e.g. as an index into commlist_freq
|
||||
//
|
||||
|
@ -140,7 +145,7 @@ public:
|
|||
inline atc_type GetType() { return _type; }
|
||||
|
||||
// Set the core ATC data
|
||||
void SetData(ATCData* d);
|
||||
void SetStation(flightgear::CommStation* sta);
|
||||
|
||||
inline int get_freq() const { return freq; }
|
||||
inline void set_freq(const int fq) {freq = fq;}
|
||||
|
|
|
@ -34,9 +34,9 @@
|
|||
#include "ATCDialog.hxx"
|
||||
#include "ATC.hxx"
|
||||
#include "ATCmgr.hxx"
|
||||
#include "commlist.hxx"
|
||||
#include "ATCutils.hxx"
|
||||
#include <Airports/simple.hxx>
|
||||
#include <ATC/CommStation.hxx>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
@ -286,21 +286,17 @@ void FGATCDialog::PopupCallback(int num) {
|
|||
}
|
||||
}
|
||||
|
||||
// map() key data type (removes duplicates and sorts by distance)
|
||||
struct atcdata {
|
||||
atcdata() {}
|
||||
atcdata(const string i, const string n, const double d) {
|
||||
id = i, name = n, distance = d;
|
||||
}
|
||||
bool operator<(const atcdata& a) const {
|
||||
return id != a.id && distance < a.distance;
|
||||
}
|
||||
bool operator==(const atcdata& a) const {
|
||||
return id == a.id && distance == a.distance;
|
||||
}
|
||||
string id;
|
||||
string name;
|
||||
double distance;
|
||||
class AirportsWithATC : public FGAirport::AirportFilter
|
||||
{
|
||||
public:
|
||||
virtual FGPositioned::Type maxType() const {
|
||||
return FGPositioned::SEAPORT;
|
||||
}
|
||||
|
||||
virtual bool passAirport(FGAirport* aApt) const
|
||||
{
|
||||
return (!aApt->commStations().empty());
|
||||
}
|
||||
};
|
||||
|
||||
void FGATCDialog::FreqDialog() {
|
||||
|
@ -315,38 +311,25 @@ void FGATCDialog::FreqDialog() {
|
|||
// remove all dynamic airport/ATC buttons
|
||||
button_group->removeChildren("button", false);
|
||||
|
||||
// Find the ATC stations within a reasonable range
|
||||
comm_list_type atc_stations;
|
||||
comm_list_iterator atc_stat_itr;
|
||||
|
||||
SGGeod geod(SGGeod::fromDegFt(fgGetDouble("/position/longitude-deg"),
|
||||
fgGetDouble("/position/latitude-deg"), fgGetDouble("/position/altitude-ft")));
|
||||
SGVec3d aircraft = SGVec3d::fromGeod(geod);
|
||||
|
||||
// search stations in range
|
||||
int num_stat = current_commlist->FindByPos(geod, 50.0, &atc_stations);
|
||||
if (num_stat != 0) {
|
||||
map<atcdata, bool> uniq;
|
||||
// fill map (sorts by distance and removes duplicates)
|
||||
comm_list_iterator itr = atc_stations.begin();
|
||||
for (; itr != atc_stations.end(); ++itr) {
|
||||
double distance = distSqr(aircraft, itr->cart);
|
||||
uniq[atcdata(itr->ident, itr->name, distance)] = true;
|
||||
}
|
||||
// create button per map entry (modified copy of <button-template>)
|
||||
map<atcdata, bool>::iterator uit = uniq.begin();
|
||||
for (int n = 0; uit != uniq.end() && n < 6; ++uit, ++n) { // max 6 buttons
|
||||
SGPropertyNode *entry = button_group->getNode("button", n, true);
|
||||
copyProperties(button_group->getNode("button-template", true), entry);
|
||||
entry->removeChildren("enabled", true);
|
||||
entry->setStringValue("legend", uit->first.id.c_str());
|
||||
entry->setStringValue("binding[0]/value", uit->first.id.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
AirportsWithATC filt;
|
||||
FGPositioned::List results = FGPositioned::findWithinRange(geod, 50.0, &filt);
|
||||
FGPositioned::sortByRange(results, geod);
|
||||
for (unsigned int r=0; (r<results.size()) && (r < 6); ++r) {
|
||||
|
||||
SGPropertyNode *entry = button_group->getNode("button", r, true);
|
||||
copyProperties(button_group->getNode("button-template", true), entry);
|
||||
entry->removeChildren("enabled", true);
|
||||
entry->setStringValue("legend", results[r]->ident());
|
||||
entry->setStringValue("binding[0]/value", results[r]->ident());
|
||||
}
|
||||
|
||||
// (un)hide message saying no things in range
|
||||
SGPropertyNode_ptr range_error = getNamedNode(dlg, "no-atc-in-range");
|
||||
range_error->setBoolValue("enabled", !num_stat);
|
||||
range_error->setBoolValue("enabled", !results.empty());
|
||||
|
||||
_gui->showDialog(dialog_name);
|
||||
}
|
||||
|
@ -377,43 +360,33 @@ void FGATCDialog::FreqDisplay(string& ident) {
|
|||
label = ident + " Frequencies";
|
||||
dlg->setStringValue("text/label", label.c_str());
|
||||
|
||||
int n = 0; // Number of ATC frequencies at this airport
|
||||
|
||||
comm_list_type stations;
|
||||
int found = current_commlist->FindByPos(a->geod(), 20.0, &stations);
|
||||
if(found) {
|
||||
comm_list_iterator itr = stations.begin();
|
||||
for (n = 0; itr != stations.end(); ++itr) {
|
||||
if(itr->ident != ident)
|
||||
continue;
|
||||
|
||||
if(itr->type == INVALID)
|
||||
continue;
|
||||
|
||||
// add frequency line (modified copy of <group-template>)
|
||||
SGPropertyNode *entry = freq_group->getNode("group", n, true);
|
||||
copyProperties(freq_group->getNode("group-template", true), entry);
|
||||
entry->removeChildren("enabled", true);
|
||||
|
||||
ostringstream ostr;
|
||||
ostr << itr->type;
|
||||
entry->setStringValue("text[0]/label", ostr.str());
|
||||
|
||||
char buf[8];
|
||||
snprintf(buf, 8, "%.2f", (itr->freq / 100.0)); // Convert from KHz to MHz
|
||||
if(buf[5] == '3') buf[5] = '2';
|
||||
if(buf[5] == '8') buf[5] = '7';
|
||||
buf[7] = '\0';
|
||||
|
||||
entry->setStringValue("text[1]/label", buf);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if(n == 0) {
|
||||
label = "No frequencies found for airport " + ident;
|
||||
const flightgear::CommStationList& comms(a->commStations());
|
||||
if (comms.empty()) {
|
||||
label = "No frequencies found for airport " + ident;
|
||||
mkDialog(label.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
for (unsigned int c=0; c < comms.size(); ++c) {
|
||||
flightgear::CommStation* comm = comms[c];
|
||||
|
||||
// add frequency line (modified copy of <group-template>)
|
||||
SGPropertyNode *entry = freq_group->getNode("group", n, true);
|
||||
copyProperties(freq_group->getNode("group-template", true), entry);
|
||||
entry->removeChildren("enabled", true);
|
||||
|
||||
entry->setStringValue("text[0]/label", comm->ident());
|
||||
|
||||
char buf[8];
|
||||
snprintf(buf, 8, "%.2f", comm->freqMHz());
|
||||
if(buf[5] == '3') buf[5] = '2';
|
||||
if(buf[5] == '8') buf[5] = '7';
|
||||
buf[7] = '\0';
|
||||
|
||||
entry->setStringValue("text[1]/label", buf);
|
||||
++n;
|
||||
}
|
||||
|
||||
_gui->showDialog(dialog_name);
|
||||
}
|
||||
|
|
|
@ -24,29 +24,18 @@
|
|||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
#include <Airports/simple.hxx>
|
||||
#include <ATC/CommStation.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#include "ATCmgr.hxx"
|
||||
#include "commlist.hxx"
|
||||
#include "ATCDialog.hxx"
|
||||
#include "ATCutils.hxx"
|
||||
#include "atis.hxx"
|
||||
|
||||
|
||||
/*
|
||||
// periodic radio station search wrapper
|
||||
static void fgATCSearch( void ) {
|
||||
globals->get_ATC_mgr()->Search();
|
||||
}
|
||||
*/ //This wouldn't compile - including Time/event.hxx breaks it :-(
|
||||
// Is this still true?? -EMH-
|
||||
|
||||
AirportATC::AirportATC() :
|
||||
atis_freq(0.0),
|
||||
atis_active(false)
|
||||
//airport_atc_map.clear();
|
||||
{
|
||||
}
|
||||
using flightgear::CommStation;
|
||||
|
||||
FGATCMgr::FGATCMgr() :
|
||||
initDone(false),
|
||||
|
@ -148,44 +137,6 @@ void FGATCMgr::update(double dt) {
|
|||
//cout << "Leaving update..." << endl;
|
||||
}
|
||||
|
||||
|
||||
// Returns frequency in KHz - should I alter this to return in MHz?
|
||||
unsigned short int FGATCMgr::GetFrequency(const string& ident, const atc_type& tp) {
|
||||
ATCData test;
|
||||
bool ok = current_commlist->FindByCode(ident, test, tp);
|
||||
return(ok ? test.freq : 0);
|
||||
}
|
||||
|
||||
// Register the fact that the comm radio is tuned to an airport
|
||||
// Channel is zero based
|
||||
bool FGATCMgr::CommRegisterAirport(const string& ident, int chan, const atc_type& tp) {
|
||||
SG_LOG(SG_ATC, SG_BULK, "Comm channel " << chan << " registered airport " << ident);
|
||||
//cout << "Comm channel " << chan << " registered airport " << ident << ' ' << tp << '\n';
|
||||
if(airport_atc_map.find(ident) != airport_atc_map.end()) {
|
||||
if(tp == ATIS || tp == AWOS) {
|
||||
airport_atc_map[ident]->atis_active = true;
|
||||
}
|
||||
return(true);
|
||||
} else {
|
||||
//cout << "NOT IN MAP - creating new..." << endl;
|
||||
const FGAirport *ap = fgFindAirportID(ident);
|
||||
if (ap) {
|
||||
AirportATC *a = new AirportATC;
|
||||
// I'm not entirely sure that this AirportATC structure business is actually needed - it just duplicates what we can find out anyway!
|
||||
a->geod = ap->geod();
|
||||
a->atis_freq = GetFrequency(ident, ATIS)
|
||||
|| GetFrequency(ident, AWOS);
|
||||
a->atis_active = false;
|
||||
if(tp == ATIS || tp == AWOS) {
|
||||
a->atis_active = true;
|
||||
}
|
||||
airport_atc_map[ident] = a;
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
typedef map<string,int> MSI;
|
||||
|
||||
void FGATCMgr::ZapOtherService(const string ncunit, const string svc_name){
|
||||
|
@ -224,16 +175,6 @@ FGATC* FGATCMgr::FindInList(const string& id, const atc_type& tp) {
|
|||
return (*atc_list)[ndx];
|
||||
}
|
||||
|
||||
// Returns true if the airport is found in the map
|
||||
bool FGATCMgr::GetAirportATCDetails(const string& icao, AirportATC* a) {
|
||||
if(airport_atc_map.find(icao) != airport_atc_map.end()) {
|
||||
*a = *airport_atc_map[icao];
|
||||
return(true);
|
||||
} else {
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Return a pointer to an appropriate voice for a given type of ATC
|
||||
// creating the voice if necessary - ie. make sure exactly one copy
|
||||
// of every voice in use exists in memory.
|
||||
|
@ -303,49 +244,44 @@ void FGATCMgr::FreqSearch(const string navcomm, const int unit) {
|
|||
if (!comm_node) return; // no such radio unit
|
||||
|
||||
ATCData data;
|
||||
double freq = comm_node->getDoubleValue();
|
||||
// Note: 122.375 must be rounded DOWN to 12237
|
||||
// in order to be consistent with apt.dat et cetera.
|
||||
int freqKhz = static_cast<int>(comm_node->getDoubleValue() * 100.0 + 0.25);
|
||||
|
||||
_aircraftPos = SGGeod::fromDegFt(lon_node->getDoubleValue(),
|
||||
lat_node->getDoubleValue(), elev_node->getDoubleValue());
|
||||
|
||||
// Query the data store and get the closest match if any
|
||||
//cout << "Will FindByFreq: " << lat << " " << lon << " " << elev
|
||||
// << " freq: " << freq << endl;
|
||||
if(current_commlist->FindByFreq(_aircraftPos, freq, &data)) {
|
||||
//cout << "FoundByFreq: " << freq
|
||||
// << " ident: " << data.ident
|
||||
// << " type: " << data.type << " ***" << endl;
|
||||
// We are in range of something.
|
||||
CommStation* sta = CommStation::findByFreq(freqKhz, _aircraftPos);
|
||||
if (!sta) {
|
||||
ZapOtherService(ncunit, "x x x");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get rid of any *other* service that was on this radio unit:
|
||||
FGPositioned::Type ty = sta->type();
|
||||
string svc_name = sta->ident() + FGPositioned::nameForType(ty);
|
||||
ZapOtherService(ncunit, svc_name);
|
||||
// See if the service already exists, possibly connected to
|
||||
// some other radio unit:
|
||||
if (atc_list->count(svc_name)) {
|
||||
// make sure the service knows it's tuned on this radio:
|
||||
FGATC* svc = (*atc_list)[svc_name];
|
||||
svc->active_on[ncunit] = 1;
|
||||
svc->SetDisplay();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Get rid of any *other* service that was on this radio unit:
|
||||
string svc_name = data.ident+decimalNumeral(data.type);
|
||||
ZapOtherService(ncunit, svc_name);
|
||||
// See if the service already exists, possibly connected to
|
||||
// some other radio unit:
|
||||
if (atc_list->count(svc_name)) {
|
||||
// make sure the service knows it's tuned on this radio:
|
||||
FGATC* svc = (*atc_list)[svc_name];
|
||||
// This was a switch-case statement but the compiler didn't like
|
||||
// the new variable creation with it.
|
||||
if(ty == FGPositioned::FREQ_ATIS || ty == FGPositioned::FREQ_AWOS) {
|
||||
(*atc_list)[svc_name] = new FGATIS;
|
||||
FGATC* svc = (*atc_list)[svc_name];
|
||||
if(svc != NULL) {
|
||||
svc->SetStation(sta);
|
||||
svc->active_on[ncunit] = 1;
|
||||
svc->SetDisplay();
|
||||
return;
|
||||
svc->Init();
|
||||
}
|
||||
}
|
||||
|
||||
CommRegisterAirport(data.ident, unit, data.type);
|
||||
|
||||
// This was a switch-case statement but the compiler didn't like
|
||||
// the new variable creation with it.
|
||||
if(data.type == ATIS || data.type == AWOS) {
|
||||
(*atc_list)[svc_name] = new FGATIS;
|
||||
FGATC* svc = (*atc_list)[svc_name];
|
||||
if(svc != NULL) {
|
||||
svc->SetData(&data);
|
||||
svc->active_on[ncunit] = 1;
|
||||
svc->SetDisplay();
|
||||
svc->Init();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No services in range. Zap any service on this unit.
|
||||
ZapOtherService(ncunit, "x x x");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,31 +24,12 @@
|
|||
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <GUI/gui.h>
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "ATC.hxx"
|
||||
|
||||
using std::string;
|
||||
using std::list;
|
||||
using std::map;
|
||||
|
||||
// Structure for holding details of the ATC frequencies at a given airport, and whether they are in the active list or not.
|
||||
// These can then be cross referenced with the commlists which are stored by frequency or bucket.
|
||||
// Non-available services are denoted by a frequency of zero.
|
||||
// These structures are only intended to be created for in-use airports, and removed when no longer needed.
|
||||
struct AirportATC {
|
||||
AirportATC();
|
||||
|
||||
SGGeod geod;
|
||||
float atis_freq;
|
||||
bool atis_active;
|
||||
};
|
||||
|
||||
class FGATCMgr : public SGSubsystem
|
||||
{
|
||||
|
||||
|
@ -56,16 +37,8 @@ private:
|
|||
|
||||
bool initDone; // Hack - guard against update getting called before init
|
||||
|
||||
// A map of airport ID vs frequencies and ATC provision
|
||||
typedef map < string, AirportATC* > airport_atc_map_type;
|
||||
typedef airport_atc_map_type::iterator airport_atc_map_iterator;
|
||||
typedef airport_atc_map_type::const_iterator airport_atc_map_const_iterator;
|
||||
|
||||
airport_atc_map_type airport_atc_map;
|
||||
airport_atc_map_iterator airport_atc_map_itr;
|
||||
|
||||
// A list of pointers to all currently active ATC classes
|
||||
typedef map<string,FGATC*> atc_list_type;
|
||||
typedef std::map<std::string,FGATC*> atc_list_type;
|
||||
typedef atc_list_type::iterator atc_list_iterator;
|
||||
typedef atc_list_type::const_iterator atc_list_const_iterator;
|
||||
|
||||
|
@ -107,9 +80,7 @@ public:
|
|||
|
||||
void update(double dt);
|
||||
|
||||
// Returns true if the airport is found in the map
|
||||
bool GetAirportATCDetails(const string& icao, AirportATC* a);
|
||||
|
||||
|
||||
// Return a pointer to an appropriate voice for a given type of ATC
|
||||
// creating the voice if necessary - ie. make sure exactly one copy
|
||||
// of every voice in use exists in memory.
|
||||
|
@ -124,26 +95,20 @@ public:
|
|||
atc_type GetComm2ATCType() { return(INVALID); }
|
||||
FGATC* GetComm2ATCPointer() { return(0/* kludge */); }
|
||||
|
||||
// Get the frequency of a given service at a given airport
|
||||
// Returns zero if not found
|
||||
unsigned short int GetFrequency(const string& ident, const atc_type& tp);
|
||||
|
||||
// Register the fact that the comm radio is tuned to an airport
|
||||
bool CommRegisterAirport(const string& ident, int chan, const atc_type& tp);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Remove a class from the atc_list and delete it from memory
|
||||
// *if* no other comm channel or AI plane is using it.
|
||||
void ZapOtherService(const string ncunit, const string svc_name);
|
||||
void ZapOtherService(const std::string ncunit, const std::string svc_name);
|
||||
|
||||
// Return a pointer to a class in the list given ICAO code and type
|
||||
// Return NULL if the given service is not in the list
|
||||
// - *** THE CALLING FUNCTION MUST CHECK FOR THIS ***
|
||||
FGATC* FindInList(const string& id, const atc_type& tp);
|
||||
FGATC* FindInList(const std::string& id, const atc_type& tp);
|
||||
|
||||
// Search the specified radio for stations on the same frequency and in range.
|
||||
void FreqSearch(const string navcomm, const int unit);
|
||||
void FreqSearch(const std::string navcomm, const int unit);
|
||||
};
|
||||
|
||||
#endif // _FG_ATCMGR_HXX
|
||||
|
|
|
@ -3,7 +3,6 @@ include(FlightGearComponent)
|
|||
set(SOURCES
|
||||
ATC.cxx
|
||||
atis.cxx
|
||||
commlist.cxx
|
||||
ATCDialog.cxx
|
||||
ATCVoice.cxx
|
||||
ATCmgr.cxx
|
||||
|
|
|
@ -3,7 +3,6 @@ noinst_LIBRARIES = libATCDCL.a
|
|||
libATCDCL_a_SOURCES = \
|
||||
ATC.hxx ATC.cxx \
|
||||
atis.hxx atis.cxx \
|
||||
commlist.hxx commlist.cxx \
|
||||
ATCDialog.hxx ATCDialog.cxx \
|
||||
ATCVoice.hxx ATCVoice.cxx \
|
||||
ATCmgr.hxx ATCmgr.cxx \
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "atis_lexicon.hxx"
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/math/sg_random.h>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include <stdlib.h> // atoi()
|
||||
#include <stdio.h> // sprintf
|
||||
|
@ -44,9 +46,6 @@
|
|||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include <Environment/environment_mgr.hxx>
|
||||
#include <Environment/environment.hxx>
|
||||
#include <Environment/atmosphere.hxx>
|
||||
|
@ -54,9 +53,9 @@
|
|||
#include <Main/fg_props.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
#include <Airports/runways.hxx>
|
||||
#include <Airports/dynamics.hxx>
|
||||
|
||||
|
||||
#include "commlist.hxx"
|
||||
#include "ATCutils.hxx"
|
||||
#include "ATCmgr.hxx"
|
||||
|
||||
|
@ -241,12 +240,12 @@ int FGATIS::GenTransmission(const int regen, const int special) {
|
|||
string BRK = ".\n";
|
||||
string PAUSE = " / ";
|
||||
|
||||
double tstamp = atof(fgGetString("sim/time/elapsed-sec"));
|
||||
int interval = _type == ATIS ?
|
||||
ATIS_interval // ATIS updated hourly
|
||||
: 2*minute; // AWOS updated more frequently
|
||||
int sequence = current_commlist->GetAtisSequence(ident,
|
||||
tstamp, interval, special);
|
||||
|
||||
FGAirport* apt = FGAirport::findByIdent(ident);
|
||||
int sequence = apt->getDynamics()->updateAtisSequence(interval, special);
|
||||
if (!regen && sequence > LTRS) {
|
||||
//xx if (msg_OK) cout << "ATIS: no change: " << sequence << endl;
|
||||
//xx msg_time = cur_time;
|
||||
|
|
|
@ -95,6 +95,7 @@ class FGATIS : public FGATC {
|
|||
void TreeOut(int msgOK);
|
||||
|
||||
friend std::istream& operator>> ( std::istream&, FGATIS& );
|
||||
|
||||
};
|
||||
|
||||
typedef int (FGATIS::*int_getter)() const;
|
||||
|
|
|
@ -1,302 +0,0 @@
|
|||
// commlist.cxx -- comm frequency lookup class
|
||||
//
|
||||
// Written by David Luff and Alexander Kappes, started Jan 2003.
|
||||
// Based on navlist.cxx by Curtis Olson, started April 2000.
|
||||
//
|
||||
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "commlist.hxx"
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/math/sg_random.h>
|
||||
#include <simgear/bucket/newbucket.hxx>
|
||||
#include <Airports/simple.hxx>
|
||||
|
||||
#include "ATCutils.hxx"
|
||||
|
||||
|
||||
FGCommList *current_commlist;
|
||||
|
||||
|
||||
// Constructor
|
||||
FGCommList::FGCommList( void ) {
|
||||
sg_srandom_time();
|
||||
}
|
||||
|
||||
|
||||
// Destructor
|
||||
FGCommList::~FGCommList( void ) {
|
||||
}
|
||||
|
||||
|
||||
// load the navaids and build the map
|
||||
bool FGCommList::init( const SGPath& path ) {
|
||||
|
||||
SGPath temp = path;
|
||||
commlist_freq.erase(commlist_freq.begin(), commlist_freq.end());
|
||||
commlist_bck.erase(commlist_bck.begin(), commlist_bck.end());
|
||||
temp.append( "ATC/default.atis" );
|
||||
LoadComms(temp);
|
||||
temp = path;
|
||||
temp.append( "ATC/default.tower" );
|
||||
LoadComms(temp);
|
||||
temp = path;
|
||||
temp.append( "ATC/default.ground" );
|
||||
LoadComms(temp);
|
||||
temp = path;
|
||||
temp.append( "ATC/default.approach" );
|
||||
LoadComms(temp);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FGCommList::LoadComms(const SGPath& path) {
|
||||
|
||||
sg_gzifstream fin( path.str() );
|
||||
if ( !fin.is_open() ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// read in each line of the file
|
||||
fin >> skipcomment;
|
||||
|
||||
while ( !fin.eof() ) {
|
||||
ATCData a;
|
||||
fin >> a;
|
||||
if(a.type == INVALID) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "WARNING - INVALID type found in " << path.str() << '\n');
|
||||
} else {
|
||||
// Push all stations onto frequency map
|
||||
commlist_freq[a.freq].push_back(a);
|
||||
|
||||
// Push non-atis stations onto bucket map as well
|
||||
// In fact, push all stations onto bucket map for now so FGATCMgr::GetFrequency() works.
|
||||
//if(a.type != ATIS and/or AWOS?) {
|
||||
// get bucket number
|
||||
SGBucket bucket(a.geod);
|
||||
int bucknum = bucket.gen_index();
|
||||
commlist_bck[bucknum].push_back(a);
|
||||
//}
|
||||
}
|
||||
|
||||
fin >> skipcomment;
|
||||
}
|
||||
|
||||
fin.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// query the database for the specified frequency, lon and lat are in
|
||||
// degrees, elev is in meters
|
||||
// If no atc_type is specified, it returns true if any non-invalid type is found
|
||||
// If atc_type is specifed, returns true only if the specified type is found
|
||||
bool FGCommList::FindByFreq(const SGGeod& aPos, double freq,
|
||||
ATCData* ad, atc_type tp )
|
||||
{
|
||||
comm_list_type stations;
|
||||
stations = commlist_freq[kHz10(freq)];
|
||||
comm_list_iterator current = stations.begin();
|
||||
comm_list_iterator last = stations.end();
|
||||
|
||||
// double az1, az2, s;
|
||||
SGVec3d aircraft = SGVec3d::fromGeod(aPos);
|
||||
const double orig_max_d = 1e100;
|
||||
double max_d = orig_max_d;
|
||||
double d;
|
||||
// TODO - at the moment this loop returns the first match found in range
|
||||
// We want to return the closest match in the event of a frequency conflict
|
||||
for ( ; current != last ; ++current ) {
|
||||
d = distSqr(aircraft, current->cart);
|
||||
|
||||
//cout << " dist = " << sqrt(d)
|
||||
// << " range = " << current->range * SG_NM_TO_METER << endl;
|
||||
|
||||
// TODO - match up to twice the published range so we can model
|
||||
// reduced signal strength
|
||||
// NOTE The below is squared since we match to distance3Dsquared (above) to avoid a sqrt.
|
||||
if ( d < (current->range * SG_NM_TO_METER
|
||||
* current->range * SG_NM_TO_METER ) ) {
|
||||
//cout << "matched = " << current->ident << endl;
|
||||
if((tp == INVALID) || (tp == (*current).type)) {
|
||||
if(d < max_d) {
|
||||
max_d = d;
|
||||
*ad = *current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(max_d < orig_max_d) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int FGCommList::FindByPos(const SGGeod& aPos, double range, comm_list_type* stations, atc_type tp)
|
||||
{
|
||||
// number of relevant stations found within range
|
||||
int found = 0;
|
||||
stations->erase(stations->begin(), stations->end());
|
||||
|
||||
// get bucket number for plane position
|
||||
SGBucket buck(aPos);
|
||||
|
||||
// get neigboring buckets
|
||||
int bx = (int)( range*SG_NM_TO_METER / buck.get_width_m() / 2) + 1;
|
||||
int by = (int)( range*SG_NM_TO_METER / buck.get_height_m() / 2 ) + 1;
|
||||
|
||||
// loop over bucket range
|
||||
for ( int i=-bx; i<=bx; i++) {
|
||||
for ( int j=-by; j<=by; j++) {
|
||||
buck = sgBucketOffset(aPos.getLongitudeDeg(), aPos.getLatitudeDeg(), i, j);
|
||||
long int bucket = buck.gen_index();
|
||||
comm_map_const_iterator Fstations = commlist_bck.find(bucket);
|
||||
if (Fstations == commlist_bck.end()) continue;
|
||||
comm_list_const_iterator current = Fstations->second.begin();
|
||||
comm_list_const_iterator last = Fstations->second.end();
|
||||
|
||||
|
||||
// double az1, az2, s;
|
||||
SGVec3d aircraft = SGVec3d::fromGeod(aPos);
|
||||
double d;
|
||||
for(; current != last; ++current) {
|
||||
if((current->type == tp) || (tp == INVALID)) {
|
||||
d = distSqr(aircraft, current->cart);
|
||||
// NOTE The below is squared since we match to distance3Dsquared (above) to avoid a sqrt.
|
||||
if ( d < (current->range * SG_NM_TO_METER
|
||||
* current->range * SG_NM_TO_METER ) ) {
|
||||
stations->push_back(*current);
|
||||
++found;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
// Returns the distance in meters to the closest station of a given type,
|
||||
// with the details written into ATCData& ad. If no type is specifed simply
|
||||
// returns the distance to the closest station of any type.
|
||||
// Returns -9999 if no stations found within max_range in nautical miles (default 100 miles).
|
||||
// Note that the search algorithm starts at 10 miles and multiplies by 10 thereafter, so if
|
||||
// say 300 miles is specifed 10, then 100, then 1000 will be searched, breaking at first result
|
||||
// and giving up after 1000.
|
||||
double FGCommList::FindClosest(const SGGeod& aPos, ATCData& ad, atc_type tp, double max_range) {
|
||||
int num_stations = 0;
|
||||
int range = 10;
|
||||
comm_list_type stations;
|
||||
comm_list_iterator itr;
|
||||
double distance = -9999.0;
|
||||
|
||||
while(num_stations == 0) {
|
||||
num_stations = FindByPos(aPos, range, &stations, tp);
|
||||
if(num_stations) {
|
||||
double closest = max_range * SG_NM_TO_METER;
|
||||
double tmp;
|
||||
for(itr = stations.begin(); itr != stations.end(); ++itr) {
|
||||
ATCData ad2 = *itr;
|
||||
const FGAirport *a = fgFindAirportID(ad2.ident);
|
||||
if (a) {
|
||||
tmp = dclGetHorizontalSeparation(ad2.geod, aPos);
|
||||
if(tmp <= closest) {
|
||||
closest = tmp;
|
||||
distance = tmp;
|
||||
ad = *itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
//cout << "Closest station is " << ad.ident << " at a range of " << distance << " meters\n";
|
||||
return(distance);
|
||||
}
|
||||
if(range > max_range) {
|
||||
break;
|
||||
}
|
||||
range *= 10;
|
||||
}
|
||||
return(-9999.0);
|
||||
}
|
||||
|
||||
|
||||
// Find by Airport code.
|
||||
// This is basically a wrapper for a call to the airport database to get the airport
|
||||
// position followed by a call to FindByPos(...)
|
||||
bool FGCommList::FindByCode( const string& ICAO, ATCData& ad, atc_type tp ) {
|
||||
const FGAirport *a = fgFindAirportID( ICAO);
|
||||
if ( a) {
|
||||
comm_list_type stations;
|
||||
int found = FindByPos(a->geod(), 10.0, &stations, tp);
|
||||
if(found) {
|
||||
comm_list_iterator itr = stations.begin();
|
||||
while(itr != stations.end()) {
|
||||
if(((*itr).ident == ICAO) && ((*itr).type == tp)) {
|
||||
ad = *itr;
|
||||
//cout << "FindByCode returns " << ICAO
|
||||
// << " type: " << tp
|
||||
// << " freq: " << itr->freq
|
||||
// << endl;
|
||||
return true;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO - this function should move somewhere else eventually!
|
||||
// Return an appropriate sequence number for an ATIS transmission.
|
||||
// Return sequence number + 2600 if sequence is unchanged since
|
||||
// last time.
|
||||
int FGCommList::GetAtisSequence( const string& apt_id,
|
||||
const double tstamp, const int interval, const int special)
|
||||
{
|
||||
atis_transmission_type tran;
|
||||
|
||||
if(atislog.find(apt_id) == atislog.end()) { // New station
|
||||
tran.tstamp = tstamp - interval;
|
||||
// Random number between 0 and 25 inclusive, i.e. 26 equiprobable outcomes:
|
||||
tran.sequence = int(sg_random() * LTRS);
|
||||
atislog[apt_id] = tran;
|
||||
//cout << "New ATIS station: " << apt_id << " seq-1: "
|
||||
// << tran.sequence << endl;
|
||||
}
|
||||
|
||||
// calculate the appropriate identifier and update the log
|
||||
tran = atislog[apt_id];
|
||||
|
||||
int delta = int((tstamp - tran.tstamp) / interval);
|
||||
tran.tstamp += delta * interval;
|
||||
if (special && !delta) delta++; // a "special" ATIS update is required
|
||||
tran.sequence = (tran.sequence + delta) % LTRS;
|
||||
atislog[apt_id] = tran;
|
||||
//if (delta) cout << "New ATIS sequence: " << tran.sequence
|
||||
// << " Delta: " << delta << endl;
|
||||
return(tran.sequence + (delta ? 0 : LTRS*1000));
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
// commlist.hxx -- comm frequency lookup class
|
||||
//
|
||||
// Written by David Luff and Alexander Kappes, started Jan 2003.
|
||||
// Based on navlist.hxx by Curtis Olson, started April 2000.
|
||||
//
|
||||
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
/*****************************************************************
|
||||
*
|
||||
* FGCommList is used to store communication frequency information
|
||||
* for the ATC and AI subsystems. Two maps are maintained - one
|
||||
* searchable by location and one searchable by frequency. The
|
||||
* data structure returned from the search is the ATCData struct
|
||||
* defined in ATC.hxx, containing location, frequency, name, range
|
||||
* and type of the returned station.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
#ifndef _FG_COMMLIST_HXX
|
||||
#define _FG_COMMLIST_HXX
|
||||
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "ATC.hxx"
|
||||
#include "atis.hxx"
|
||||
|
||||
class SGPath;
|
||||
|
||||
// A list of ATC stations
|
||||
typedef std::list < ATCData > comm_list_type;
|
||||
typedef comm_list_type::iterator comm_list_iterator;
|
||||
typedef comm_list_type::const_iterator comm_list_const_iterator;
|
||||
|
||||
// A map of ATC station lists
|
||||
typedef std::map < int, comm_list_type > comm_map_type;
|
||||
typedef comm_map_type::iterator comm_map_iterator;
|
||||
typedef comm_map_type::const_iterator comm_map_const_iterator;
|
||||
|
||||
|
||||
class FGCommList {
|
||||
|
||||
public:
|
||||
|
||||
FGCommList();
|
||||
~FGCommList();
|
||||
|
||||
// load all comm frequencies and build the map
|
||||
bool init( const SGPath& path );
|
||||
|
||||
// query the database for the specified frequency, lon and lat are
|
||||
// If no atc_type is specified, it returns true if any non-invalid type is found.
|
||||
// If atc_type is specifed, returns true only if the specified type is found.
|
||||
// Returns the station closest to the supplied position.
|
||||
// The data found is written into the passed-in ATCData structure.
|
||||
bool FindByFreq(const SGGeod& aPos, double freq, ATCData* ad, atc_type tp = INVALID );
|
||||
|
||||
// query the database by location, lon and lat are in degrees, elev is in meters, range is in nautical miles.
|
||||
// Returns the number of stations of the specified atc_type tp that are in range of the position defined by
|
||||
// lon, lat and elev, and pushes them into stations.
|
||||
// If no atc_type is specifed, returns the number of all stations in range, and pushes them into stations
|
||||
// ** stations is erased before use **
|
||||
int FindByPos(const SGGeod& aPos, double range, comm_list_type* stations, atc_type tp = INVALID );
|
||||
|
||||
// Returns the distance in meters to the closest station of a given type,
|
||||
// with the details written into ATCData& ad. If no type is specifed simply
|
||||
// returns the distance to the closest station of any type.
|
||||
// Returns -9999 if no stations found within max_range in nautical miles (default 100 miles).
|
||||
// Note that the search algorithm starts at 10 miles and multiplies by 10 thereafter, so if
|
||||
// say 300 miles is specifed 10, then 100, then 1000 will be searched, breaking at first result
|
||||
// and giving up after 1000.
|
||||
// !!!Be warned that searching anything over 100 miles will pause the sim unacceptably!!!
|
||||
// (The ability to search longer ranges should be used during init only).
|
||||
double FindClosest(const SGGeod& aPos, ATCData& ad, atc_type tp = INVALID, double max_range = 100.0 );
|
||||
|
||||
// Find by Airport code.
|
||||
bool FindByCode( const std::string& ICAO, ATCData& ad, atc_type tp = INVALID );
|
||||
|
||||
// Return the sequence letter for an ATIS transmission given transmission time and airport id
|
||||
// This maybe should get moved somewhere else!!
|
||||
int GetAtisSequence( const std::string& apt_id, const double tstamp,
|
||||
const int interval, const int flush=0);
|
||||
|
||||
// Comm stations mapped by frequency
|
||||
comm_map_type commlist_freq;
|
||||
|
||||
// Comm stations mapped by bucket
|
||||
comm_map_type commlist_bck;
|
||||
|
||||
// Load comms from a specified path (which must include the filename)
|
||||
private:
|
||||
|
||||
bool LoadComms(const SGPath& path);
|
||||
|
||||
//----------- This stuff is left over from atislist.[ch]xx and maybe should move somewhere else
|
||||
// Add structure and map for storing a log of atis transmissions
|
||||
// made in this session of FlightGear. This allows the callsign
|
||||
// to be allocated correctly wrt time.
|
||||
typedef struct {
|
||||
double tstamp;
|
||||
int sequence;
|
||||
} atis_transmission_type;
|
||||
|
||||
typedef std::map < std::string, atis_transmission_type > atis_log_type;
|
||||
typedef atis_log_type::iterator atis_log_iterator;
|
||||
typedef atis_log_type::const_iterator atis_log_const_iterator;
|
||||
|
||||
atis_log_type atislog;
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
||||
};
|
||||
|
||||
|
||||
extern FGCommList *current_commlist;
|
||||
|
||||
#endif // _FG_COMMLIST_HXX
|
||||
|
||||
|
|
@ -46,7 +46,8 @@
|
|||
#include "simple.hxx"
|
||||
#include "runways.hxx"
|
||||
#include "pavement.hxx"
|
||||
#include <ATCDCL/commlist.hxx>
|
||||
|
||||
#include <ATC/CommStation.hxx>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
@ -78,7 +79,7 @@ public:
|
|||
|
||||
|
||||
|
||||
void parseAPT(const string &aptdb_file, FGCommList *comm_list)
|
||||
void parseAPT(const string &aptdb_file)
|
||||
{
|
||||
sg_gzifstream in( aptdb_file );
|
||||
|
||||
|
@ -157,12 +158,8 @@ public:
|
|||
// custom startup locations (ignore)
|
||||
} else if ( line_id == 0 ) {
|
||||
// ??
|
||||
} else if ( line_id == 50 ) {
|
||||
|
||||
parseATISLine(comm_list, simgear::strutils::split(line));
|
||||
|
||||
} else if ( line_id >= 51 && line_id <= 56 ) {
|
||||
// other frequency entries (ignore)
|
||||
} else if ( line_id >= 50 && line_id <= 56) {
|
||||
parseCommLine(line_id, simgear::strutils::split(line));
|
||||
} else if ( line_id == 110 ) {
|
||||
pavement = true;
|
||||
parsePavementLine850(simgear::strutils::split(line, 0, 4));
|
||||
|
@ -206,6 +203,7 @@ private:
|
|||
vector<FGRunwayPtr> runways;
|
||||
vector<FGTaxiwayPtr> taxiways;
|
||||
vector<FGPavementPtr> pavements;
|
||||
vector<flightgear::CommStation*> commStations;
|
||||
|
||||
void addAirport()
|
||||
{
|
||||
|
@ -235,6 +233,7 @@ private:
|
|||
FGAirport* apt = new FGAirport(last_apt_id, pos, tower, last_apt_name, false,
|
||||
fptypeFromRobinType(atoi(last_apt_type.c_str())));
|
||||
apt->setRunwaysAndTaxiways(runways, taxiways, pavements);
|
||||
apt->setCommStations(commStations);
|
||||
}
|
||||
|
||||
void parseAirportLine(const vector<string>& token)
|
||||
|
@ -466,48 +465,38 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void parseATISLine(FGCommList *comm_list, const vector<string>& token)
|
||||
void parseCommLine(int lineId, const vector<string>& token)
|
||||
{
|
||||
if ( rwy_count <= 0 ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||
"No runways; skipping AWOS for " + last_apt_id);
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "No runways; skipping comm for " + last_apt_id);
|
||||
}
|
||||
|
||||
// This assumes/requires that any code-50 line (ATIS or AWOS)
|
||||
// applies to the preceding code-1 line (airport ID and name)
|
||||
// and that a full set of code-10 lines (runway descriptors)
|
||||
// has come between the code-1 and code-50 lines.
|
||||
// typical code-50 lines:
|
||||
// 50 11770 ATIS
|
||||
// 50 11770 AWOS 3
|
||||
// This code parallels code found in "operator>>" in ATC.hxx;
|
||||
// FIXME: unify the code.
|
||||
ATCData a;
|
||||
a.geod = SGGeod::fromDegFt(rwy_lon_accum / (double)rwy_count,
|
||||
rwy_lat_accum / (double)rwy_count, last_apt_elev);
|
||||
a.range = 50; // give all ATISs small range
|
||||
a.ident = last_apt_id;
|
||||
a.name = last_apt_name;
|
||||
|
||||
SGGeod pos = SGGeod::fromDegFt(rwy_lon_accum / (double)rwy_count,
|
||||
rwy_lat_accum / (double)rwy_count, last_apt_elev);
|
||||
|
||||
// short int representing tens of kHz:
|
||||
a.freq = atoi(token[1].c_str());
|
||||
if (token[2] == "ATIS") a.type = ATIS;
|
||||
else a.type = AWOS; // ASOS same as AWOS
|
||||
int freqKhz = atoi(token[1].c_str());
|
||||
int rangeNm = 50;
|
||||
FGPositioned::Type ty;
|
||||
switch (lineId) {
|
||||
case 50:
|
||||
ty = FGPositioned::FREQ_AWOS;
|
||||
if (token[2] == "ATIS") {
|
||||
ty = FGPositioned::FREQ_ATIS;
|
||||
}
|
||||
break;
|
||||
|
||||
case 51: ty = FGPositioned::FREQ_UNICOM; break;
|
||||
case 52: ty = FGPositioned::FREQ_CLEARANCE; break;
|
||||
case 53: ty = FGPositioned::FREQ_GROUND; break;
|
||||
case 54: ty = FGPositioned::FREQ_TOWER; break;
|
||||
case 55:
|
||||
case 56: ty = FGPositioned::FREQ_APP_DEP; break;
|
||||
default:
|
||||
throw sg_range_exception("unupported apt.dat comm station type");
|
||||
}
|
||||
|
||||
// generate cartesian coordinates
|
||||
a.cart = SGVec3d::fromGeod(a.geod);
|
||||
comm_list->commlist_freq[a.freq].push_back(a);
|
||||
|
||||
SGBucket bucket(a.geod);
|
||||
int bucknum = bucket.gen_index();
|
||||
comm_list->commlist_bck[bucknum].push_back(a);
|
||||
#if 0
|
||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||
"Loaded ATIS/AWOS for airport: " << a.ident
|
||||
<< " lat: " << a.geod.getLatitudeDeg()
|
||||
<< " lon: " << a.geod.getLongitudeDeg()
|
||||
<< " freq: " << a.freq
|
||||
<< " type: " << a.type );
|
||||
#endif
|
||||
commStations.push_back(new flightgear::CommStation(token[2], ty, pos, rangeNm, freqKhz));
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -516,12 +505,11 @@ private:
|
|||
// Load the airport data base from the specified aptdb file. The
|
||||
// metar file is used to mark the airports as having metar available
|
||||
// or not.
|
||||
bool fgAirportDBLoad( const string &aptdb_file,
|
||||
FGCommList *comm_list, const std::string &metar_file )
|
||||
bool fgAirportDBLoad( const string &aptdb_file, const std::string &metar_file )
|
||||
{
|
||||
|
||||
APTLoader ld;
|
||||
ld.parseAPT(aptdb_file, comm_list);
|
||||
ld.parseAPT(aptdb_file);
|
||||
//
|
||||
// Load the metar.dat file and update apt db with stations that
|
||||
// have metar data.
|
||||
|
|
|
@ -29,14 +29,11 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
// forward decls
|
||||
class FGCommList;
|
||||
|
||||
// Load the airport data base from the specified aptdb file. The
|
||||
// metar file is used to mark the airports as having metar available
|
||||
// or not.
|
||||
|
||||
bool fgAirportDBLoad( const std::string &aptdb_file,
|
||||
FGCommList *comm_list, const std::string &metar_file );
|
||||
const std::string &metar_file );
|
||||
|
||||
#endif // _FG_APT_LOADER_HXX
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Airports/runways.hxx>
|
||||
#include <ATCDCL/ATCutils.hxx>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -49,33 +50,11 @@ using std::random_shuffle;
|
|||
#include "dynamics.hxx"
|
||||
|
||||
FGAirportDynamics::FGAirportDynamics(FGAirport * ap):
|
||||
_ap(ap), rwyPrefs(ap), SIDs(ap)
|
||||
_ap(ap), rwyPrefs(ap), SIDs(ap),
|
||||
atisSequenceIndex(-1),
|
||||
atisSequenceTimeStamp(0.0)
|
||||
{
|
||||
lastUpdate = 0;
|
||||
|
||||
// For testing only. This needs to be refined when we move ATIS functionality over.
|
||||
atisInformation = "Sierra";
|
||||
}
|
||||
|
||||
// Note that the ground network should also be copied
|
||||
FGAirportDynamics::
|
||||
FGAirportDynamics(const FGAirportDynamics & other):rwyPrefs(other.
|
||||
rwyPrefs),
|
||||
SIDs(other.SIDs)
|
||||
{
|
||||
for (FGParkingVecConstIterator ip = other.parkings.begin();
|
||||
ip != other.parkings.end(); ip++)
|
||||
parkings.push_back(*(ip));
|
||||
// rwyPrefs = other.rwyPrefs;
|
||||
lastUpdate = other.lastUpdate;
|
||||
|
||||
stringVecConstIterator il;
|
||||
for (il = other.landing.begin(); il != other.landing.end(); il++)
|
||||
landing.push_back(*il);
|
||||
for (il = other.takeoff.begin(); il != other.takeoff.end(); il++)
|
||||
takeoff.push_back(*il);
|
||||
lastUpdate = other.lastUpdate;
|
||||
atisInformation = other.atisInformation;
|
||||
}
|
||||
|
||||
// Destructor
|
||||
|
@ -540,3 +519,33 @@ FGAIFlightPlan *FGAirportDynamics::getSID(string activeRunway,
|
|||
{
|
||||
return SIDs.getBest(activeRunway, heading);
|
||||
}
|
||||
|
||||
const std::string FGAirportDynamics::getAtisSequence()
|
||||
{
|
||||
if (atisSequenceIndex == -1) {
|
||||
updateAtisSequence(1, false);
|
||||
}
|
||||
|
||||
return GetPhoneticLetter(atisSequenceIndex);
|
||||
}
|
||||
|
||||
int FGAirportDynamics::updateAtisSequence(int interval, bool forceUpdate)
|
||||
{
|
||||
double now = globals->get_sim_time_sec();
|
||||
if (atisSequenceIndex == -1) {
|
||||
// first computation
|
||||
atisSequenceTimeStamp = now;
|
||||
atisSequenceIndex = rand() % LTRS; // random initial sequence letters
|
||||
return atisSequenceIndex;
|
||||
}
|
||||
|
||||
int steps = static_cast<int>((now - atisSequenceTimeStamp) / interval);
|
||||
atisSequenceTimeStamp += (interval * steps);
|
||||
if (forceUpdate && (steps == 0)) {
|
||||
++steps; // a "special" ATIS update is required
|
||||
}
|
||||
|
||||
atisSequenceIndex = (atisSequenceIndex + steps) % LTRS;
|
||||
// return a huge value if no update occurred
|
||||
return (atisSequenceIndex + (steps ? 0 : LTRS*1000));
|
||||
}
|
||||
|
|
|
@ -22,24 +22,15 @@
|
|||
#ifndef _AIRPORT_DYNAMICS_HXX_
|
||||
#define _AIRPORT_DYNAMICS_HXX_
|
||||
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <simgear/xml/easyxml.hxx>
|
||||
|
||||
#include <ATC/trafficcontrol.hxx>
|
||||
#include "parking.hxx"
|
||||
#include "groundnetwork.hxx"
|
||||
#include "runwayprefs.hxx"
|
||||
#include "sidstar.hxx"
|
||||
|
||||
//typedef vector<float> DoubleVec;
|
||||
//typedef vector<float>::iterator DoubleVecIterator;
|
||||
|
||||
// forward decls
|
||||
class FGAirport;
|
||||
|
||||
class FGEnvironment;
|
||||
|
||||
class FGAirportDynamics {
|
||||
|
||||
|
@ -55,7 +46,7 @@ private:
|
|||
FGApproachController approachController;
|
||||
|
||||
time_t lastUpdate;
|
||||
string prevTrafficType;
|
||||
std::string prevTrafficType;
|
||||
stringVec landing;
|
||||
stringVec takeoff;
|
||||
stringVec milActive, comActive, genActive, ulActive;
|
||||
|
@ -67,14 +58,14 @@ private:
|
|||
intVec freqTower; // </TOWER>
|
||||
intVec freqApproach; // </APPROACH>
|
||||
|
||||
string atisInformation;
|
||||
|
||||
string chooseRunwayFallback();
|
||||
bool innerGetActiveRunway(const string &trafficType, int action, string &runway, double heading);
|
||||
string chooseRwyByHeading(stringVec rwys, double heading);
|
||||
int atisSequenceIndex;
|
||||
double atisSequenceTimeStamp;
|
||||
|
||||
std::string chooseRunwayFallback();
|
||||
bool innerGetActiveRunway(const std::string &trafficType, int action, std::string &runway, double heading);
|
||||
std::string chooseRwyByHeading(stringVec rwys, double heading);
|
||||
public:
|
||||
FGAirportDynamics(FGAirport* ap);
|
||||
FGAirportDynamics(const FGAirportDynamics &other);
|
||||
~FGAirportDynamics();
|
||||
|
||||
void addAwosFreq (int val) { freqAwos.push_back(val); };
|
||||
|
@ -118,8 +109,13 @@ public:
|
|||
FGTowerController *getTowerController() { return &towerController; };
|
||||
FGApproachController *getApproachController() { return &approachController; };
|
||||
|
||||
const string& getAtisInformation() { return atisInformation; };
|
||||
int getGroundFrequency(unsigned leg); //{ return freqGround.size() ? freqGround[0] : 0; };
|
||||
int getGroundFrequency(unsigned leg);
|
||||
|
||||
/// get current ATIS sequence letter
|
||||
const std::string getAtisSequence();
|
||||
|
||||
/// get the current ATIS sequence number, updating it if necessary
|
||||
int updateAtisSequence(int interval, bool forceUpdate);
|
||||
|
||||
void setRwyUse(const FGRunwayPreference& ref);
|
||||
};
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
#include "runwaybase.hxx"
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@ public:
|
|||
{ return _surface_code; }
|
||||
|
||||
protected:
|
||||
|
||||
double _heading;
|
||||
double _length;
|
||||
double _width;
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
|
||||
#include <Airports/simple.hxx>
|
||||
#include <Navaids/procedure.hxx>
|
||||
#include <Navaids/navrecord.hxx>
|
||||
#include <Navaids/PositionedBinding.hxx>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -197,4 +199,9 @@ std::vector<flightgear::STAR*> FGRunway::getSTARs()
|
|||
return result;
|
||||
}
|
||||
|
||||
flightgear::PositionedBinding*
|
||||
FGRunway::createBinding(SGPropertyNode* nd) const
|
||||
{
|
||||
return new flightgear::RunwayBinding(this, nd);
|
||||
}
|
||||
|
||||
|
|
|
@ -116,6 +116,8 @@ public:
|
|||
{ return _reciprocal; }
|
||||
void setReciprocalRunway(FGRunway* other);
|
||||
|
||||
virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const;
|
||||
|
||||
/**
|
||||
* Helper to process property data loaded from an ICAO.threshold.xml file
|
||||
*/
|
||||
|
@ -130,6 +132,7 @@ public:
|
|||
* Get STARs associared with this runway
|
||||
*/
|
||||
std::vector<flightgear::STAR*> getSTARs();
|
||||
|
||||
};
|
||||
|
||||
#endif // _FG_RUNWAYS_HXX
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
#include <Airports/xmlloader.hxx>
|
||||
#include <Navaids/procedure.hxx>
|
||||
#include <Navaids/waypoint.hxx>
|
||||
#include <Navaids/PositionedBinding.hxx>
|
||||
#include <ATC/CommStation.hxx>
|
||||
|
||||
using std::vector;
|
||||
using namespace flightgear;
|
||||
|
@ -94,20 +96,18 @@ bool FGAirport::isHeliport() const
|
|||
|
||||
FGAirportDynamics * FGAirport::getDynamics()
|
||||
{
|
||||
if (_dynamics != 0) {
|
||||
if (_dynamics) {
|
||||
return _dynamics;
|
||||
} else {
|
||||
//cerr << "Trying to load dynamics for " << _id << endl;
|
||||
_dynamics = new FGAirportDynamics(this);
|
||||
XMLLoader::load(_dynamics);
|
||||
}
|
||||
|
||||
_dynamics = new FGAirportDynamics(this);
|
||||
XMLLoader::load(_dynamics);
|
||||
|
||||
FGRunwayPreference rwyPrefs(this);
|
||||
XMLLoader::load(&rwyPrefs);
|
||||
_dynamics->setRwyUse(rwyPrefs);
|
||||
|
||||
//FGSidStar SIDs(this);
|
||||
XMLLoader::load(_dynamics->getSIDs());
|
||||
}
|
||||
FGRunwayPreference rwyPrefs(this);
|
||||
XMLLoader::load(&rwyPrefs);
|
||||
_dynamics->setRwyUse(rwyPrefs);
|
||||
XMLLoader::load(_dynamics->getSIDs());
|
||||
|
||||
return _dynamics;
|
||||
}
|
||||
|
||||
|
@ -662,6 +662,61 @@ Approach* FGAirport::getApproachByIndex(unsigned int aIndex) const
|
|||
return mApproaches[aIndex];
|
||||
}
|
||||
|
||||
class AirportNodeListener : public SGPropertyChangeListener
|
||||
{
|
||||
public:
|
||||
AirportNodeListener()
|
||||
{
|
||||
SGPropertyNode* airports = fgGetNode("/sim/airport");
|
||||
airports->addChangeListener(this, false);
|
||||
}
|
||||
|
||||
virtual void valueChanged(SGPropertyNode*)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void childAdded(SGPropertyNode* pr, SGPropertyNode* child)
|
||||
{
|
||||
FGAirport* apt = FGAirport::findByIdent(child->getName());
|
||||
if (!apt) {
|
||||
return;
|
||||
}
|
||||
|
||||
flightgear::PositionedBinding::bind(apt, child);
|
||||
}
|
||||
};
|
||||
|
||||
void FGAirport::installPropertyListener()
|
||||
{
|
||||
new AirportNodeListener;
|
||||
}
|
||||
|
||||
flightgear::PositionedBinding*
|
||||
FGAirport::createBinding(SGPropertyNode* nd) const
|
||||
{
|
||||
return new flightgear::AirportBinding(this, nd);
|
||||
}
|
||||
|
||||
void FGAirport::setCommStations(CommStationList& comms)
|
||||
{
|
||||
mCommStations.swap(comms);
|
||||
for (unsigned int c=0; c<mCommStations.size(); ++c) {
|
||||
mCommStations[c]->setAirport(this);
|
||||
}
|
||||
}
|
||||
|
||||
CommStationList
|
||||
FGAirport::commStationsOfType(FGPositioned::Type aTy) const
|
||||
{
|
||||
CommStationList result;
|
||||
for (unsigned int c=0; c<mCommStations.size(); ++c) {
|
||||
if (mCommStations[c]->type() == aTy) {
|
||||
result.push_back(mCommStations[c]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// get airport elevation
|
||||
double fgGetAirportElev( const string& id )
|
||||
{
|
||||
|
|
|
@ -50,10 +50,12 @@ namespace flightgear {
|
|||
class STAR;
|
||||
class Approach;
|
||||
class Waypt;
|
||||
|
||||
class CommStation;
|
||||
|
||||
typedef SGSharedPtr<Waypt> WayptRef;
|
||||
typedef std::vector<WayptRef> WayptVec;
|
||||
|
||||
typedef std::vector<CommStation*> CommStationList;
|
||||
}
|
||||
|
||||
|
||||
|
@ -185,6 +187,8 @@ public:
|
|||
unsigned int numApproaches() const;
|
||||
flightgear::Approach* getApproachByIndex(unsigned int aIndex) const;
|
||||
|
||||
static void installPropertyListener();
|
||||
|
||||
/**
|
||||
* Syntactic wrapper around FGPositioned::findClosest - find the closest
|
||||
* match for filter, and return it cast to FGAirport. The default filter
|
||||
|
@ -228,6 +232,14 @@ public:
|
|||
*/
|
||||
std::pair<flightgear::STAR*, flightgear::WayptRef> selectSTAR(const SGGeod& aOrigin, FGRunway* aRwy);
|
||||
|
||||
virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const;
|
||||
|
||||
void setCommStations(flightgear::CommStationList& comms);
|
||||
|
||||
flightgear::CommStationList commStationsOfType(FGPositioned::Type aTy) const;
|
||||
|
||||
const flightgear::CommStationList& commStations() const
|
||||
{ return mCommStations; }
|
||||
private:
|
||||
typedef std::vector<FGRunwayPtr>::const_iterator Runway_iterator;
|
||||
/**
|
||||
|
@ -275,6 +287,8 @@ private:
|
|||
std::vector<flightgear::SID*> mSIDs;
|
||||
std::vector<flightgear::STAR*> mSTARs;
|
||||
std::vector<flightgear::Approach*> mApproaches;
|
||||
|
||||
flightgear::CommStationList mCommStations;
|
||||
};
|
||||
|
||||
// find basic airport location info from airport database
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/structure/commands.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
|
||||
#include <simgear/props/props_io.hxx>
|
||||
|
@ -109,6 +110,151 @@ PropertyWatcher* createWatcher(T* obj, void (T::*m)())
|
|||
return new MethodPropertyWatcher<T>(obj, m);
|
||||
}
|
||||
|
||||
static bool commandLoadFlightPlan(const SGPropertyNode* arg)
|
||||
{
|
||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||
SGPath path(arg->getStringValue("path"));
|
||||
return self->loadRoute(path);
|
||||
}
|
||||
|
||||
static bool commandSaveFlightPlan(const SGPropertyNode* arg)
|
||||
{
|
||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||
SGPath path(arg->getStringValue("path"));
|
||||
return self->saveRoute(path);
|
||||
}
|
||||
|
||||
static bool commandActivateFlightPlan(const SGPropertyNode* arg)
|
||||
{
|
||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||
bool activate = arg->getBoolValue("activate", true);
|
||||
if (activate) {
|
||||
self->activate();
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool commandClearFlightPlan(const SGPropertyNode*)
|
||||
{
|
||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||
self->clearRoute();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool commandSetActiveWaypt(const SGPropertyNode* arg)
|
||||
{
|
||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||
int index = arg->getIntValue("index");
|
||||
if ((index < 0) || (index >= self->numWaypts())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self->jumpToIndex(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool commandInsertWaypt(const SGPropertyNode* arg)
|
||||
{
|
||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||
int index = arg->getIntValue("index");
|
||||
std::string ident(arg->getStringValue("id"));
|
||||
int alt = arg->getIntValue("altitude-ft", -999);
|
||||
int ias = arg->getIntValue("speed-knots", -999);
|
||||
|
||||
WayptRef wp;
|
||||
// lat/lon may be supplied to narrow down navaid search, or to specify
|
||||
// a raw waypoint
|
||||
SGGeod pos;
|
||||
if (arg->hasChild("longitude-deg")) {
|
||||
pos = SGGeod::fromDeg(arg->getDoubleValue("longitude-deg"),
|
||||
arg->getDoubleValue("latitude-deg"));
|
||||
}
|
||||
|
||||
if (arg->hasChild("navaid")) {
|
||||
FGPositionedRef p = FGPositioned::findClosestWithIdent(arg->getStringValue("navaid"), pos);
|
||||
|
||||
if (arg->hasChild("navaid", 1)) {
|
||||
// intersection of two radials
|
||||
FGPositionedRef p2 = FGPositioned::findClosestWithIdent(arg->getStringValue("navaid[1]"), pos);
|
||||
if (!p2) {
|
||||
SG_LOG( SG_AUTOPILOT, SG_INFO, "Unable to find FGPositioned with ident:" << arg->getStringValue("navaid[1]"));
|
||||
return false;
|
||||
}
|
||||
|
||||
double r1 = arg->getDoubleValue("radial"),
|
||||
r2 = arg->getDoubleValue("radial[1]");
|
||||
|
||||
SGGeod intersection;
|
||||
bool ok = SGGeodesy::radialIntersection(p->geod(), r1, p2->geod(), r2, intersection);
|
||||
if (!ok) {
|
||||
SG_LOG(SG_AUTOPILOT, SG_INFO, "no valid intersection for:" << p->ident()
|
||||
<< "," << p2->ident());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string name = p->ident() + "-" + p2->ident();
|
||||
wp = new BasicWaypt(intersection, name, NULL);
|
||||
} else if (arg->hasChild("offset-nm") && arg->hasChild("radial")) {
|
||||
// offset radial from navaid
|
||||
double radial = arg->getDoubleValue("radial");
|
||||
double distanceNm = arg->getDoubleValue("offset-nm");
|
||||
//radial += magvar->getDoubleValue(); // convert to true bearing
|
||||
wp = new OffsetNavaidWaypoint(p, NULL, radial, distanceNm);
|
||||
} else {
|
||||
wp = new NavaidWaypoint(p, NULL);
|
||||
}
|
||||
} else if (arg->hasChild("airport")) {
|
||||
const FGAirport* apt = fgFindAirportID(arg->getStringValue("airport"));
|
||||
if (!apt) {
|
||||
SG_LOG(SG_AUTOPILOT, SG_INFO, "no such airport" << arg->getStringValue("airport"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arg->hasChild("runway")) {
|
||||
if (!apt->hasRunwayWithIdent(arg->getStringValue("runway"))) {
|
||||
SG_LOG(SG_AUTOPILOT, SG_INFO, "No runway: " << arg->getStringValue("runway") << " at " << apt->ident());
|
||||
return false;
|
||||
}
|
||||
|
||||
FGRunway* runway = apt->getRunwayByIdent(arg->getStringValue("runway"));
|
||||
wp = new RunwayWaypt(runway, NULL);
|
||||
} else {
|
||||
wp = new NavaidWaypoint((FGAirport*) apt, NULL);
|
||||
}
|
||||
} else if (arg->hasChild("text")) {
|
||||
wp = self->waypointFromString(arg->getStringValue("text"));
|
||||
} else if (!(pos == SGGeod())) {
|
||||
// just a raw lat/lon
|
||||
wp = new BasicWaypt(pos, ident, NULL);
|
||||
} else {
|
||||
return false; // failed to build waypoint
|
||||
}
|
||||
|
||||
if (alt >= 0) {
|
||||
wp->setAltitude(alt, flightgear::RESTRICT_AT);
|
||||
}
|
||||
|
||||
if (ias > 0) {
|
||||
wp->setSpeed(ias, flightgear::RESTRICT_AT);
|
||||
}
|
||||
|
||||
self->insertWayptAtIndex(wp, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool commandDeleteWaypt(const SGPropertyNode* arg)
|
||||
{
|
||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||
int index = arg->getIntValue("index");
|
||||
self->removeWayptAtIndex(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FGRouteMgr::FGRouteMgr() :
|
||||
_currentIndex(0),
|
||||
input(fgGetNode( RM "input", true )),
|
||||
|
@ -117,6 +263,14 @@ FGRouteMgr::FGRouteMgr() :
|
|||
listener = new InputListener(this);
|
||||
input->setStringValue("");
|
||||
input->addChangeListener(listener);
|
||||
|
||||
SGCommandMgr::instance()->addCommand("load-flightplan", commandLoadFlightPlan);
|
||||
SGCommandMgr::instance()->addCommand("save-flightplan", commandSaveFlightPlan);
|
||||
SGCommandMgr::instance()->addCommand("activate-flightplan", commandActivateFlightPlan);
|
||||
SGCommandMgr::instance()->addCommand("clear-flightplan", commandClearFlightPlan);
|
||||
SGCommandMgr::instance()->addCommand("set-active-waypt", commandSetActiveWaypt);
|
||||
SGCommandMgr::instance()->addCommand("insert-waypt", commandInsertWaypt);
|
||||
SGCommandMgr::instance()->addCommand("delete-waypt", commandDeleteWaypt);
|
||||
}
|
||||
|
||||
|
||||
|
@ -227,7 +381,7 @@ void FGRouteMgr::postinit()
|
|||
SGPath path(_pathNode->getStringValue());
|
||||
if (path.exists()) {
|
||||
SG_LOG(SG_AUTOPILOT, SG_INFO, "loading flight-plan from:" << path.str());
|
||||
loadRoute();
|
||||
loadRoute(path);
|
||||
}
|
||||
|
||||
// this code only matters for the --wp option now - perhaps the option
|
||||
|
@ -897,11 +1051,11 @@ void FGRouteMgr::InputListener::valueChanged(SGPropertyNode *prop)
|
|||
else if (!strcmp(s, "@ACTIVATE"))
|
||||
mgr->activate();
|
||||
else if (!strcmp(s, "@LOAD")) {
|
||||
mgr->loadRoute();
|
||||
SGPath path(mgr->_pathNode->getStringValue());
|
||||
mgr->loadRoute(path);
|
||||
} else if (!strcmp(s, "@SAVE")) {
|
||||
mgr->saveRoute();
|
||||
} else if (!strcmp(s, "@POP")) {
|
||||
SG_LOG(SG_AUTOPILOT, SG_WARN, "route-manager @POP command is deprecated");
|
||||
SGPath path(mgr->_pathNode->getStringValue());
|
||||
mgr->saveRoute(path);
|
||||
} else if (!strcmp(s, "@NEXT")) {
|
||||
mgr->jumpToIndex(mgr->_currentIndex + 1);
|
||||
} else if (!strcmp(s, "@PREVIOUS")) {
|
||||
|
@ -1119,9 +1273,8 @@ Waypt* FGRouteMgr::wayptAtIndex(int index) const
|
|||
return _route[index];
|
||||
}
|
||||
|
||||
void FGRouteMgr::saveRoute()
|
||||
bool FGRouteMgr::saveRoute(const SGPath& path)
|
||||
{
|
||||
SGPath path(_pathNode->getStringValue());
|
||||
SG_LOG(SG_IO, SG_INFO, "Saving route to " << path.str());
|
||||
try {
|
||||
SGPropertyNode_ptr d(new SGPropertyNode);
|
||||
|
@ -1148,18 +1301,19 @@ void FGRouteMgr::saveRoute()
|
|||
wpt->saveAsNode(routeNode->getChild("wp", i, true));
|
||||
} // of waypoint iteration
|
||||
writeProperties(path.str(), d, true /* write-all */);
|
||||
return true;
|
||||
} catch (sg_exception& e) {
|
||||
SG_LOG(SG_IO, SG_WARN, "failed to save flight-plan:" << e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FGRouteMgr::loadRoute()
|
||||
bool FGRouteMgr::loadRoute(const SGPath& path)
|
||||
{
|
||||
// deactivate route first
|
||||
active->setBoolValue(false);
|
||||
|
||||
SGPropertyNode_ptr routeData(new SGPropertyNode);
|
||||
SGPath path(_pathNode->getStringValue());
|
||||
|
||||
SG_LOG(SG_IO, SG_INFO, "going to read flight-plan from:" << path.str());
|
||||
|
||||
|
@ -1167,8 +1321,7 @@ void FGRouteMgr::loadRoute()
|
|||
readProperties(path.str(), routeData);
|
||||
} catch (sg_exception& ) {
|
||||
// if XML parsing fails, the file might be simple textual list of waypoints
|
||||
loadPlainTextRoute(path);
|
||||
return;
|
||||
return loadPlainTextRoute(path);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -1180,9 +1333,11 @@ void FGRouteMgr::loadRoute()
|
|||
} else {
|
||||
throw sg_io_exception("unsupported XML route version");
|
||||
}
|
||||
return true;
|
||||
} catch (sg_exception& e) {
|
||||
SG_LOG(SG_IO, SG_WARN, "failed to load flight-plan (from '" << e.getOrigin()
|
||||
<< "'):" << e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1299,11 +1454,11 @@ WayptRef FGRouteMgr::parseVersion1XMLWaypt(SGPropertyNode* aWP)
|
|||
return w;
|
||||
}
|
||||
|
||||
void FGRouteMgr::loadPlainTextRoute(const SGPath& path)
|
||||
bool FGRouteMgr::loadPlainTextRoute(const SGPath& path)
|
||||
{
|
||||
sg_gzifstream in(path.str().c_str());
|
||||
if (!in.is_open()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -1330,8 +1485,10 @@ void FGRouteMgr::loadPlainTextRoute(const SGPath& path)
|
|||
} // of line iteration
|
||||
|
||||
_route = wpts;
|
||||
return true;
|
||||
} catch (sg_exception& e) {
|
||||
SG_LOG(SG_IO, SG_WARN, "failed to load route from:" << path.str() << ":" << e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -118,13 +118,22 @@ public:
|
|||
*/
|
||||
void jumpToIndex(int index);
|
||||
|
||||
void saveRoute();
|
||||
void loadRoute();
|
||||
bool saveRoute(const SGPath& p);
|
||||
bool loadRoute(const SGPath& p);
|
||||
|
||||
/**
|
||||
* Helper command to setup current airport/runway if necessary
|
||||
*/
|
||||
void initAtPosition();
|
||||
|
||||
/**
|
||||
* Create a WayPoint from a string in the following format:
|
||||
* - simple identifier
|
||||
* - decimal-lon,decimal-lat
|
||||
* - airport-id/runway-id
|
||||
* - navaid/radial-deg/offset-nm
|
||||
*/
|
||||
flightgear::WayptRef waypointFromString(const std::string& target);
|
||||
private:
|
||||
flightgear::WayptVec _route;
|
||||
int _currentIndex;
|
||||
|
@ -188,17 +197,7 @@ private:
|
|||
SGPropertyNode_ptr weightOnWheels;
|
||||
|
||||
InputListener *listener;
|
||||
SGPropertyNode_ptr mirror;
|
||||
|
||||
/**
|
||||
* Create a SGWayPoint from a string in the following format:
|
||||
* - simple identifier
|
||||
* - decimal-lon,decimal-lat
|
||||
* - airport-id/runway-id
|
||||
* - navaid/radial-deg/offset-nm
|
||||
*/
|
||||
flightgear::WayptRef waypointFromString(const std::string& target);
|
||||
|
||||
SGPropertyNode_ptr mirror;
|
||||
|
||||
void departureChanged();
|
||||
void buildDeparture(flightgear::WayptRef enroute, flightgear::WayptVec& wps);
|
||||
|
@ -229,7 +228,7 @@ private:
|
|||
bool checkFinished();
|
||||
|
||||
|
||||
void loadPlainTextRoute(const SGPath& path);
|
||||
bool loadPlainTextRoute(const SGPath& path);
|
||||
|
||||
void loadVersion1XMLRoute(SGPropertyNode_ptr routeData);
|
||||
void loadVersion2XMLRoute(SGPropertyNode_ptr routeData);
|
||||
|
|
|
@ -16,6 +16,7 @@ set(SOURCES
|
|||
ridge_lift.cxx
|
||||
terrainsampler.cxx
|
||||
presets.cxx
|
||||
gravity.cxx
|
||||
)
|
||||
|
||||
flightgear_component(Environment "${SOURCES}")
|
||||
|
|
|
@ -17,6 +17,7 @@ libEnvironment_a_SOURCES = \
|
|||
ridge_lift.cxx ridge_lift.hxx \
|
||||
ephemeris.cxx ephemeris.hxx \
|
||||
terrainsampler.cxx terrainsampler.cxx \
|
||||
presets.cxx presets.hxx
|
||||
presets.cxx presets.hxx \
|
||||
gravity.cxx gravity.hxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
||||
|
|
|
@ -31,8 +31,6 @@
|
|||
#include <cmath>
|
||||
#include <utility>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* Model the atmosphere in a way consistent with the laws
|
||||
* of physics.
|
||||
|
|
|
@ -42,18 +42,56 @@
|
|||
#include "ridge_lift.hxx"
|
||||
#include "terrainsampler.hxx"
|
||||
#include "Airports/simple.hxx"
|
||||
#include "gravity.hxx"
|
||||
|
||||
class SGSky;
|
||||
extern SGSky *thesky;
|
||||
|
||||
class FG3DCloudsListener : public SGPropertyChangeListener {
|
||||
public:
|
||||
FG3DCloudsListener( FGClouds * fgClouds );
|
||||
virtual ~FG3DCloudsListener();
|
||||
|
||||
virtual void valueChanged (SGPropertyNode * node);
|
||||
|
||||
private:
|
||||
FGClouds * _fgClouds;
|
||||
SGPropertyNode_ptr _shaderNode;
|
||||
SGPropertyNode_ptr _enableNode;
|
||||
};
|
||||
|
||||
FG3DCloudsListener::FG3DCloudsListener( FGClouds * fgClouds ) :
|
||||
_fgClouds( fgClouds )
|
||||
{
|
||||
_shaderNode = fgGetNode( "/sim/rendering/shader-effects", true );
|
||||
_shaderNode->addChangeListener( this );
|
||||
|
||||
_enableNode = fgGetNode( "/sim/rendering/clouds3d-enable", true );
|
||||
_enableNode->addChangeListener( this );
|
||||
|
||||
valueChanged( _enableNode );
|
||||
}
|
||||
|
||||
FG3DCloudsListener::~FG3DCloudsListener()
|
||||
{
|
||||
_enableNode->removeChangeListener( this );
|
||||
_shaderNode->removeChangeListener( this );
|
||||
}
|
||||
|
||||
void FG3DCloudsListener::valueChanged( SGPropertyNode * node )
|
||||
{
|
||||
_fgClouds->set_3dClouds( _enableNode->getBoolValue() && _shaderNode->getBoolValue() );
|
||||
}
|
||||
|
||||
FGEnvironmentMgr::FGEnvironmentMgr () :
|
||||
_environment(new FGEnvironment()),
|
||||
fgClouds(new FGClouds()),
|
||||
_cloudLayersDirty(true),
|
||||
_altitudeNode(fgGetNode("/position/altitude-ft", true)),
|
||||
_altitude_n(fgGetNode("/position/altitude-ft", true)),
|
||||
_longitude_n(fgGetNode( "/position/longitude-deg", true )),
|
||||
_latitude_n( fgGetNode( "/position/latitude-deg", true )),
|
||||
_positionTimeToLive(0.0)
|
||||
_positionTimeToLive(0.0),
|
||||
_3dCloudsEnableListener(new FG3DCloudsListener(fgClouds) )
|
||||
{
|
||||
set_subsystem("controller", Environment::LayerInterpolateController::createInstance( fgGetNode("/environment/config", true ) ));
|
||||
set_subsystem("realwx", Environment::RealWxController::createInstance( fgGetNode("/environment/realwx", true ) ), 1.0 );
|
||||
|
@ -89,6 +127,8 @@ FGEnvironmentMgr::~FGEnvironmentMgr ()
|
|||
|
||||
delete fgClouds;
|
||||
delete _environment;
|
||||
|
||||
delete _3dCloudsEnableListener;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -97,6 +137,14 @@ FGEnvironmentMgr::init ()
|
|||
SG_LOG( SG_GENERAL, SG_INFO, "Initializing environment subsystem");
|
||||
SGSubsystemGroup::init();
|
||||
fgClouds->Init();
|
||||
|
||||
// FIXME: is this really part of the environment_mgr?
|
||||
// Initialize the longitude, latitude and altitude to the initial position
|
||||
// of the aircraft so that the atmospheric properties (pressure, temperature
|
||||
// and density) can be initialized accordingly.
|
||||
_altitude_n->setDoubleValue(fgGetDouble("/sim/presets/altitude-ft"));
|
||||
_longitude_n->setDoubleValue(fgGetDouble("/sim/presets/longitude-deg"));
|
||||
_latitude_n->setDoubleValue(fgGetDouble("/sim/presets/latitude-deg"));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -163,10 +211,6 @@ FGEnvironmentMgr::bind ()
|
|||
|
||||
_tiedProperties.setRoot( fgGetNode("/sim/rendering", true ) );
|
||||
|
||||
_tiedProperties.Tie( "clouds3d-enable", fgClouds,
|
||||
&FGClouds::get_3dClouds,
|
||||
&FGClouds::set_3dClouds);
|
||||
|
||||
_tiedProperties.Tie( "clouds3d-density", thesky,
|
||||
&SGSky::get_3dCloudDensity,
|
||||
&SGSky::set_3dCloudDensity);
|
||||
|
@ -194,7 +238,7 @@ FGEnvironmentMgr::update (double dt)
|
|||
{
|
||||
SGSubsystemGroup::update(dt);
|
||||
|
||||
_environment->set_elevation_ft( _altitudeNode->getDoubleValue() );
|
||||
_environment->set_elevation_ft( _altitude_n->getDoubleValue() );
|
||||
|
||||
simgear::Particles::setWindFrom( _environment->get_wind_from_heading_deg(),
|
||||
_environment->get_wind_speed_kt() );
|
||||
|
@ -203,6 +247,14 @@ FGEnvironmentMgr::update (double dt)
|
|||
fgClouds->set_update_event( fgClouds->get_update_event()+1 );
|
||||
}
|
||||
|
||||
|
||||
fgSetDouble( "/environment/gravitational-acceleration-mps2",
|
||||
Environment::Gravity::instance()->getGravity(SGGeod::fromDegFt(
|
||||
_longitude_n->getDoubleValue(),
|
||||
_latitude_n->getDoubleValue(),
|
||||
_altitude_n->getDoubleValue()
|
||||
)));
|
||||
|
||||
_positionTimeToLive -= dt;
|
||||
if( _positionTimeToLive <= 0.0 )
|
||||
{
|
||||
|
|
|
@ -95,11 +95,12 @@ private:
|
|||
FGEnvironment * _environment; // always the same, for now
|
||||
FGClouds *fgClouds;
|
||||
bool _cloudLayersDirty;
|
||||
SGPropertyNode_ptr _altitudeNode;
|
||||
SGPropertyNode_ptr _altitude_n;
|
||||
SGPropertyNode_ptr _longitude_n;
|
||||
SGPropertyNode_ptr _latitude_n;
|
||||
double _positionTimeToLive;
|
||||
simgear::TiedPropertyList _tiedProperties;
|
||||
SGPropertyChangeListener * _3dCloudsEnableListener;
|
||||
};
|
||||
|
||||
#endif // _ENVIRONMENT_MGR_HXX
|
||||
|
|
|
@ -45,6 +45,9 @@
|
|||
|
||||
extern SGSky *thesky;
|
||||
|
||||
static bool do_delete_3Dcloud (const SGPropertyNode *arg);
|
||||
static bool do_move_3Dcloud (const SGPropertyNode *arg);
|
||||
static bool do_add_3Dcloud (const SGPropertyNode *arg);
|
||||
|
||||
FGClouds::FGClouds() :
|
||||
#if 0
|
||||
|
@ -158,7 +161,7 @@ double FGClouds::buildCloud(SGPropertyNode *cloud_def_root, SGPropertyNode *box_
|
|||
y = w * (y - 0.5) + pos[1]; // E/W
|
||||
z = h * z + pos[2]; // Up/Down. pos[2] is the cloudbase
|
||||
|
||||
SGVec3f newpos = SGVec3f(x, y, z);
|
||||
//SGVec3f newpos = SGVec3f(x, y, z);
|
||||
SGNewCloud cld = SGNewCloud(texture_root, cld_def);
|
||||
|
||||
//layer->addCloud(newpos, cld.genCloud());
|
||||
|
|
|
@ -64,9 +64,5 @@ public:
|
|||
|
||||
};
|
||||
|
||||
static bool do_delete_3Dcloud (const SGPropertyNode *arg);
|
||||
static bool do_move_3Dcloud (const SGPropertyNode *arg);
|
||||
static bool do_add_3Dcloud (const SGPropertyNode *arg);
|
||||
|
||||
#endif // _FGCLOUDS_HXX
|
||||
|
||||
|
|
88
src/Environment/gravity.cxx
Normal file
88
src/Environment/gravity.cxx
Normal file
|
@ -0,0 +1,88 @@
|
|||
// gravity.cxx -- interface for earth gravitational model
|
||||
//
|
||||
// Written by Torsten Dreyer, June 2011
|
||||
//
|
||||
// Copyright (C) 2011 Torsten Dreyer - torsten (at) t3r _dot_ de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "gravity.hxx"
|
||||
|
||||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
namespace Environment {
|
||||
|
||||
/*
|
||||
http://de.wikipedia.org/wiki/Normalschwereformel
|
||||
*/
|
||||
class Somigliana : public Gravity {
|
||||
public:
|
||||
Somigliana();
|
||||
virtual ~Somigliana();
|
||||
virtual double getGravity( const SGGeod & position ) const;
|
||||
};
|
||||
|
||||
Somigliana::Somigliana()
|
||||
{
|
||||
}
|
||||
|
||||
Somigliana::~Somigliana()
|
||||
{
|
||||
}
|
||||
|
||||
double Somigliana::getGravity( const SGGeod & position ) const
|
||||
{
|
||||
// Geodetic Reference System 1980 parameter
|
||||
#define A 6378137.0 // equatorial radius of earth
|
||||
#define B 6356752.3141 // semiminor axis
|
||||
#define AGA (A*9.7803267715) // A times normal gravity at equator
|
||||
#define BGB (B*9.8321863685) // B times normal gravity at pole
|
||||
// forumla of Somigliana
|
||||
double cosphi = ::cos(position.getLatitudeRad());
|
||||
double cos2phi = cosphi*cosphi;
|
||||
double sinphi = ::sin(position.getLatitudeRad());
|
||||
double sin2phi = sinphi*sinphi;
|
||||
double g0 = (AGA * cos2phi + BGB * sin2phi) / sqrt( A*A*cos2phi+B*B*sin2phi );
|
||||
|
||||
static const double k1 = 3.15704e-7;
|
||||
static const double k2 = 2.10269e-9;
|
||||
static const double k3 = 7.37452e-14;
|
||||
|
||||
double h = position.getElevationM();
|
||||
|
||||
return g0*(1-(k1-k2*sin2phi)*h+k3*h*h);
|
||||
}
|
||||
|
||||
static Somigliana _somigliana;
|
||||
|
||||
/* --------------------- Gravity implementation --------------------- */
|
||||
Gravity * Gravity::_instance = NULL;
|
||||
|
||||
Gravity::~Gravity()
|
||||
{
|
||||
}
|
||||
|
||||
//double Gravity::getGravity( const SGGeoc & position ) = 0;
|
||||
|
||||
const Gravity * Gravity::instance()
|
||||
{
|
||||
if( _instance == NULL )
|
||||
_instance = &_somigliana;
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
} // namespace
|
43
src/Environment/gravity.hxx
Normal file
43
src/Environment/gravity.hxx
Normal file
|
@ -0,0 +1,43 @@
|
|||
// gravity.hxx -- interface for earth gravitational model
|
||||
//
|
||||
// Written by Torsten Dreyer, June 2011
|
||||
//
|
||||
// Copyright (C) 2011 Torsten Dreyer - torsten (at) t3r _dot_ de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef __GRAVITY_HXX
|
||||
#define __GRAVITY_HXX
|
||||
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
namespace Environment {
|
||||
|
||||
class Gravity
|
||||
{
|
||||
public:
|
||||
virtual ~Gravity();
|
||||
virtual double getGravity( const SGGeod & position ) const = 0;
|
||||
|
||||
const static Gravity * instance();
|
||||
|
||||
private:
|
||||
static Gravity * _instance;
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
#endif // __GRAVITY_HXX
|
|
@ -301,9 +301,6 @@ void MetarProperties::set_metar( const char * metar )
|
|||
}
|
||||
}
|
||||
|
||||
vector<SGMetarCloud> cv = m->getClouds();
|
||||
vector<SGMetarCloud>::const_iterator cloud, cloud_end = cv.end();
|
||||
|
||||
{
|
||||
static const char * LAYER = "layer";
|
||||
SGPropertyNode_ptr cloudsNode = _rootNode->getNode("clouds", true );
|
||||
|
|
|
@ -285,6 +285,7 @@ void AreaSampler::analyse()
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
double alt_low_min = 0.0;
|
||||
double n_max = 0.0;
|
||||
sum = 0.0;
|
||||
|
@ -296,7 +297,7 @@ void AreaSampler::analyse()
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
_altLayered = 0.5 * (_altMin + _altOffset);
|
||||
|
||||
#if 0
|
||||
|
|
|
@ -181,7 +181,7 @@ FGJSBsim::FGJSBsim( double dt )
|
|||
MassBalance = fdmex->GetMassBalance();
|
||||
Propulsion = fdmex->GetPropulsion();
|
||||
Aircraft = fdmex->GetAircraft();
|
||||
Propagate = fdmex->GetPropagate();
|
||||
Propagate = fdmex->GetPropagate();
|
||||
Auxiliary = fdmex->GetAuxiliary();
|
||||
Inertial = fdmex->GetInertial();
|
||||
Aerodynamics = fdmex->GetAerodynamics();
|
||||
|
@ -369,9 +369,9 @@ void FGJSBsim::init()
|
|||
Atmosphere->UseInternal();
|
||||
}
|
||||
|
||||
fgic->SetVNorthFpsIC( -wind_from_north->getDoubleValue() );
|
||||
fgic->SetVEastFpsIC( -wind_from_east->getDoubleValue() );
|
||||
fgic->SetVDownFpsIC( -wind_from_down->getDoubleValue() );
|
||||
fgic->SetWindNEDFpsIC( -wind_from_north->getDoubleValue(),
|
||||
-wind_from_east->getDoubleValue(),
|
||||
-wind_from_down->getDoubleValue() );
|
||||
|
||||
//Atmosphere->SetExTemperature(get_Static_temperature());
|
||||
//Atmosphere->SetExPressure(get_Static_pressure());
|
||||
|
@ -393,20 +393,20 @@ void FGJSBsim::init()
|
|||
}
|
||||
// end of egt_degf deprecation patch
|
||||
|
||||
if (fgGetBool("/sim/presets/running")) {
|
||||
for (unsigned int i=0; i < Propulsion->GetNumEngines(); i++) {
|
||||
SGPropertyNode * node = fgGetNode("engines/engine", i, true);
|
||||
node->setBoolValue("running", true);
|
||||
Propulsion->GetEngine(i)->SetRunning(true);
|
||||
}
|
||||
}
|
||||
|
||||
FCS->SetDfPos( ofNorm, globals->get_controls()->get_flaps() );
|
||||
|
||||
common_init();
|
||||
|
||||
copy_to_JSBsim();
|
||||
fdmex->RunIC(); //loop JSBSim once w/o integrating
|
||||
if (fgGetBool("/sim/presets/running")) {
|
||||
Propulsion->InitRunning(-1);
|
||||
for (unsigned int i = 0; i < Propulsion->GetNumEngines(); i++) {
|
||||
FGPiston* eng = (FGPiston*)Propulsion->GetEngine(i);
|
||||
globals->get_controls()->set_magnetos(i, eng->GetMagnetos());
|
||||
globals->get_controls()->set_mixture(i, FCS->GetMixtureCmd(i));
|
||||
}
|
||||
}
|
||||
copy_from_JSBsim(); //update the bus
|
||||
|
||||
SG_LOG( SG_FLIGHT, SG_INFO, " Initialized JSBSim with:" );
|
||||
|
@ -1282,7 +1282,7 @@ void FGJSBsim::do_trim(void)
|
|||
{
|
||||
fgtrim = new FGTrim(fdmex,tGround);
|
||||
} else {
|
||||
fgtrim = new FGTrim(fdmex,tLongitudinal);
|
||||
fgtrim = new FGTrim(fdmex,tFull);
|
||||
}
|
||||
|
||||
if ( !fgtrim->DoTrim() ) {
|
||||
|
@ -1296,7 +1296,7 @@ void FGJSBsim::do_trim(void)
|
|||
pitch_trim->setDoubleValue( FCS->GetPitchTrimCmd() );
|
||||
throttle_trim->setDoubleValue( FCS->GetThrottleCmd(0) );
|
||||
aileron_trim->setDoubleValue( FCS->GetDaCmd() );
|
||||
rudder_trim->setDoubleValue( FCS->GetDrCmd() );
|
||||
rudder_trim->setDoubleValue( -FCS->GetDrCmd() );
|
||||
|
||||
globals->get_controls()->set_elevator_trim(FCS->GetPitchTrimCmd());
|
||||
globals->get_controls()->set_elevator(FCS->GetDeCmd());
|
||||
|
@ -1304,7 +1304,7 @@ void FGJSBsim::do_trim(void)
|
|||
globals->get_controls()->set_throttle(i, FCS->GetThrottleCmd(i));
|
||||
|
||||
globals->get_controls()->set_aileron(FCS->GetDaCmd());
|
||||
globals->get_controls()->set_rudder( FCS->GetDrCmd());
|
||||
globals->get_controls()->set_rudder( -FCS->GetDrCmd());
|
||||
|
||||
SG_LOG( SG_FLIGHT, SG_INFO, " Trim complete" );
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.59 2011/04/03 13:18:51 bcoconni Exp $";
|
||||
static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.61 2011/05/20 00:47:03 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_INITIALCONDITION;
|
||||
|
||||
//******************************************************************************
|
||||
|
@ -112,7 +112,7 @@ void FGInitialCondition::ResetIC(double u0, double v0, double w0,
|
|||
FGQuaternion Quat(phi, theta, psi);
|
||||
Quat.Normalize();
|
||||
Tl2b = Quat.GetT();
|
||||
Tb2l = Quat.GetTInv();
|
||||
Tb2l = Tl2b.Transposed();
|
||||
|
||||
vUVW_NED = Tb2l * FGColumnVector3(u0, v0, w0);
|
||||
vt = vUVW_NED.Magnitude();
|
||||
|
@ -322,20 +322,18 @@ void FGInitialCondition::SetClimbRateFpsIC(double hdot)
|
|||
|
||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||
FGColumnVector3 _WIND_NED = _vt_NED - vUVW_NED;
|
||||
double hdot0 = _vt_NED(eW);
|
||||
double hdot0 = -_vt_NED(eW);
|
||||
|
||||
if (fabs(hdot0) < vt) {
|
||||
double scale = sqrt((vt*vt-hdot*hdot)/(vt*vt-hdot0*hdot0));
|
||||
_vt_NED(eU) *= scale;
|
||||
_vt_NED(eV) *= scale;
|
||||
}
|
||||
_vt_NED(eW) = hdot;
|
||||
_vt_NED(eW) = -hdot;
|
||||
vUVW_NED = _vt_NED - _WIND_NED;
|
||||
|
||||
// The AoA is not modified here but the function SetAlphaRadIC is updating the
|
||||
// same angles than SetClimbRateFpsIC needs to update.
|
||||
// TODO : create a subroutine that only shares the relevant code.
|
||||
SetAlphaRadIC(alpha);
|
||||
// Updating the angles theta and beta to keep the true airspeed amplitude
|
||||
calcThetaBeta(alpha, _vt_NED);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
|
@ -346,13 +344,22 @@ void FGInitialCondition::SetClimbRateFpsIC(double hdot)
|
|||
void FGInitialCondition::SetAlphaRadIC(double alfa)
|
||||
{
|
||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||
calcThetaBeta(alfa, _vt_NED);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// When the AoA is modified, we need to update the angles theta and beta to
|
||||
// keep the true airspeed amplitude, the climb rate and the heading unchanged.
|
||||
// Beta will be modified if the aircraft roll angle is not null.
|
||||
|
||||
void FGInitialCondition::calcThetaBeta(double alfa, const FGColumnVector3& _vt_NED)
|
||||
{
|
||||
double calpha = cos(alfa), salpha = sin(alfa);
|
||||
double cpsi = cos(psi), spsi = sin(psi);
|
||||
double cphi = cos(phi), sphi = sin(phi);
|
||||
FGMatrix33 Tpsi( cpsi, spsi, 0.,
|
||||
-spsi, cpsi, 0.,
|
||||
0., 0., 1.);
|
||||
-spsi, cpsi, 0.,
|
||||
0., 0., 1.);
|
||||
FGMatrix33 Tphi(1., 0., 0.,
|
||||
0., cphi, sphi,
|
||||
0.,-sphi, cphi);
|
||||
|
@ -398,11 +405,11 @@ void FGInitialCondition::SetAlphaRadIC(double alfa)
|
|||
Tl2b = Quat.GetT();
|
||||
Tb2l = Quat.GetTInv();
|
||||
|
||||
FGColumnVector3 v2 = Talpha * Quat.GetT() * _vt_NED;
|
||||
FGColumnVector3 v2 = Talpha * Tl2b * _vt_NED;
|
||||
|
||||
alpha = alfa;
|
||||
beta = atan2(v2(eV), v2(eU));
|
||||
double cbeta=0.0, sbeta=0.0;
|
||||
double cbeta=1.0, sbeta=0.0;
|
||||
if (vt != 0.0) {
|
||||
cbeta = v2(eU) / vt;
|
||||
sbeta = v2(eV) / vt;
|
||||
|
@ -687,6 +694,8 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt)
|
|||
double ve0 = vt * sqrt(rho/rhoSL);
|
||||
|
||||
altitudeASL=alt;
|
||||
position.SetRadius(alt + sea_level_radius);
|
||||
|
||||
temperature = fdmex->GetAtmosphere()->GetTemperature(altitudeASL);
|
||||
soundSpeed = sqrt(SHRatio*Reng*temperature);
|
||||
rho = fdmex->GetAtmosphere()->GetDensity(altitudeASL);
|
||||
|
@ -703,8 +712,6 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt)
|
|||
default: // Make the compiler stop complaining about missing enums
|
||||
break;
|
||||
}
|
||||
|
||||
position.SetRadius(alt + sea_level_radius);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
|
|
|
@ -54,7 +54,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.26 2011/01/16 16:10:59 bcoconni Exp $"
|
||||
#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.27 2011/05/20 00:47:03 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -213,7 +213,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.26 2011/01/16 16:10:59 bcoconni Exp $"
|
||||
@version "$Id: FGInitialCondition.h,v 1.27 2011/05/20 00:47:03 bcoconni Exp $"
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -666,6 +666,7 @@ private:
|
|||
double getMachFromVcas(double vcas);
|
||||
double calcVcas(double Mach) const;
|
||||
void calcAeroAngles(const FGColumnVector3& _vt_BODY);
|
||||
void calcThetaBeta(double alfa, const FGColumnVector3& _vt_NED);
|
||||
void bind(void);
|
||||
void Debug(int from);
|
||||
|
||||
|
|
|
@ -270,12 +270,10 @@ float Turbulence::iturb(unsigned int x, unsigned int y)
|
|||
xfrac = xfrac*xfrac*(3 - 2*xfrac); // ... as cubics
|
||||
yfrac = yfrac*yfrac*(3 - 2*yfrac);
|
||||
|
||||
#define WRAP(a) (a) >= wrapmax ? 0 : (a)
|
||||
float p00 = lattice(WRAP(xl), WRAP(yl)); // lattice values
|
||||
float p01 = lattice(WRAP(xl), WRAP(yl+1));
|
||||
float p10 = lattice(WRAP(xl+1), WRAP(yl));
|
||||
float p11 = lattice(WRAP(xl+1), WRAP(yl+1));
|
||||
#undef WRAP
|
||||
float p00 = lattice(xl, yl); // lattice values
|
||||
float p01 = lattice(xl, yl+1);
|
||||
float p10 = lattice(xl+1, yl);
|
||||
float p11 = lattice(xl+1, yl+1);
|
||||
|
||||
float p0 = p00 * (1-yfrac) + p01 * yfrac;
|
||||
float p1 = p10 * (1-yfrac) + p11 * yfrac;
|
||||
|
|
|
@ -179,6 +179,15 @@ FGInterface::common_init ()
|
|||
double slr = SGGeodesy::SGGeodToSeaLevelRadius(geodetic_position_v);
|
||||
_set_Sea_level_radius( slr * SG_METER_TO_FEET );
|
||||
|
||||
// Set initial Euler angles
|
||||
SG_LOG( SG_FLIGHT, SG_INFO, "...initializing Euler angles..." );
|
||||
set_Euler_Angles( fgGetDouble("/sim/presets/roll-deg")
|
||||
* SGD_DEGREES_TO_RADIANS,
|
||||
fgGetDouble("/sim/presets/pitch-deg")
|
||||
* SGD_DEGREES_TO_RADIANS,
|
||||
fgGetDouble("/sim/presets/heading-deg")
|
||||
* SGD_DEGREES_TO_RADIANS );
|
||||
|
||||
// Set initial velocities
|
||||
SG_LOG( SG_FLIGHT, SG_INFO, "...initializing velocities..." );
|
||||
if ( !fgHasNode("/sim/presets/speed-set") ) {
|
||||
|
@ -207,14 +216,11 @@ FGInterface::common_init ()
|
|||
}
|
||||
}
|
||||
|
||||
// Set initial Euler angles
|
||||
SG_LOG( SG_FLIGHT, SG_INFO, "...initializing Euler angles..." );
|
||||
set_Euler_Angles( fgGetDouble("/sim/presets/roll-deg")
|
||||
* SGD_DEGREES_TO_RADIANS,
|
||||
fgGetDouble("/sim/presets/pitch-deg")
|
||||
* SGD_DEGREES_TO_RADIANS,
|
||||
fgGetDouble("/sim/presets/heading-deg")
|
||||
* SGD_DEGREES_TO_RADIANS );
|
||||
if ( fgHasNode("/sim/presets/glideslope-deg") )
|
||||
set_Gamma_vert_rad( fgGetDouble("/sim/presets/glideslope-deg")
|
||||
* SGD_DEGREES_TO_RADIANS );
|
||||
else if ( fgHasNode( "/velocities/vertical-speed-fps") )
|
||||
set_Climb_Rate( fgGetDouble("/velocities/vertical-speed-fps") );
|
||||
|
||||
SG_LOG( SG_FLIGHT, SG_INFO, "End common FDM init" );
|
||||
}
|
||||
|
@ -251,7 +257,7 @@ FGInterface::bind ()
|
|||
false);
|
||||
fgSetArchivable("/position/altitude-ft");
|
||||
fgTie("/position/altitude-agl-ft", this,
|
||||
&FGInterface::get_Altitude_AGL, &FGInterface::set_AltitudeAGL);
|
||||
&FGInterface::get_Altitude_AGL, &FGInterface::set_AltitudeAGL, false);
|
||||
fgSetArchivable("/position/ground-elev-ft");
|
||||
fgTie("/position/ground-elev-ft", this,
|
||||
&FGInterface::get_Runway_altitude); // read-only
|
||||
|
@ -263,7 +269,7 @@ FGInterface::bind ()
|
|||
fgSetArchivable("/position/sea-level-radius-ft");
|
||||
fgTie("/position/sea-level-radius-ft", this,
|
||||
&FGInterface::get_Sea_level_radius,
|
||||
&FGInterface::_set_Sea_level_radius);
|
||||
&FGInterface::_set_Sea_level_radius, false);
|
||||
|
||||
// Orientation
|
||||
fgTie("/orientation/roll-deg", this,
|
||||
|
@ -279,24 +285,27 @@ FGInterface::bind ()
|
|||
&FGInterface::set_Psi_deg, false);
|
||||
fgSetArchivable("/orientation/heading-deg");
|
||||
fgTie("/orientation/track-deg", this,
|
||||
&FGInterface::get_Track);
|
||||
&FGInterface::get_Track); // read-only
|
||||
|
||||
// Body-axis "euler rates" (rotation speed, but in a funny
|
||||
// representation).
|
||||
fgTie("/orientation/roll-rate-degps", this,
|
||||
&FGInterface::get_Phi_dot_degps, &FGInterface::set_Phi_dot_degps);
|
||||
&FGInterface::get_Phi_dot_degps,
|
||||
&FGInterface::set_Phi_dot_degps, false);
|
||||
fgTie("/orientation/pitch-rate-degps", this,
|
||||
&FGInterface::get_Theta_dot_degps, &FGInterface::set_Theta_dot_degps);
|
||||
&FGInterface::get_Theta_dot_degps,
|
||||
&FGInterface::set_Theta_dot_degps, false);
|
||||
fgTie("/orientation/yaw-rate-degps", this,
|
||||
&FGInterface::get_Psi_dot_degps, &FGInterface::set_Psi_dot_degps);
|
||||
&FGInterface::get_Psi_dot_degps,
|
||||
&FGInterface::set_Psi_dot_degps, false);
|
||||
|
||||
fgTie("/orientation/p-body", this, &FGInterface::get_P_body);
|
||||
fgTie("/orientation/q-body", this, &FGInterface::get_Q_body);
|
||||
fgTie("/orientation/r-body", this, &FGInterface::get_R_body);
|
||||
fgTie("/orientation/p-body", this, &FGInterface::get_P_body); // read-only
|
||||
fgTie("/orientation/q-body", this, &FGInterface::get_Q_body); // read-only
|
||||
fgTie("/orientation/r-body", this, &FGInterface::get_R_body); // read-only
|
||||
|
||||
// Ground speed knots
|
||||
fgTie("/velocities/groundspeed-kt", this,
|
||||
&FGInterface::get_V_ground_speed_kt);
|
||||
&FGInterface::get_V_ground_speed_kt); // read-only
|
||||
|
||||
// Calibrated airspeed
|
||||
fgTie("/velocities/airspeed-kt", this,
|
||||
|
@ -305,7 +314,7 @@ FGInterface::bind ()
|
|||
false);
|
||||
|
||||
fgTie("/velocities/equivalent-kt", this,
|
||||
&FGInterface::get_V_equiv_kts);
|
||||
&FGInterface::get_V_equiv_kts); // read-only
|
||||
|
||||
// Mach number
|
||||
fgTie("/velocities/mach", this,
|
||||
|
@ -338,11 +347,11 @@ FGInterface::bind ()
|
|||
&FGInterface::get_V_down, &FGInterface::set_V_down, false);
|
||||
|
||||
fgTie("/velocities/north-relground-fps", this,
|
||||
&FGInterface::get_V_north_rel_ground);
|
||||
&FGInterface::get_V_north_rel_ground); // read-only
|
||||
fgTie("/velocities/east-relground-fps", this,
|
||||
&FGInterface::get_V_east_rel_ground);
|
||||
&FGInterface::get_V_east_rel_ground); // read-only
|
||||
fgTie("/velocities/down-relground-fps", this,
|
||||
&FGInterface::get_V_down_rel_ground);
|
||||
&FGInterface::get_V_down_rel_ground); // read-only
|
||||
|
||||
|
||||
// Relative wind
|
||||
|
@ -367,36 +376,37 @@ FGInterface::bind ()
|
|||
// Climb and slip (read-only)
|
||||
fgTie("/velocities/vertical-speed-fps", this,
|
||||
&FGInterface::get_Climb_Rate,
|
||||
&FGInterface::set_Climb_Rate );
|
||||
&FGInterface::set_Climb_Rate, false );
|
||||
fgTie("/velocities/glideslope", this,
|
||||
&FGInterface::get_Gamma_vert_rad,
|
||||
&FGInterface::set_Gamma_vert_rad );
|
||||
&FGInterface::set_Gamma_vert_rad, false );
|
||||
fgTie("/orientation/side-slip-rad", this,
|
||||
&FGInterface::get_Beta, &FGInterface::_set_Beta);
|
||||
&FGInterface::get_Beta, &FGInterface::_set_Beta, false);
|
||||
fgTie("/orientation/side-slip-deg", this,
|
||||
&FGInterface::get_Beta_deg); // read-only
|
||||
fgTie("/orientation/alpha-deg", this,
|
||||
&FGInterface::get_Alpha_deg, &FGInterface::set_Alpha_deg); // read-only
|
||||
&FGInterface::get_Alpha_deg, &FGInterface::set_Alpha_deg, false);
|
||||
fgTie("/accelerations/nlf", this,
|
||||
&FGInterface::get_Nlf); // read-only
|
||||
|
||||
// NED accelerations
|
||||
fgTie("/accelerations/ned/north-accel-fps_sec",
|
||||
this, &FGInterface::get_V_dot_north);
|
||||
this, &FGInterface::get_V_dot_north); // read-only
|
||||
fgTie("/accelerations/ned/east-accel-fps_sec",
|
||||
this, &FGInterface::get_V_dot_east);
|
||||
this, &FGInterface::get_V_dot_east); // read-only
|
||||
fgTie("/accelerations/ned/down-accel-fps_sec",
|
||||
this, &FGInterface::get_V_dot_down);
|
||||
this, &FGInterface::get_V_dot_down); // read-only
|
||||
|
||||
// Pilot accelerations
|
||||
fgTie("/accelerations/pilot/x-accel-fps_sec",
|
||||
this, &FGInterface::get_A_X_pilot, &FGInterface::set_A_X_pilot);
|
||||
this, &FGInterface::get_A_X_pilot, &FGInterface::set_A_X_pilot, false);
|
||||
fgTie("/accelerations/pilot/y-accel-fps_sec",
|
||||
this, &FGInterface::get_A_Y_pilot, &FGInterface::set_A_Y_pilot);
|
||||
this, &FGInterface::get_A_Y_pilot, &FGInterface::set_A_Y_pilot, false);
|
||||
fgTie("/accelerations/pilot/z-accel-fps_sec",
|
||||
this, &FGInterface::get_A_Z_pilot, &FGInterface::set_A_Z_pilot);
|
||||
this, &FGInterface::get_A_Z_pilot, &FGInterface::set_A_Z_pilot, false);
|
||||
|
||||
fgTie("/accelerations/n-z-cg-fps_sec", this, &FGInterface::get_N_Z_cg);
|
||||
fgTie("/accelerations/n-z-cg-fps_sec",
|
||||
this, &FGInterface::get_N_Z_cg); // read-only
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#cmakedefine HAVE_SYS_TIME_H
|
||||
#cmakedefine HAVE_WINDOWS_H
|
||||
#cmakedefine HAVE_CULLSETTINGS_CLEAR_MASK
|
||||
#cmakedefine HAVE_MKFIFO
|
||||
|
||||
#define VERSION "@FLIGHTGEAR_VERSION@"
|
||||
|
||||
|
|
|
@ -27,58 +27,14 @@
|
|||
|
||||
#include "kln89_page_apt.hxx"
|
||||
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <cassert>
|
||||
|
||||
#include <ATCDCL/commlist.hxx>
|
||||
#include <ATC/CommStation.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
#include <Airports/runways.hxx>
|
||||
#include <Airports/simple.hxx>
|
||||
|
||||
// This function is copied from Airports/runways.cxx
|
||||
// TODO - Make the original properly available and remove this instance!!!!
|
||||
// Return reverse rwy number
|
||||
// eg 01 -> 19
|
||||
// 03L -> 21R
|
||||
static string GetReverseRunwayNo(string rwyno) {
|
||||
// cout << "Original rwyno = " << rwyNo << '\n';
|
||||
|
||||
// standardize input number
|
||||
string tmp = rwyno.substr(1, 1);
|
||||
if (( tmp == "L" || tmp == "R" || tmp == "C" ) || (rwyno.size() == 1)) {
|
||||
tmp = rwyno;
|
||||
rwyno = "0" + tmp;
|
||||
SG_LOG( SG_GENERAL, SG_INFO,
|
||||
"Standardising rwy number from " << tmp << " to " << rwyno );
|
||||
}
|
||||
|
||||
char buf[4];
|
||||
int rn = atoi(rwyno.substr(0,2).c_str());
|
||||
rn += 18;
|
||||
while(rn > 36) {
|
||||
rn -= 36;
|
||||
}
|
||||
sprintf(buf, "%02i", rn);
|
||||
if(rwyno.size() == 3) {
|
||||
if(rwyno.substr(2,1) == "L") {
|
||||
buf[2] = 'R';
|
||||
buf[3] = '\0';
|
||||
} else if (rwyno.substr(2,1) == "R") {
|
||||
buf[2] = 'L';
|
||||
buf[3] = '\0';
|
||||
} else if (rwyno.substr(2,1) == "C") {
|
||||
buf[2] = 'C';
|
||||
buf[3] = '\0';
|
||||
} else if (rwyno.substr(2,1) == "T") {
|
||||
buf[2] = 'T';
|
||||
buf[3] = '\0';
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Unknown runway code "
|
||||
<< rwyno << " passed to GetReverseRunwayNo(...)");
|
||||
}
|
||||
}
|
||||
return(buf);
|
||||
}
|
||||
|
||||
KLN89AptPage::KLN89AptPage(KLN89* parent)
|
||||
: KLN89Page(parent) {
|
||||
_nSubPages = 8;
|
||||
|
@ -230,7 +186,8 @@ void KLN89AptPage::Update(double dt) {
|
|||
string s = _aptRwys[i]->ident();
|
||||
_kln89->DrawText(s, 2, 9, 3);
|
||||
_kln89->DrawText("/", 2, 12, 3);
|
||||
_kln89->DrawText(GetReverseRunwayNo(s), 2, 13, 3);
|
||||
string recipIdent = _aptRwys[i]->reciprocalRunway()->ident();
|
||||
_kln89->DrawText(recipIdent, 2, 13, 3);
|
||||
// Length
|
||||
s = GPSitoa(int(float(_aptRwys[i]->lengthFt()) * (_kln89->_altUnits == GPS_ALT_UNITS_FT ? 1.0 : SG_FEET_TO_METER) + 0.5));
|
||||
_kln89->DrawText(s, 2, 5 - s.size(), 2);
|
||||
|
@ -278,7 +235,8 @@ void KLN89AptPage::Update(double dt) {
|
|||
string s = _aptRwys[i]->ident();
|
||||
_kln89->DrawText(s, 2, 9, 1);
|
||||
_kln89->DrawText("/", 2, 12, 1);
|
||||
_kln89->DrawText(GetReverseRunwayNo(s), 2, 13, 1);
|
||||
string recip = _aptRwys[i]->reciprocalRunway()->ident();
|
||||
_kln89->DrawText(recip, 2, 13, 1);
|
||||
// Length
|
||||
s = GPSitoa(int(float(_aptRwys[i]->lengthFt()) * (_kln89->_altUnits == GPS_ALT_UNITS_FT ? 1.0 : SG_FEET_TO_METER) + 0.5));
|
||||
_kln89->DrawText(s, 2, 5 - s.size(), 0);
|
||||
|
@ -499,38 +457,35 @@ void KLN89AptPage::SetId(const string& s) {
|
|||
// Update the cached airport details
|
||||
void KLN89AptPage::UpdateAirport(const string& id) {
|
||||
// Frequencies
|
||||
_aptFreqs.clear();
|
||||
ATCData ad;
|
||||
AptFreq aq;
|
||||
//cout << "UpdateAirport called, id = " << id << '\n';
|
||||
// TODO - the logic below only returns one service per type per airport - they can be on more than one freq though.
|
||||
if(current_commlist->FindByCode(id, ad, ATIS)) {
|
||||
//cout << "Found ATIS\n";
|
||||
aq.service = "ATIS*";
|
||||
aq.freq = ad.freq;
|
||||
_aptFreqs.push_back(aq);
|
||||
}
|
||||
if(current_commlist->FindByCode(id, ad, GROUND)) {
|
||||
aq.service = "GRND*";
|
||||
aq.freq = ad.freq;
|
||||
_aptFreqs.push_back(aq);
|
||||
}
|
||||
if(current_commlist->FindByCode(id, ad, TOWER)) {
|
||||
aq.service = "TWR *";
|
||||
aq.freq = ad.freq;
|
||||
_aptFreqs.push_back(aq);
|
||||
}
|
||||
if(current_commlist->FindByCode(id, ad, APPROACH)) {
|
||||
aq.service = "APR";
|
||||
aq.freq = ad.freq;
|
||||
_aptFreqs.push_back(aq);
|
||||
}
|
||||
_aptFreqs.clear();
|
||||
|
||||
const FGAirport* apt = fgFindAirportID(id);
|
||||
if (!apt) {
|
||||
throw sg_exception("UpdateAirport: unknown airport id " + id);
|
||||
}
|
||||
|
||||
for (unsigned int c=0; c<apt->commStations().size(); ++c) {
|
||||
flightgear::CommStation* comm = apt->commStations()[c];
|
||||
AptFreq aq;
|
||||
aq.freq = comm->freqKHz();
|
||||
switch (comm->type()) {
|
||||
case FGPositioned::FREQ_ATIS:
|
||||
aq.service = "ATIS*"; break;
|
||||
case FGPositioned::FREQ_GROUND:
|
||||
aq.service = "GRND*"; break;
|
||||
case FGPositioned::FREQ_TOWER:
|
||||
aq.service = "TWR *"; break;
|
||||
case FGPositioned::FREQ_APP_DEP:
|
||||
aq.service = "APR *"; break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
_nFreqPages = (unsigned int)ceil((float(_aptFreqs.size())) / 3.0f);
|
||||
|
||||
// Runways
|
||||
_aptRwys.clear();
|
||||
const FGAirport* apt = fgFindAirportID(id);
|
||||
assert(apt);
|
||||
|
||||
// build local array, longest runway first
|
||||
for (unsigned int r=0; r<apt->numRunways(); ++r) {
|
||||
|
|
|
@ -52,26 +52,30 @@ WindowBuilder::makeDefaultTraits(bool stencil)
|
|||
{
|
||||
GraphicsContext::WindowingSystemInterface* wsi
|
||||
= osg::GraphicsContext::getWindowingSystemInterface();
|
||||
int w = fgGetInt("/sim/startup/xsize");
|
||||
int h = fgGetInt("/sim/startup/ysize");
|
||||
int bpp = fgGetInt("/sim/rendering/bits-per-pixel");
|
||||
bool alpha = fgGetBool("/sim/rendering/clouds3d-enable");
|
||||
bool fullscreen = fgGetBool("/sim/startup/fullscreen");
|
||||
|
||||
GraphicsContext::Traits* traits = new osg::GraphicsContext::Traits;
|
||||
|
||||
traits->readDISPLAY();
|
||||
if (traits->displayNum < 0)
|
||||
traits->displayNum = 0;
|
||||
if (traits->screenNum < 0)
|
||||
traits->screenNum = 0;
|
||||
|
||||
int bpp = fgGetInt("/sim/rendering/bits-per-pixel");
|
||||
bool alpha = fgGetBool("/sim/rendering/clouds3d-enable");
|
||||
int cbits = (bpp <= 16) ? 5 : 8;
|
||||
int zbits = (bpp <= 16) ? 16 : 24;
|
||||
traits->red = traits->green = traits->blue = cbits;
|
||||
traits->depth = zbits;
|
||||
if (alpha)
|
||||
traits->alpha = 8;
|
||||
traits->alpha = 8;
|
||||
|
||||
if (stencil)
|
||||
traits->stencil = 8;
|
||||
traits->stencil = 8;
|
||||
|
||||
unsigned screenwidth = 0;
|
||||
unsigned screenheight = 0;
|
||||
wsi->getScreenResolution(*traits, screenwidth, screenheight);
|
||||
|
||||
traits->doubleBuffer = true;
|
||||
traits->mipMapGeneration = true;
|
||||
traits->windowName = "FlightGear";
|
||||
|
@ -79,25 +83,25 @@ WindowBuilder::makeDefaultTraits(bool stencil)
|
|||
traits->sampleBuffers = fgGetBool("/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
|
||||
traits->samples = fgGetInt("/sim/rendering/multi-samples", traits->samples);
|
||||
traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync);
|
||||
if (fullscreen) {
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
wsi->getScreenResolution(*traits, width, height);
|
||||
traits->windowDecoration = false;
|
||||
traits->width = width;
|
||||
traits->height = height;
|
||||
traits->windowDecoration = !fgGetBool("/sim/startup/fullscreen");
|
||||
|
||||
if (!traits->windowDecoration) {
|
||||
// fullscreen
|
||||
traits->supportsResize = false;
|
||||
traits->width = screenwidth;
|
||||
traits->height = screenheight;
|
||||
} else {
|
||||
traits->windowDecoration = true;
|
||||
// window
|
||||
int w = fgGetInt("/sim/startup/xsize");
|
||||
int h = fgGetInt("/sim/startup/ysize");
|
||||
traits->supportsResize = true;
|
||||
traits->width = w;
|
||||
traits->height = h;
|
||||
#if defined(WIN32) || defined(__APPLE__)
|
||||
// Ugly Hack, why does CW_USEDEFAULT works like phase of the moon?
|
||||
// Mac also needs this to show window frame, menubar and Docks
|
||||
traits->x = 100;
|
||||
traits->y = 100;
|
||||
#endif
|
||||
traits->supportsResize = true;
|
||||
if ((w>0)&&(h>0))
|
||||
{
|
||||
traits->x = ((unsigned)w>screenwidth) ? 0 : (screenwidth-w)/3;
|
||||
traits->y = ((unsigned)h>screenheight) ? 0 : (screenheight-h)/3;
|
||||
}
|
||||
}
|
||||
return traits;
|
||||
}
|
||||
|
@ -165,8 +169,11 @@ GraphicsWindow* WindowBuilder::buildWindow(const SGPropertyNode* winNode)
|
|||
int traitsSet = setFromProperty(traits->hostName, winNode, "host-name");
|
||||
traitsSet |= setFromProperty(traits->displayNum, winNode, "display");
|
||||
traitsSet |= setFromProperty(traits->screenNum, winNode, "screen");
|
||||
|
||||
const SGPropertyNode* fullscreenNode = winNode->getNode("fullscreen");
|
||||
|
||||
if (fullscreenNode && fullscreenNode->getBoolValue()) {
|
||||
// fullscreen mode
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
wsi->getScreenResolution(*traits, width, height);
|
||||
|
@ -174,9 +181,16 @@ GraphicsWindow* WindowBuilder::buildWindow(const SGPropertyNode* winNode)
|
|||
traits->width = width;
|
||||
traits->height = height;
|
||||
traits->supportsResize = false;
|
||||
traits->x = 0;
|
||||
traits->y = 0;
|
||||
traitsSet = 1;
|
||||
} else {
|
||||
int resizable = 0;
|
||||
if (fullscreenNode && !fullscreenNode->getBoolValue())
|
||||
{
|
||||
traits->windowDecoration = true;
|
||||
resizable = 1;
|
||||
}
|
||||
resizable |= setFromProperty(traits->windowDecoration, winNode,
|
||||
"decoration");
|
||||
resizable |= setFromProperty(traits->width, winNode, "width");
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
#include <Scripting/NasalSys.hxx>
|
||||
#include <Sound/sample_queue.hxx>
|
||||
#include <Airports/xmlloader.hxx>
|
||||
#include <ATC/CommStation.hxx>
|
||||
#include <Navaids/navrecord.hxx>
|
||||
#include <Navaids/navlist.hxx>
|
||||
|
||||
#include "fg_init.hxx"
|
||||
#include "fg_io.hxx"
|
||||
|
@ -1349,7 +1352,63 @@ do_release_cockpit_button (const SGPropertyNode *arg)
|
|||
return true;
|
||||
}
|
||||
|
||||
static SGGeod commandSearchPos(const SGPropertyNode* arg)
|
||||
{
|
||||
if (arg->hasChild("longitude-deg") && arg->hasChild("latitude-deg")) {
|
||||
return SGGeod::fromDeg(arg->getDoubleValue("longitude-deg"),
|
||||
arg->getDoubleValue("latitude-deg"));
|
||||
}
|
||||
|
||||
// use current viewer/aircraft position
|
||||
return SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"),
|
||||
fgGetDouble("/position/latitude-deg"));
|
||||
}
|
||||
|
||||
static bool
|
||||
do_comm_search(const SGPropertyNode* arg)
|
||||
{
|
||||
SGGeod pos = commandSearchPos(arg);
|
||||
int khz = static_cast<int>(arg->getDoubleValue("frequency-mhz") * 100.0 + 0.25);
|
||||
|
||||
flightgear::CommStation* sta = flightgear::CommStation::findByFreq(khz, pos, NULL);
|
||||
if (!sta) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SGPropertyNode* result = fgGetNode(arg->getStringValue("result"));
|
||||
sta->createBinding(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
do_nav_search(const SGPropertyNode* arg)
|
||||
{
|
||||
SGGeod pos = commandSearchPos(arg);
|
||||
double mhz = arg->getDoubleValue("frequency-mhz");
|
||||
|
||||
FGNavList* navList = globals->get_navlist();
|
||||
string type(arg->getStringValue("type", "vor"));
|
||||
if (type == "dme") {
|
||||
navList = globals->get_dmelist();
|
||||
} else if (type == "tacan") {
|
||||
navList = globals->get_tacanlist();
|
||||
}
|
||||
|
||||
FGNavRecord* nav = navList->findByFreq(mhz, pos);
|
||||
if (!nav && (type == "vor")) {
|
||||
// if we're searching VORs, look for localizers too
|
||||
nav = globals->get_loclist()->findByFreq(mhz, pos);
|
||||
}
|
||||
|
||||
if (!nav) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SGPropertyNode* result = fgGetNode(arg->getStringValue("result"));
|
||||
nav->createBinding(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Command setup.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1421,6 +1480,10 @@ static struct {
|
|||
{ "dump-terrainbranch", do_dump_terrain_branch },
|
||||
{ "print-visible-scene", do_print_visible_scene_info },
|
||||
{ "reload-shaders", do_reload_shaders },
|
||||
|
||||
{ "find-navaid", do_nav_search },
|
||||
{ "find-comm", do_comm_search },
|
||||
|
||||
{ 0, 0 } // zero-terminated
|
||||
};
|
||||
|
||||
|
|
|
@ -75,8 +75,6 @@
|
|||
#include <AIModel/AIManager.hxx>
|
||||
|
||||
#include <ATCDCL/ATCmgr.hxx>
|
||||
#include <ATCDCL/commlist.hxx>
|
||||
#include <ATC/atis_mgr.hxx>
|
||||
|
||||
#include <Autopilot/route_mgr.hxx>
|
||||
#include <Autopilot/autopilotgroup.hxx>
|
||||
|
@ -1084,15 +1082,10 @@ fgInitNav ()
|
|||
SGPath p_metar( globals->get_fg_root() );
|
||||
p_metar.append( "Airports/metar.dat" );
|
||||
|
||||
// Initialise the frequency search map BEFORE reading
|
||||
// the airport database:
|
||||
|
||||
|
||||
|
||||
current_commlist = new FGCommList;
|
||||
current_commlist->init( globals->get_fg_root() );
|
||||
fgAirportDBLoad( aptdb.str(), current_commlist, p_metar.str() );
|
||||
|
||||
fgAirportDBLoad( aptdb.str(), p_metar.str() );
|
||||
FGAirport::installPropertyListener();
|
||||
FGPositioned::installCommands();
|
||||
|
||||
FGNavList *navlist = new FGNavList;
|
||||
FGNavList *loclist = new FGNavList;
|
||||
FGNavList *gslist = new FGNavList;
|
||||
|
@ -1423,12 +1416,6 @@ bool fgInitSubsystems() {
|
|||
globals->set_ATC_mgr(new FGATCMgr);
|
||||
globals->get_ATC_mgr()->init();
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Initialise the ATIS Manager
|
||||
////////////////////////////////////////////////////////////////////
|
||||
globals->add_subsystem("atis", new FGAtisManager, SGSubsystemMgr::POST_FDM);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Initialize multiplayer subsystem
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
#include <Network/ray.hxx>
|
||||
#include <Network/rul.hxx>
|
||||
#include <Network/generic.hxx>
|
||||
#include <Network/multiplay.hxx>
|
||||
|
||||
#ifdef FG_HAVE_HLA
|
||||
#include <Network/HLA/hla.hxx>
|
||||
#endif
|
||||
|
@ -219,10 +219,23 @@ FGIO::parse_port_config( const string& config )
|
|||
return NULL;
|
||||
}
|
||||
string dir = tokens[1];
|
||||
string rate = tokens[2];
|
||||
int rate = atoi(tokens[2].c_str());
|
||||
string host = tokens[3];
|
||||
string port = tokens[4];
|
||||
return new FGMultiplay(dir, atoi(rate.c_str()), host, atoi(port.c_str()));
|
||||
|
||||
short port = atoi(tokens[4].c_str());
|
||||
|
||||
// multiplay used to be handled by an FGProtocol, but no longer. This code
|
||||
// retains compatability with existing command-line syntax
|
||||
fgSetInt("/sim/multiplay/tx-rate-hz", rate);
|
||||
if (dir == "in") {
|
||||
fgSetInt("/sim/multiplay/rxport", port);
|
||||
fgSetString("/sim/multiplay/rxhost", host.c_str());
|
||||
} else if (dir == "out") {
|
||||
fgSetInt("/sim/multiplay/txport", port);
|
||||
fgSetString("/sim/multiplay/txhost", host.c_str());
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#ifdef FG_HAVE_HLA
|
||||
} else if ( protocol == "hla" ) {
|
||||
return new FGHLA(tokens);
|
||||
|
@ -343,20 +356,20 @@ FGIO::init()
|
|||
// appropriate FGIOChannel structures
|
||||
string_list::iterator i = globals->get_channel_options_list()->begin();
|
||||
string_list::iterator end = globals->get_channel_options_list()->end();
|
||||
for (; i != end; ++i )
|
||||
{
|
||||
p = parse_port_config( *i );
|
||||
if ( p != NULL ) {
|
||||
p->open();
|
||||
io_channels.push_back( p );
|
||||
if ( !p->is_enabled() ) {
|
||||
SG_LOG( SG_IO, SG_ALERT, "I/O Channel config failed." );
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
SG_LOG( SG_IO, SG_INFO, "I/O Channel parse failed." );
|
||||
}
|
||||
}
|
||||
for (; i != end; ++i ) {
|
||||
p = parse_port_config( *i );
|
||||
if (!p) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p->open();
|
||||
if ( !p->is_enabled() ) {
|
||||
SG_LOG( SG_IO, SG_ALERT, "I/O Channel config failed." );
|
||||
delete p;
|
||||
}
|
||||
|
||||
io_channels.push_back( p );
|
||||
} // of channel options iteration
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -612,16 +612,17 @@ int fgMainInit( int argc, char **argv ) {
|
|||
fgInitFGRoot(argc, argv);
|
||||
|
||||
// Check for the correct base package version
|
||||
static char required_version[] = "2.0.0";
|
||||
static char required_version[] = "2.3.0";
|
||||
string base_version = fgBasePackageVersion();
|
||||
if ( !(base_version == required_version) ) {
|
||||
// tell the operator how to use this application
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "" ); // To popup the console on windows
|
||||
cerr << endl << "Base package check failed ... " \
|
||||
<< "Found version " << base_version << " at: " \
|
||||
<< globals->get_fg_root() << endl;
|
||||
cerr << "Please upgrade to version: " << required_version << endl;
|
||||
cerr << endl << "Base package check failed:" << endl \
|
||||
<< " Version " << base_version << " found at: " \
|
||||
<< globals->get_fg_root() << endl \
|
||||
<< " Version " << required_version << " is required." << endl \
|
||||
<< "Please upgrade/downgrade base package." << endl;
|
||||
#ifdef _MSC_VER
|
||||
cerr << "Hit a key to continue..." << endl;
|
||||
cin.get();
|
||||
|
|
|
@ -1838,7 +1838,7 @@ fgUsage (bool verbose)
|
|||
|
||||
while ( t_str.size() > 47 ) {
|
||||
|
||||
unsigned int m = t_str.rfind(' ', 47);
|
||||
string::size_type m = t_str.rfind(' ', 47);
|
||||
msg += t_str.substr(0, m) + '\n';
|
||||
msg.append( 32, ' ');
|
||||
|
||||
|
|
|
@ -356,7 +356,7 @@ FGViewMgr::update (double dt)
|
|||
abs_viewer_position = loop_view->getViewPosition();
|
||||
|
||||
// update audio listener values
|
||||
// set the viewer posotion in Cartesian coordinates in meters
|
||||
// set the viewer position in Cartesian coordinates in meters
|
||||
smgr->set_position( abs_viewer_position, loop_view->getPosition() );
|
||||
smgr->set_orientation( current_view_orientation );
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ struct FGExternalMotionData {
|
|||
// the earth centered frame
|
||||
SGVec3f angularAccel;
|
||||
|
||||
// The set of properties recieved for this timeslot
|
||||
// The set of properties received for this timeslot
|
||||
std::vector<FGPropertyData*> properties;
|
||||
|
||||
~FGExternalMotionData()
|
||||
|
|
|
@ -42,9 +42,11 @@
|
|||
#include <simgear/props/props.hxx>
|
||||
|
||||
#include <AIModel/AIManager.hxx>
|
||||
#include <AIModel/AIMultiplayer.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include "multiplaymgr.hxx"
|
||||
#include "mpmessages.hxx"
|
||||
#include <FDM/flightProperties.hxx>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -56,11 +58,18 @@ using namespace std;
|
|||
const char sMULTIPLAYMGR_BID[] = "$Id$";
|
||||
const char sMULTIPLAYMGR_HID[] = MULTIPLAYTXMGR_HID;
|
||||
|
||||
struct IdPropertyList {
|
||||
unsigned id;
|
||||
const char* name;
|
||||
simgear::props::Type type;
|
||||
};
|
||||
|
||||
static const IdPropertyList* findProperty(unsigned id);
|
||||
|
||||
// A static map of protocol property id values to property paths,
|
||||
// This should be extendable dynamically for every specific aircraft ...
|
||||
// For now only that static list
|
||||
const FGMultiplayMgr::IdPropertyList
|
||||
FGMultiplayMgr::sIdPropertyList[] = {
|
||||
static const IdPropertyList sIdPropertyList[] = {
|
||||
{100, "surface-positions/left-aileron-pos-norm", simgear::props::FLOAT},
|
||||
{101, "surface-positions/right-aileron-pos-norm", simgear::props::FLOAT},
|
||||
{102, "surface-positions/elevator-pos-norm", simgear::props::FLOAT},
|
||||
|
@ -229,34 +238,33 @@ FGMultiplayMgr::sIdPropertyList[] = {
|
|||
{10319, "sim/multiplay/generic/int[19]", simgear::props::INT}
|
||||
};
|
||||
|
||||
const unsigned
|
||||
FGMultiplayMgr::numProperties = (sizeof(FGMultiplayMgr::sIdPropertyList)
|
||||
/ sizeof(FGMultiplayMgr::sIdPropertyList[0]));
|
||||
const unsigned int numProperties = (sizeof(sIdPropertyList)
|
||||
/ sizeof(sIdPropertyList[0]));
|
||||
|
||||
// Look up a property ID using binary search.
|
||||
namespace
|
||||
{
|
||||
struct ComparePropertyId
|
||||
{
|
||||
bool operator()(const FGMultiplayMgr::IdPropertyList& lhs,
|
||||
const FGMultiplayMgr::IdPropertyList& rhs)
|
||||
bool operator()(const IdPropertyList& lhs,
|
||||
const IdPropertyList& rhs)
|
||||
{
|
||||
return lhs.id < rhs.id;
|
||||
}
|
||||
bool operator()(const FGMultiplayMgr::IdPropertyList& lhs,
|
||||
bool operator()(const IdPropertyList& lhs,
|
||||
unsigned id)
|
||||
{
|
||||
return lhs.id < id;
|
||||
}
|
||||
bool operator()(unsigned id,
|
||||
const FGMultiplayMgr::IdPropertyList& rhs)
|
||||
const IdPropertyList& rhs)
|
||||
{
|
||||
return id < rhs.id;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
const FGMultiplayMgr::IdPropertyList* FGMultiplayMgr::findProperty(unsigned id)
|
||||
|
||||
const IdPropertyList* findProperty(unsigned id)
|
||||
{
|
||||
std::pair<const IdPropertyList*, const IdPropertyList*> result
|
||||
= std::equal_range(sIdPropertyList, sIdPropertyList + numProperties, id,
|
||||
|
@ -276,8 +284,7 @@ namespace
|
|||
const xdr_data_t* xdr = data;
|
||||
while (xdr < end) {
|
||||
unsigned id = XDR_decode_uint32(*xdr);
|
||||
const FGMultiplayMgr::IdPropertyList* plist
|
||||
= FGMultiplayMgr::findProperty(id);
|
||||
const IdPropertyList* plist = findProperty(id);
|
||||
|
||||
if (plist) {
|
||||
xdr++;
|
||||
|
@ -336,6 +343,24 @@ namespace
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class MPPropertyListener : public SGPropertyChangeListener
|
||||
{
|
||||
public:
|
||||
MPPropertyListener(FGMultiplayMgr* mp) :
|
||||
_multiplay(mp)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void childAdded(SGPropertyNode*, SGPropertyNode*)
|
||||
{
|
||||
_multiplay->setPropertiesChanged();
|
||||
}
|
||||
|
||||
private:
|
||||
FGMultiplayMgr* _multiplay;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MultiplayMgr constructor
|
||||
|
@ -343,9 +368,9 @@ namespace
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
FGMultiplayMgr::FGMultiplayMgr()
|
||||
{
|
||||
mSocket = 0;
|
||||
mInitialised = false;
|
||||
mHaveServer = false;
|
||||
mListener = NULL;
|
||||
} // FGMultiplayMgr::FGMultiplayMgr()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -356,7 +381,7 @@ FGMultiplayMgr::FGMultiplayMgr()
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
FGMultiplayMgr::~FGMultiplayMgr()
|
||||
{
|
||||
Close();
|
||||
|
||||
} // FGMultiplayMgr::~FGMultiplayMgr()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -375,22 +400,36 @@ FGMultiplayMgr::init (void)
|
|||
SG_LOG(SG_NETWORK, SG_WARN, "FGMultiplayMgr::init - already initialised");
|
||||
return;
|
||||
}
|
||||
|
||||
fgSetBool("/sim/multiplay/online", false);
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Set members from property values
|
||||
//////////////////////////////////////////////////
|
||||
short rxPort = fgGetInt("/sim/multiplay/rxport");
|
||||
string rxAddress = fgGetString("/sim/multiplay/rxhost");
|
||||
short txPort = fgGetInt("/sim/multiplay/txport");
|
||||
short txPort = fgGetInt("/sim/multiplay/txport", 5000);
|
||||
string txAddress = fgGetString("/sim/multiplay/txhost");
|
||||
|
||||
int hz = fgGetInt("/sim/multiplay/tx-rate-hz", 10);
|
||||
if (hz < 1) {
|
||||
hz = 10;
|
||||
}
|
||||
|
||||
mDt = 1.0 / hz;
|
||||
mTimeUntilSend = 0.0;
|
||||
|
||||
mCallsign = fgGetString("/sim/multiplay/callsign");
|
||||
if (txPort > 0 && !txAddress.empty()) {
|
||||
if (!txAddress.empty()) {
|
||||
mServer.set(txAddress.c_str(), txPort);
|
||||
if (strncmp (mServer.getHost(), "0.0.0.0", 8) == 0) {
|
||||
mHaveServer = false;
|
||||
SG_LOG(SG_NETWORK, SG_DEBUG,
|
||||
SG_LOG(SG_NETWORK, SG_WARN,
|
||||
"FGMultiplayMgr - could not resolve '"
|
||||
<< txAddress << "', Multiplayermode disabled");
|
||||
return;
|
||||
} else {
|
||||
SG_LOG(SG_NETWORK, SG_INFO, "have server");
|
||||
mHaveServer = true;
|
||||
}
|
||||
if (rxPort <= 0)
|
||||
|
@ -408,11 +447,10 @@ FGMultiplayMgr::init (void)
|
|||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-rxaddress="<<rxAddress );
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-rxport= "<<rxPort);
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-callsign= "<<mCallsign);
|
||||
Close(); // Should Init be called twice, close Socket first
|
||||
// A memory leak was reported here by valgrind
|
||||
mSocket = new simgear::Socket();
|
||||
|
||||
mSocket.reset(new simgear::Socket());
|
||||
if (!mSocket->open(false)) {
|
||||
SG_LOG( SG_NETWORK, SG_DEBUG,
|
||||
SG_LOG( SG_NETWORK, SG_WARN,
|
||||
"FGMultiplayMgr::init - Failed to create data socket" );
|
||||
return;
|
||||
}
|
||||
|
@ -424,6 +462,11 @@ FGMultiplayMgr::init (void)
|
|||
return;
|
||||
}
|
||||
|
||||
mPropertiesChanged = true;
|
||||
mListener = new MPPropertyListener(this);
|
||||
globals->get_props()->addChangeListener(mListener, false);
|
||||
|
||||
fgSetBool("/sim/multiplay/online", true);
|
||||
mInitialised = true;
|
||||
} // FGMultiplayMgr::init()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -435,19 +478,39 @@ FGMultiplayMgr::init (void)
|
|||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::Close (void)
|
||||
FGMultiplayMgr::shutdown (void)
|
||||
{
|
||||
mMultiPlayerMap.clear();
|
||||
|
||||
if (mSocket) {
|
||||
fgSetBool("/sim/multiplay/online", false);
|
||||
|
||||
if (mSocket.get()) {
|
||||
mSocket->close();
|
||||
delete mSocket;
|
||||
mSocket = 0;
|
||||
mSocket.reset();
|
||||
}
|
||||
|
||||
MultiPlayerMap::iterator it = mMultiPlayerMap.begin(),
|
||||
end = mMultiPlayerMap.end();
|
||||
for (; it != end; ++it) {
|
||||
it->second->setDie(true);
|
||||
}
|
||||
mMultiPlayerMap.clear();
|
||||
|
||||
if (mListener) {
|
||||
globals->get_props()->removeChangeListener(mListener);
|
||||
delete mListener;
|
||||
mListener = NULL;
|
||||
}
|
||||
|
||||
mInitialised = false;
|
||||
} // FGMultiplayMgr::Close(void)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
FGMultiplayMgr::reinit()
|
||||
{
|
||||
shutdown();
|
||||
init();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Description: Sends the position data for the local position.
|
||||
|
@ -757,7 +820,7 @@ FGMultiplayMgr::SendTextMessage(const string &MsgText)
|
|||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::update(double)
|
||||
FGMultiplayMgr::update(double dt)
|
||||
{
|
||||
if (!mInitialised)
|
||||
return;
|
||||
|
@ -765,6 +828,14 @@ FGMultiplayMgr::update(double)
|
|||
/// Just for expiry
|
||||
long stamp = SGTimeStamp::now().getSeconds();
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Send if required
|
||||
//////////////////////////////////////////////////
|
||||
mTimeUntilSend -= dt;
|
||||
if (mTimeUntilSend <= 0.0) {
|
||||
Send();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Read the receive socket and process any data
|
||||
//////////////////////////////////////////////////
|
||||
|
@ -813,7 +884,7 @@ FGMultiplayMgr::update(double)
|
|||
<< "message has invalid protocol number!" );
|
||||
break;
|
||||
}
|
||||
if (MsgHdr->MsgLen != bytes) {
|
||||
if (static_cast<ssize_t>(MsgHdr->MsgLen) != bytes) {
|
||||
SG_LOG(SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::MP_ProcessData - "
|
||||
<< "message from " << MsgHdr->Callsign << " has invalid length!");
|
||||
break;
|
||||
|
@ -854,6 +925,140 @@ FGMultiplayMgr::update(double)
|
|||
} // FGMultiplayMgr::ProcessData(void)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
FGMultiplayMgr::Send()
|
||||
{
|
||||
using namespace simgear;
|
||||
|
||||
findProperties();
|
||||
|
||||
// smooth the send rate, by adjusting based on the 'remainder' time, which
|
||||
// is how -ve mTimeUntilSend is. Watch for large values and ignore them,
|
||||
// however.
|
||||
if ((mTimeUntilSend < 0.0) && (fabs(mTimeUntilSend) < mDt)) {
|
||||
mTimeUntilSend = mDt + mTimeUntilSend;
|
||||
} else {
|
||||
mTimeUntilSend = mDt;
|
||||
}
|
||||
|
||||
double sim_time = globals->get_sim_time_sec();
|
||||
static double lastTime = 0.0;
|
||||
|
||||
// SG_LOG(SG_GENERAL, SG_INFO, "actual dt=" << sim_time - lastTime);
|
||||
lastTime = sim_time;
|
||||
|
||||
FlightProperties ifce;
|
||||
|
||||
// put together a motion info struct, you will get that later
|
||||
// from FGInterface directly ...
|
||||
FGExternalMotionData motionInfo;
|
||||
|
||||
// The current simulation time we need to update for,
|
||||
// note that the simulation time is updated before calling all the
|
||||
// update methods. Thus it contains the time intervals *end* time.
|
||||
// The FDM is already run, so the states belong to that time.
|
||||
motionInfo.time = sim_time;
|
||||
motionInfo.lag = mDt;
|
||||
|
||||
// These are for now converted from lat/lon/alt and euler angles.
|
||||
// But this should change in FGInterface ...
|
||||
double lon = ifce.get_Longitude();
|
||||
double lat = ifce.get_Latitude();
|
||||
// first the aprioriate structure for the geodetic one
|
||||
SGGeod geod = SGGeod::fromRadFt(lon, lat, ifce.get_Altitude());
|
||||
// Convert to cartesion coordinate
|
||||
motionInfo.position = SGVec3d::fromGeod(geod);
|
||||
|
||||
// The quaternion rotating from the earth centered frame to the
|
||||
// horizontal local frame
|
||||
SGQuatf qEc2Hl = SGQuatf::fromLonLatRad((float)lon, (float)lat);
|
||||
// The orientation wrt the horizontal local frame
|
||||
float heading = ifce.get_Psi();
|
||||
float pitch = ifce.get_Theta();
|
||||
float roll = ifce.get_Phi();
|
||||
SGQuatf hlOr = SGQuatf::fromYawPitchRoll(heading, pitch, roll);
|
||||
// The orientation of the vehicle wrt the earth centered frame
|
||||
motionInfo.orientation = qEc2Hl*hlOr;
|
||||
|
||||
if (!globals->get_subsystem("flight")->is_suspended()) {
|
||||
// velocities
|
||||
motionInfo.linearVel = SG_FEET_TO_METER*SGVec3f(ifce.get_uBody(),
|
||||
ifce.get_vBody(),
|
||||
ifce.get_wBody());
|
||||
motionInfo.angularVel = SGVec3f(ifce.get_P_body(),
|
||||
ifce.get_Q_body(),
|
||||
ifce.get_R_body());
|
||||
|
||||
// accels, set that to zero for now.
|
||||
// Angular accelerations are missing from the interface anyway,
|
||||
// linear accelerations are screwed up at least for JSBSim.
|
||||
// motionInfo.linearAccel = SG_FEET_TO_METER*SGVec3f(ifce.get_U_dot_body(),
|
||||
// ifce.get_V_dot_body(),
|
||||
// ifce.get_W_dot_body());
|
||||
motionInfo.linearAccel = SGVec3f::zeros();
|
||||
motionInfo.angularAccel = SGVec3f::zeros();
|
||||
} else {
|
||||
// if the interface is suspendend, prevent the client from
|
||||
// wild extrapolations
|
||||
motionInfo.linearVel = SGVec3f::zeros();
|
||||
motionInfo.angularVel = SGVec3f::zeros();
|
||||
motionInfo.linearAccel = SGVec3f::zeros();
|
||||
motionInfo.angularAccel = SGVec3f::zeros();
|
||||
}
|
||||
|
||||
// now send the properties
|
||||
PropertyMap::iterator it;
|
||||
for (it = mPropertyMap.begin(); it != mPropertyMap.end(); ++it) {
|
||||
FGPropertyData* pData = new FGPropertyData;
|
||||
pData->id = it->first;
|
||||
pData->type = it->second->getType();
|
||||
|
||||
switch (pData->type) {
|
||||
case props::INT:
|
||||
case props::LONG:
|
||||
case props::BOOL:
|
||||
pData->int_value = it->second->getIntValue();
|
||||
break;
|
||||
case props::FLOAT:
|
||||
case props::DOUBLE:
|
||||
pData->float_value = it->second->getFloatValue();
|
||||
break;
|
||||
case props::STRING:
|
||||
case props::UNSPECIFIED:
|
||||
{
|
||||
// FIXME: We assume unspecified are strings for the moment.
|
||||
|
||||
const char* cstr = it->second->getStringValue();
|
||||
int len = strlen(cstr);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
pData->string_value = new char[len + 1];
|
||||
strcpy(pData->string_value, cstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Size 0 - ignore
|
||||
pData->string_value = 0;
|
||||
}
|
||||
|
||||
//cout << " Sending property " << pData->id << " " << pData->type << " " << pData->string_value << "\n";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// FIXME Currently default to a float.
|
||||
//cout << "Unknown type when iterating through props: " << pData->type << "\n";
|
||||
pData->float_value = it->second->getFloatValue();
|
||||
break;
|
||||
}
|
||||
|
||||
motionInfo.properties.push_back(pData);
|
||||
}
|
||||
|
||||
SendMyPosition(motionInfo);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// handle a position message
|
||||
|
@ -1101,3 +1306,29 @@ FGMultiplayMgr::getMultiplayer(const std::string& callsign)
|
|||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
FGMultiplayMgr::findProperties()
|
||||
{
|
||||
if (!mPropertiesChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
mPropertiesChanged = false;
|
||||
|
||||
for (unsigned i = 0; i < numProperties; ++i) {
|
||||
const char* name = sIdPropertyList[i].name;
|
||||
SGPropertyNode* pNode = globals->get_props()->getNode(name);
|
||||
if (!pNode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int id = sIdPropertyList[i].id;
|
||||
if (mPropertyMap.find(id) != mPropertyMap.end()) {
|
||||
continue; // already activated
|
||||
}
|
||||
|
||||
mPropertyMap[id] = pNode;
|
||||
SG_LOG(SG_NETWORK, SG_DEBUG, "activating MP property:" << pNode->getPath());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,48 +31,51 @@
|
|||
|
||||
#define MULTIPLAYTXMGR_HID "$Id$"
|
||||
|
||||
#include "mpmessages.hxx"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
#include <simgear/io/raw_socket.hxx>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
#include <AIModel/AIMultiplayer.hxx>
|
||||
|
||||
struct FGExternalMotionInfo;
|
||||
struct FGExternalMotionData;
|
||||
class MPPropertyListener;
|
||||
struct T_MsgHdr;
|
||||
class FGAIMultiplayer;
|
||||
|
||||
class FGMultiplayMgr : public SGSubsystem
|
||||
{
|
||||
public:
|
||||
|
||||
struct IdPropertyList {
|
||||
unsigned id;
|
||||
const char* name;
|
||||
simgear::props::Type type;
|
||||
};
|
||||
static const IdPropertyList sIdPropertyList[];
|
||||
static const unsigned numProperties;
|
||||
|
||||
static const IdPropertyList* findProperty(unsigned id);
|
||||
|
||||
public:
|
||||
FGMultiplayMgr();
|
||||
~FGMultiplayMgr();
|
||||
|
||||
virtual void init(void);
|
||||
virtual void update(double dt);
|
||||
|
||||
void Close(void);
|
||||
virtual void shutdown(void);
|
||||
virtual void reinit();
|
||||
|
||||
// transmitter
|
||||
void SendMyPosition(const FGExternalMotionData& motionInfo);
|
||||
|
||||
void SendTextMessage(const string &sMsgText);
|
||||
// receiver
|
||||
|
||||
private:
|
||||
friend class MPPropertyListener;
|
||||
|
||||
void setPropertiesChanged()
|
||||
{
|
||||
mPropertiesChanged = true;
|
||||
}
|
||||
|
||||
void findProperties();
|
||||
|
||||
void Send();
|
||||
void SendMyPosition(const FGExternalMotionData& motionInfo);
|
||||
|
||||
union MsgBuf;
|
||||
FGAIMultiplayer* addMultiplayer(const std::string& callsign,
|
||||
const std::string& modelName);
|
||||
|
@ -87,11 +90,22 @@ private:
|
|||
typedef std::map<std::string, SGSharedPtr<FGAIMultiplayer> > MultiPlayerMap;
|
||||
MultiPlayerMap mMultiPlayerMap;
|
||||
|
||||
simgear::Socket* mSocket;
|
||||
std::auto_ptr<simgear::Socket> mSocket;
|
||||
simgear::IPAddress mServer;
|
||||
bool mHaveServer;
|
||||
bool mInitialised;
|
||||
std::string mCallsign;
|
||||
|
||||
// Map between the property id's from the multiplayers network packets
|
||||
// and the property nodes
|
||||
typedef std::map<unsigned int, SGSharedPtr<SGPropertyNode> > PropertyMap;
|
||||
PropertyMap mPropertyMap;
|
||||
|
||||
bool mPropertiesChanged;
|
||||
MPPropertyListener* mListener;
|
||||
|
||||
double mDt; // reciprocal of /sim/multiplay/tx-rate-hz
|
||||
double mTimeUntilSend;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,6 +13,7 @@ set(SOURCES
|
|||
route.cxx
|
||||
routePath.cxx
|
||||
waypoint.cxx
|
||||
PositionedBinding.cxx
|
||||
)
|
||||
|
||||
flightgear_component(Navaids "${SOURCES}")
|
|
@ -13,7 +13,8 @@ libNavaids_a_SOURCES = \
|
|||
airways.hxx airways.cxx \
|
||||
route.hxx route.cxx \
|
||||
waypoint.hxx waypoint.cxx \
|
||||
procedure.hxx procedure.cxx
|
||||
procedure.hxx procedure.cxx \
|
||||
PositionedBinding.hxx PositionedBinding.cxx
|
||||
|
||||
#
|
||||
# testnavs_SOURCES = testnavs.cxx
|
||||
|
|
188
src/Navaids/PositionedBinding.cxx
Normal file
188
src/Navaids/PositionedBinding.cxx
Normal file
|
@ -0,0 +1,188 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "PositionedBinding.hxx"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Navaids/navrecord.hxx>
|
||||
#include <Airports/simple.hxx>
|
||||
#include <Airports/runways.hxx>
|
||||
#include <ATC/CommStation.hxx>
|
||||
|
||||
typedef std::map<SGPropertyNode*, flightgear::PositionedBinding*> BindingMap;
|
||||
static BindingMap static_bindings;
|
||||
|
||||
namespace {
|
||||
|
||||
class PropertyDeleteObserver : public SGPropertyChangeListener
|
||||
{
|
||||
public:
|
||||
virtual void childRemoved(SGPropertyNode*, SGPropertyNode* node)
|
||||
{
|
||||
BindingMap::iterator it = static_bindings.find(node);
|
||||
if (it != static_bindings.end()) {
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "saw remove of:" << node->getPath() << ", deleting binding");
|
||||
delete it->second;
|
||||
static_bindings.erase(it);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static PropertyDeleteObserver* static_deleteObserver = NULL;
|
||||
|
||||
} // of anonymous namespace
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
|
||||
PositionedBinding::PositionedBinding(const FGPositioned* pos, SGPropertyNode* nd) :
|
||||
p(const_cast<FGPositioned*>(pos)),
|
||||
tied(nd)
|
||||
{
|
||||
if (!static_deleteObserver) {
|
||||
static_deleteObserver = new PropertyDeleteObserver;
|
||||
globals->get_props()->addChangeListener(static_deleteObserver, false);
|
||||
}
|
||||
|
||||
nd->setDoubleValue("latitude-deg", p->latitude());
|
||||
nd->setDoubleValue("longitude-deg", p->longitude());
|
||||
|
||||
if (p->elevation() > -1000) {
|
||||
nd->setDoubleValue("elevation-ft", p->elevation());
|
||||
}
|
||||
|
||||
nd->setStringValue("ident", p->ident());
|
||||
if (!p->name().empty()) {
|
||||
nd->setStringValue("name", p->name());
|
||||
}
|
||||
|
||||
nd->setStringValue("type", FGPositioned::nameForType(p->type()));
|
||||
}
|
||||
|
||||
PositionedBinding::~PositionedBinding()
|
||||
{
|
||||
tied.Untie();
|
||||
}
|
||||
|
||||
void PositionedBinding::bind(FGPositioned* pos, SGPropertyNode* node)
|
||||
{
|
||||
BindingMap::iterator it = static_bindings.find(node);
|
||||
if (it != static_bindings.end()) {
|
||||
throw sg_exception("duplicate positioned binding", node->getPath());
|
||||
}
|
||||
|
||||
PositionedBinding* binding = pos->createBinding(node);
|
||||
static_bindings.insert(it, std::make_pair(node, binding));
|
||||
}
|
||||
|
||||
NavaidBinding::NavaidBinding(const FGNavRecord* nav, SGPropertyNode* nd) :
|
||||
PositionedBinding(nav, nd)
|
||||
{
|
||||
FGPositioned::Type ty = nav->type();
|
||||
if (ty == FGPositioned::NDB) {
|
||||
nd->setDoubleValue("frequency-khz", nav->get_freq() / 100.0);
|
||||
} else {
|
||||
nd->setDoubleValue("frequency-mhz", nav->get_freq() / 100.0);
|
||||
}
|
||||
|
||||
if ((ty == FGPositioned::LOC) || (ty == FGPositioned::ILS)) {
|
||||
nd->setDoubleValue("loc-course-deg", nav->get_multiuse());
|
||||
}
|
||||
|
||||
if (ty == FGPositioned::GS) {
|
||||
nd->setDoubleValue("gs-angle-deg", nav->get_multiuse());
|
||||
}
|
||||
|
||||
nd->setDoubleValue("range-nm", nav->get_range());
|
||||
|
||||
if (nav->runway()) {
|
||||
// don't want to create a cycle in the graph, so we don't re-bind
|
||||
// the airport/runway node here - just expose the IDs
|
||||
nd->setStringValue("airport", nav->runway()->airport()->ident());
|
||||
nd->setStringValue("runway", nav->runway()->ident());
|
||||
}
|
||||
};
|
||||
|
||||
RunwayBinding::RunwayBinding(const FGRunway* rwy, SGPropertyNode* nd) :
|
||||
PositionedBinding(rwy, nd)
|
||||
{
|
||||
nd->setDoubleValue("length-ft", rwy->lengthFt());
|
||||
nd->setDoubleValue("length-m", rwy->lengthM());
|
||||
nd->setDoubleValue("width-ft", rwy->widthFt());
|
||||
nd->setDoubleValue("width-m", rwy->widthM());
|
||||
nd->setDoubleValue("heading-deg", rwy->headingDeg());
|
||||
nd->setBoolValue("hard-surface", rwy->isHardSurface());
|
||||
|
||||
nd->setDoubleValue("threshold-displacement-m", rwy->displacedThresholdM());
|
||||
nd->setDoubleValue("stopway-m", rwy->stopwayM());
|
||||
|
||||
if (rwy->ILS()) {
|
||||
SGPropertyNode* ilsNode = nd->getChild("ils", 0, true);
|
||||
PositionedBinding::bind(rwy->ILS(), ilsNode);
|
||||
}
|
||||
}
|
||||
|
||||
AirportBinding::AirportBinding(const FGAirport* apt, SGPropertyNode* nd) :
|
||||
PositionedBinding(apt, nd)
|
||||
{
|
||||
nd->setIntValue("num-runways", apt->numRunways());
|
||||
|
||||
SGGeod tower = apt->getTowerLocation();
|
||||
nd->setDoubleValue("tower/latitude-deg", tower.getLatitudeDeg());
|
||||
nd->setDoubleValue("tower/longitude-deg", tower.getLongitudeDeg());
|
||||
nd->setDoubleValue("tower/elevation-ft", tower.getElevationFt());
|
||||
|
||||
for (unsigned int r=0; r<apt->numRunways(); ++r) {
|
||||
SGPropertyNode* rn = nd->getChild("runway", r, true);
|
||||
FGRunway* rwy = apt->getRunwayByIndex(r);
|
||||
PositionedBinding::bind(rwy, rn);
|
||||
}
|
||||
|
||||
for (unsigned int c=0; c<apt->commStations().size(); ++c) {
|
||||
flightgear::CommStation* comm = apt->commStations()[c];
|
||||
std::string tynm = FGPositioned::nameForType(comm->type());
|
||||
|
||||
// for some standard frequence types, we don't care about the ident,
|
||||
// so just list the frequencies under one group.
|
||||
if ((comm->type() == FGPositioned::FREQ_ATIS) ||
|
||||
(comm->type() == FGPositioned::FREQ_AWOS) ||
|
||||
(comm->type() == FGPositioned::FREQ_TOWER) ||
|
||||
(comm->type() == FGPositioned::FREQ_GROUND))
|
||||
{
|
||||
SGPropertyNode* commNode = nd->getChild(tynm, 0, true);
|
||||
int count = nd->getChildren("frequency-mhz").size();
|
||||
SGPropertyNode* freqNode = commNode->getChild("frequency-mhz", count, true);
|
||||
freqNode->setDoubleValue(comm->freqMHz());
|
||||
} else {
|
||||
// for other kinds of frequency, there's more variation, so list the ID too
|
||||
int count = nd->getChildren(tynm).size();
|
||||
SGPropertyNode* commNode = nd->getChild(tynm, count, true);
|
||||
commNode->setStringValue("ident", comm->ident());
|
||||
commNode->setDoubleValue("frequency-mhz", comm->freqMHz());
|
||||
|
||||
}
|
||||
} // of airprot comm stations iteration
|
||||
}
|
||||
|
||||
CommStationBinding::CommStationBinding(const CommStation* sta, SGPropertyNode* node) :
|
||||
PositionedBinding(sta, node)
|
||||
{
|
||||
node->setIntValue("range-nm", sta->rangeNm());
|
||||
node->setDoubleValue("frequency-mhz", sta->freqMHz());
|
||||
|
||||
if (sta->airport()) {
|
||||
// don't want to create a cycle in the graph, so we don't re-bind
|
||||
// the airport/runway node here - just expose the IDs
|
||||
node->setStringValue("airport", sta->airport()->ident());
|
||||
}
|
||||
}
|
||||
|
||||
} // of namespace flightgear
|
||||
|
63
src/Navaids/PositionedBinding.hxx
Normal file
63
src/Navaids/PositionedBinding.hxx
Normal file
|
@ -0,0 +1,63 @@
|
|||
#ifndef FG_POSITIONED_BINDING_HXX
|
||||
#define FG_POSITIONED_BINDING_HXX
|
||||
|
||||
#include <simgear/props/tiedpropertylist.hxx>
|
||||
|
||||
#include "positioned.hxx"
|
||||
|
||||
// forward decls
|
||||
class FGNavRecord;
|
||||
class FGRunway;
|
||||
class FGAirport;
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
|
||||
// forward decls
|
||||
class CommStation;
|
||||
|
||||
class PositionedBinding
|
||||
{
|
||||
public:
|
||||
virtual ~PositionedBinding();
|
||||
|
||||
static void bind(FGPositioned* pos, SGPropertyNode* node);
|
||||
|
||||
|
||||
PositionedBinding(const FGPositioned* pos, SGPropertyNode* node);
|
||||
|
||||
protected:
|
||||
FGPositionedRef p; // bindings own a reference to their positioned
|
||||
simgear::TiedPropertyList tied;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
class NavaidBinding : public PositionedBinding
|
||||
{
|
||||
public:
|
||||
NavaidBinding(const FGNavRecord* nav, SGPropertyNode* node);
|
||||
};
|
||||
|
||||
class RunwayBinding : public PositionedBinding
|
||||
{
|
||||
public:
|
||||
RunwayBinding(const FGRunway* rwy, SGPropertyNode* node);
|
||||
};
|
||||
|
||||
class AirportBinding : public PositionedBinding
|
||||
{
|
||||
public:
|
||||
AirportBinding(const FGAirport* apt, SGPropertyNode* node);
|
||||
};
|
||||
|
||||
class CommStationBinding : public PositionedBinding
|
||||
{
|
||||
public:
|
||||
CommStationBinding(const CommStation* sta, SGPropertyNode* node);
|
||||
};
|
||||
|
||||
} // of namespace flightgear
|
||||
|
||||
#endif // of FG_POSITIONED_BINDING_HXX
|
|
@ -41,6 +41,7 @@
|
|||
#include <Airports/xmlloader.hxx>
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Navaids/PositionedBinding.hxx>
|
||||
|
||||
FGNavRecord::FGNavRecord(Type aTy, const std::string& aIdent,
|
||||
const std::string& aName, const SGGeod& aPos,
|
||||
|
@ -187,6 +188,13 @@ double FGNavRecord::localizerWidth() const
|
|||
|
||||
}
|
||||
|
||||
flightgear::PositionedBinding*
|
||||
FGNavRecord::createBinding(SGPropertyNode* nd) const
|
||||
{
|
||||
return new flightgear::NavaidBinding(this, nd);
|
||||
}
|
||||
|
||||
|
||||
FGTACANRecord::FGTACANRecord(void) :
|
||||
channel(""),
|
||||
freq(0)
|
||||
|
|
|
@ -89,12 +89,17 @@ public:
|
|||
*/
|
||||
FGRunway* runway() const { return mRunway; }
|
||||
|
||||
virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const;
|
||||
|
||||
/**
|
||||
* return the localizer width, in degrees
|
||||
* computation is based up ICAO stdandard width at the runway threshold
|
||||
* see implementation for further details.
|
||||
*/
|
||||
double localizerWidth() const;
|
||||
|
||||
void bindToNode(SGPropertyNode* nd) const;
|
||||
void unbindFromNode(SGPropertyNode* nd) const;
|
||||
};
|
||||
|
||||
class FGTACANRecord : public SGReferenced {
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <set>
|
||||
#include <algorithm> // for sort
|
||||
#include <queue>
|
||||
#include <memory>
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
@ -35,11 +36,16 @@
|
|||
#include <osg/Math> // for osg::isNaN
|
||||
|
||||
#include <simgear/timing/timestamp.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/math/SGGeometry.hxx>
|
||||
#include <simgear/sg_inlines.h>
|
||||
#include <simgear/structure/commands.hxx>
|
||||
|
||||
|
||||
#include "PositionedBinding.hxx"
|
||||
#include "Airports/simple.hxx"
|
||||
#include "Main/fg_props.hxx"
|
||||
|
||||
typedef std::multimap<std::string, FGPositioned*> NamedPositionedIndex;
|
||||
typedef std::pair<NamedPositionedIndex::const_iterator, NamedPositionedIndex::const_iterator> NamedIndexRange;
|
||||
|
@ -628,7 +634,15 @@ FGPositioned::Type FGPositioned::typeFromName(const std::string& aName)
|
|||
{"fix", FIX},
|
||||
{"tacan", TACAN},
|
||||
{"dme", DME},
|
||||
{"atis", FREQ_ATIS},
|
||||
{"awos", FREQ_AWOS},
|
||||
{"tower", FREQ_TOWER},
|
||||
{"ground", FREQ_GROUND},
|
||||
{"approach", FREQ_APP_DEP},
|
||||
{"departure", FREQ_APP_DEP},
|
||||
// aliases
|
||||
{"gnd", FREQ_GROUND},
|
||||
{"twr", FREQ_TOWER},
|
||||
{"waypoint", WAYPOINT},
|
||||
{"apt", AIRPORT},
|
||||
{"arpt", AIRPORT},
|
||||
|
@ -672,11 +686,24 @@ const char* FGPositioned::nameForType(Type aTy)
|
|||
case WAYPOINT: return "waypoint";
|
||||
case DME: return "dme";
|
||||
case TACAN: return "tacan";
|
||||
case FREQ_TOWER: return "tower";
|
||||
case FREQ_ATIS: return "atis";
|
||||
case FREQ_AWOS: return "awos";
|
||||
case FREQ_GROUND: return "ground";
|
||||
case FREQ_CLEARANCE: return "clearance";
|
||||
case FREQ_UNICOM: return "unicom";
|
||||
case FREQ_APP_DEP: return "approach-departure";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
flightgear::PositionedBinding*
|
||||
FGPositioned::createBinding(SGPropertyNode* node) const
|
||||
{
|
||||
return new flightgear::PositionedBinding(this, node);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// search / query functions
|
||||
|
||||
|
@ -811,3 +838,145 @@ FGPositioned::sortByRange(List& aResult, const SGGeod& aPos)
|
|||
aResult[i] = r[i].get();
|
||||
}
|
||||
}
|
||||
|
||||
FGPositioned::Filter* createSearchFilter(const SGPropertyNode* arg)
|
||||
{
|
||||
string sty(arg->getStringValue("type", "any"));
|
||||
FGPositioned::Type ty = FGPositioned::typeFromName(sty);
|
||||
double minRunwayLenFt = arg->getDoubleValue("min-runway-length-ft", -1.0);
|
||||
|
||||
if ((ty == FGPositioned::AIRPORT) && (minRunwayLenFt > 0.0)) {
|
||||
return new FGAirport::HardSurfaceFilter(minRunwayLenFt);
|
||||
} else if (ty != FGPositioned::INVALID) {
|
||||
FGPositioned::TypeFilter* tf = new FGPositioned::TypeFilter(ty);
|
||||
|
||||
for (int t=1; arg->hasChild("type", t); ++t) {
|
||||
sty = arg->getChild("type", t)->getStringValue();
|
||||
tf->addType(FGPositioned::typeFromName(sty));
|
||||
}
|
||||
|
||||
return tf;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SGGeod commandSearchPos(const SGPropertyNode* arg)
|
||||
{
|
||||
if (arg->hasChild("longitude-deg") && arg->hasChild("latitude-deg")) {
|
||||
return SGGeod::fromDeg(arg->getDoubleValue("longitude-deg"),
|
||||
arg->getDoubleValue("latitude-deg"));
|
||||
}
|
||||
|
||||
// use current viewer/aircraft position
|
||||
return SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"),
|
||||
fgGetDouble("/position/latitude-deg"));
|
||||
}
|
||||
|
||||
void commandClearExisting(const SGPropertyNode* arg)
|
||||
{
|
||||
if (arg->getBoolValue("clear", true)) {
|
||||
// delete all existing result children from their parent
|
||||
string resultPath = arg->getStringValue("results");
|
||||
SGPropertyNode* n = fgGetNode(resultPath.c_str(), 0, true);
|
||||
SGPropertyNode* pr = n->getParent();
|
||||
pr->removeChildren(n->getName(), false /* keep=false, i.e delete nodes */);
|
||||
}
|
||||
}
|
||||
|
||||
bool commandFindClosest(const SGPropertyNode* arg)
|
||||
{
|
||||
int n = arg->getIntValue("max-results", 1);
|
||||
if ((n < 1) || (n > 100)) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "commandFindClosest: max-results invalid:" << n);
|
||||
return false;
|
||||
}
|
||||
|
||||
string resultPath = arg->getStringValue("results");
|
||||
if (resultPath.empty()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "commandFindClosest: no results path defined");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::auto_ptr<FGPositioned::Filter> filt(createSearchFilter(arg));
|
||||
// cap search range, since huge ranges will overload everything
|
||||
double cutoff = arg->getDoubleValue("cutoff-nm", 400.0);
|
||||
SG_CLAMP_RANGE(cutoff, 0.0, 1000.0);
|
||||
|
||||
SGGeod pos = commandSearchPos(arg);
|
||||
commandClearExisting(arg);
|
||||
|
||||
FGPositioned::List results = FGPositioned::findClosestN(pos, n, cutoff, filt.get());
|
||||
for (unsigned int i=0; i<results.size(); ++i) {
|
||||
SGPropertyNode* resultsNode = fgGetNode(resultPath.c_str(), i, true);
|
||||
flightgear::PositionedBinding::bind(results[i], resultsNode);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool commandFindByIdent(const SGPropertyNode* arg)
|
||||
{
|
||||
string resultPath = arg->getStringValue("results");
|
||||
if (resultPath.empty()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "commandFindByIdent: no results path defined");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::auto_ptr<FGPositioned::Filter> filt(createSearchFilter(arg));
|
||||
SGGeod pos = commandSearchPos(arg);
|
||||
commandClearExisting(arg);
|
||||
|
||||
FGPositioned::List results;
|
||||
bool exact = arg->getBoolValue("exact", true);
|
||||
if (arg->hasChild("name")) {
|
||||
results = FGPositioned::findAllWithName(arg->getStringValue("name"), filt.get(), exact);
|
||||
} else if (arg->hasChild("ident")) {
|
||||
results = FGPositioned::findAllWithIdent(arg->getStringValue("ident"), filt.get(), exact);
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "commandFindByIdent: no search term defined");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool orderByRange = arg->getBoolValue("order-by-distance", true);
|
||||
if (orderByRange) {
|
||||
FGPositioned::sortByRange(results, pos);
|
||||
}
|
||||
|
||||
for (unsigned int i=0; i<results.size(); ++i) {
|
||||
SGPropertyNode* resultsNode = fgGetNode(resultPath.c_str(), i, true);
|
||||
flightgear::PositionedBinding::bind(results[i], resultsNode);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
FGPositioned::installCommands()
|
||||
{
|
||||
SGCommandMgr::instance()->addCommand("find-nearest", commandFindClosest);
|
||||
SGCommandMgr::instance()->addCommand("find-by-ident", commandFindByIdent);
|
||||
}
|
||||
|
||||
FGPositioned::TypeFilter::TypeFilter(Type aTy)
|
||||
{
|
||||
types.push_back(aTy);
|
||||
}
|
||||
|
||||
void FGPositioned::TypeFilter::addType(Type aTy)
|
||||
{
|
||||
types.push_back(aTy);
|
||||
}
|
||||
|
||||
bool
|
||||
FGPositioned::TypeFilter::pass(FGPositioned* aPos) const
|
||||
{
|
||||
std::vector<Type>::const_iterator it = types.begin(),
|
||||
end = types.end();
|
||||
for (; it != end; ++it) {
|
||||
return aPos->type() == *it;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,9 +27,15 @@
|
|||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
class FGPositioned;
|
||||
class SGPropertyNode;
|
||||
|
||||
typedef SGSharedPtr<FGPositioned> FGPositionedRef;
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
class PositionedBinding;
|
||||
}
|
||||
|
||||
class FGPositioned : public SGReferenced
|
||||
{
|
||||
public:
|
||||
|
@ -56,9 +62,14 @@ public:
|
|||
DME,
|
||||
TACAN,
|
||||
OBSTACLE,
|
||||
FREQ_GND,
|
||||
FREQ_TWR,
|
||||
FREQ_GROUND,
|
||||
FREQ_TOWER,
|
||||
FREQ_ATIS,
|
||||
FREQ_AWOS,
|
||||
FREQ_APP_DEP,
|
||||
FREQ_ENROUTE,
|
||||
FREQ_CLEARANCE,
|
||||
FREQ_UNICOM,
|
||||
LAST_TYPE
|
||||
} Type;
|
||||
|
||||
|
@ -97,6 +108,9 @@ public:
|
|||
double elevation() const
|
||||
{ return mPosition.getElevationFt(); }
|
||||
|
||||
|
||||
virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const;
|
||||
|
||||
/**
|
||||
* Predicate class to support custom filtering of FGPositioned queries
|
||||
* Default implementation of this passes any FGPositioned instance.
|
||||
|
@ -135,13 +149,15 @@ public:
|
|||
class TypeFilter : public Filter
|
||||
{
|
||||
public:
|
||||
TypeFilter(Type aTy) : mType(aTy) { ; }
|
||||
virtual bool pass(FGPositioned* aPos) const
|
||||
{ return (mType == aPos->type()); }
|
||||
TypeFilter(Type aTy);
|
||||
virtual bool pass(FGPositioned* aPos) const;
|
||||
void addType(Type aTy);
|
||||
private:
|
||||
const Type mType;
|
||||
std::vector<Type> types;
|
||||
};
|
||||
|
||||
static void installCommands();
|
||||
|
||||
static List findWithinRange(const SGGeod& aPos, double aRangeNm, Filter* aFilter = NULL);
|
||||
|
||||
static FGPositionedRef findClosestWithIdent(const std::string& aIdent, const SGGeod& aPos, Filter* aFilter = NULL);
|
||||
|
|
|
@ -15,7 +15,6 @@ set(SOURCES
|
|||
jpg-httpd.cxx
|
||||
jsclient.cxx
|
||||
lfsglass.cxx
|
||||
multiplay.cxx
|
||||
native.cxx
|
||||
native_ctrls.cxx
|
||||
native_fdm.cxx
|
||||
|
|
|
@ -1216,6 +1216,9 @@ FGHLA::open()
|
|||
bool
|
||||
FGHLA::process()
|
||||
{
|
||||
if (!is_enabled())
|
||||
return false;
|
||||
|
||||
// First push our own data so that others can recieve ...
|
||||
if (get_direction() & SG_IO_OUT) {
|
||||
if (fgGetBool("/sim/fdm-initialized", false) && _localAircraftClass.valid()) {
|
||||
|
@ -1245,6 +1248,9 @@ FGHLA::process()
|
|||
bool
|
||||
FGHLA::close()
|
||||
{
|
||||
if (!is_enabled())
|
||||
return false;
|
||||
|
||||
if (get_direction() & SG_IO_OUT) {
|
||||
// Remove the local object from the rti
|
||||
_localAircraftInstance->deleteInstance(simgear::RTIData("gone"));
|
||||
|
|
|
@ -9,8 +9,6 @@ else
|
|||
JPEG_SERVER =
|
||||
endif
|
||||
|
||||
MPLAYER_AS = multiplay.cxx multiplay.hxx
|
||||
|
||||
libNetwork_a_SOURCES = \
|
||||
protocol.cxx protocol.hxx \
|
||||
ATC-Main.cxx ATC-Main.hxx \
|
||||
|
@ -33,7 +31,6 @@ libNetwork_a_SOURCES = \
|
|||
net_ctrls.hxx net_fdm.hxx net_fdm_mini.hxx net_gui.hxx \
|
||||
nmea.cxx nmea.hxx \
|
||||
opengc.cxx opengc.hxx opengc_data.hxx \
|
||||
$(MPLAYER_AS) \
|
||||
props.cxx props.hxx \
|
||||
pve.cxx pve.hxx \
|
||||
ray.cxx ray.hxx \
|
||||
|
|
|
@ -1,319 +0,0 @@
|
|||
// multiplay.cxx -- protocol object for multiplay in Flightgear
|
||||
//
|
||||
// Written by Diarmuid Tyson, started February 2003.
|
||||
// diarmuid.tyson@airservicesaustralia.com
|
||||
//
|
||||
// With addtions by Vivian Meazza, January 2006
|
||||
//
|
||||
// Copyright (C) 2003 Airservices Australia
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
#include <FDM/flightProperties.hxx>
|
||||
#include <MultiPlayer/mpmessages.hxx>
|
||||
|
||||
#include "multiplay.hxx"
|
||||
|
||||
using std::string;
|
||||
|
||||
|
||||
// These constants are provided so that the ident command can list file versions.
|
||||
const char sFG_MULTIPLAY_BID[] = "$Id$";
|
||||
const char sFG_MULTIPLAY_HID[] = FG_MULTIPLAY_HID;
|
||||
|
||||
typedef std::set<std::string> string_set;
|
||||
|
||||
class MPPropertyListener : public SGPropertyChangeListener
|
||||
{
|
||||
public:
|
||||
MPPropertyListener(FGMultiplay* mp) :
|
||||
_multiplay(mp)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void childAdded(SGPropertyNode*, SGPropertyNode*)
|
||||
{
|
||||
_multiplay->setPropertiesChanged();
|
||||
}
|
||||
|
||||
private:
|
||||
FGMultiplay* _multiplay;
|
||||
};
|
||||
|
||||
/******************************************************************
|
||||
* Name: FGMultiplay
|
||||
* Description: Constructor. Initialises the protocol and stores
|
||||
* host and port information.
|
||||
******************************************************************/
|
||||
FGMultiplay::FGMultiplay (const string &dir, const int rate, const string &host, const int port) {
|
||||
|
||||
set_hz(rate);
|
||||
|
||||
set_direction(dir);
|
||||
|
||||
if (get_direction() == SG_IO_IN) {
|
||||
|
||||
fgSetInt("/sim/multiplay/rxport", port);
|
||||
fgSetString("/sim/multiplay/rxhost", host.c_str());
|
||||
|
||||
} else if (get_direction() == SG_IO_OUT) {
|
||||
|
||||
fgSetInt("/sim/multiplay/txport", port);
|
||||
fgSetString("/sim/multiplay/txhost", host.c_str());
|
||||
|
||||
}
|
||||
|
||||
mPropertiesChanged = true;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: ~FGMultiplay
|
||||
* Description: Destructor.
|
||||
******************************************************************/
|
||||
FGMultiplay::~FGMultiplay () {
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: open
|
||||
* Description: Enables the protocol.
|
||||
******************************************************************/
|
||||
bool FGMultiplay::open() {
|
||||
|
||||
if ( is_enabled() ) {
|
||||
SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
|
||||
<< "is already in use, ignoring" );
|
||||
return false;
|
||||
}
|
||||
|
||||
set_enabled(true);
|
||||
|
||||
mPropertiesChanged = true;
|
||||
|
||||
MPPropertyListener* pl = new MPPropertyListener(this);
|
||||
globals->get_props()->addChangeListener(pl, false);
|
||||
return is_enabled();
|
||||
}
|
||||
|
||||
void FGMultiplay::findProperties()
|
||||
{
|
||||
if (!mPropertiesChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
mPropertiesChanged = false;
|
||||
|
||||
for (unsigned i = 0; i < FGMultiplayMgr::numProperties; ++i) {
|
||||
const char* name = FGMultiplayMgr::sIdPropertyList[i].name;
|
||||
SGPropertyNode* pNode = globals->get_props()->getNode(name);
|
||||
if (!pNode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int id = FGMultiplayMgr::sIdPropertyList[i].id;
|
||||
if (mPropertyMap.find(id) != mPropertyMap.end()) {
|
||||
continue; // already activated
|
||||
}
|
||||
|
||||
mPropertyMap[id] = pNode;
|
||||
SG_LOG(SG_NETWORK, SG_INFO, "activating MP property:" << pNode->getPath());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: process
|
||||
* Description: Prompts the multiplayer mgr to either send
|
||||
* or receive data over the network
|
||||
******************************************************************/
|
||||
bool FGMultiplay::process() {
|
||||
using namespace simgear;
|
||||
if (get_direction() == SG_IO_OUT) {
|
||||
findProperties();
|
||||
|
||||
// check if we have left initialization phase. That will not provide
|
||||
// interresting data, also the freeze in simulation time hurts the
|
||||
// multiplayer clients
|
||||
double sim_time = globals->get_sim_time_sec();
|
||||
// if (sim_time < 20)
|
||||
// return true;
|
||||
|
||||
FlightProperties ifce;
|
||||
|
||||
// put together a motion info struct, you will get that later
|
||||
// from FGInterface directly ...
|
||||
FGExternalMotionData motionInfo;
|
||||
|
||||
// The current simulation time we need to update for,
|
||||
// note that the simulation time is updated before calling all the
|
||||
// update methods. Thus it contains the time intervals *end* time.
|
||||
// The FDM is already run, so the states belong to that time.
|
||||
motionInfo.time = sim_time;
|
||||
|
||||
// The typical lag will be the reciprocal of the output frequency
|
||||
double hz = get_hz();
|
||||
if (hz != 0) // I guess we can test a double for exact zero in this case
|
||||
motionInfo.lag = 1/get_hz();
|
||||
else
|
||||
motionInfo.lag = 0.1; //??
|
||||
|
||||
// These are for now converted from lat/lon/alt and euler angles.
|
||||
// But this should change in FGInterface ...
|
||||
double lon = ifce.get_Longitude();
|
||||
double lat = ifce.get_Latitude();
|
||||
// first the aprioriate structure for the geodetic one
|
||||
SGGeod geod = SGGeod::fromRadFt(lon, lat, ifce.get_Altitude());
|
||||
// Convert to cartesion coordinate
|
||||
motionInfo.position = SGVec3d::fromGeod(geod);
|
||||
|
||||
// The quaternion rotating from the earth centered frame to the
|
||||
// horizontal local frame
|
||||
SGQuatf qEc2Hl = SGQuatf::fromLonLatRad((float)lon, (float)lat);
|
||||
// The orientation wrt the horizontal local frame
|
||||
float heading = ifce.get_Psi();
|
||||
float pitch = ifce.get_Theta();
|
||||
float roll = ifce.get_Phi();
|
||||
SGQuatf hlOr = SGQuatf::fromYawPitchRoll(heading, pitch, roll);
|
||||
// The orientation of the vehicle wrt the earth centered frame
|
||||
motionInfo.orientation = qEc2Hl*hlOr;
|
||||
|
||||
if (!globals->get_subsystem("flight")->is_suspended()) {
|
||||
// velocities
|
||||
motionInfo.linearVel = SG_FEET_TO_METER*SGVec3f(ifce.get_uBody(),
|
||||
ifce.get_vBody(),
|
||||
ifce.get_wBody());
|
||||
motionInfo.angularVel = SGVec3f(ifce.get_P_body(),
|
||||
ifce.get_Q_body(),
|
||||
ifce.get_R_body());
|
||||
|
||||
// accels, set that to zero for now.
|
||||
// Angular accelerations are missing from the interface anyway,
|
||||
// linear accelerations are screwed up at least for JSBSim.
|
||||
// motionInfo.linearAccel = SG_FEET_TO_METER*SGVec3f(ifce.get_U_dot_body(),
|
||||
// ifce.get_V_dot_body(),
|
||||
// ifce.get_W_dot_body());
|
||||
motionInfo.linearAccel = SGVec3f::zeros();
|
||||
motionInfo.angularAccel = SGVec3f::zeros();
|
||||
} else {
|
||||
// if the interface is suspendend, prevent the client from
|
||||
// wild extrapolations
|
||||
motionInfo.linearVel = SGVec3f::zeros();
|
||||
motionInfo.angularVel = SGVec3f::zeros();
|
||||
motionInfo.linearAccel = SGVec3f::zeros();
|
||||
motionInfo.angularAccel = SGVec3f::zeros();
|
||||
}
|
||||
|
||||
// now send the properties
|
||||
PropertyMap::iterator it;
|
||||
for (it = mPropertyMap.begin(); it != mPropertyMap.end(); ++it) {
|
||||
FGPropertyData* pData = new FGPropertyData;
|
||||
pData->id = it->first;
|
||||
pData->type = it->second->getType();
|
||||
|
||||
switch (pData->type) {
|
||||
case props::INT:
|
||||
case props::LONG:
|
||||
case props::BOOL:
|
||||
pData->int_value = it->second->getIntValue();
|
||||
break;
|
||||
case props::FLOAT:
|
||||
case props::DOUBLE:
|
||||
pData->float_value = it->second->getFloatValue();
|
||||
break;
|
||||
case props::STRING:
|
||||
case props::UNSPECIFIED:
|
||||
{
|
||||
// FIXME: We assume unspecified are strings for the moment.
|
||||
|
||||
const char* cstr = it->second->getStringValue();
|
||||
int len = strlen(cstr);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
pData->string_value = new char[len + 1];
|
||||
strcpy(pData->string_value, cstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Size 0 - ignore
|
||||
pData->string_value = 0;
|
||||
}
|
||||
|
||||
//cout << " Sending property " << pData->id << " " << pData->type << " " << pData->string_value << "\n";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// FIXME Currently default to a float.
|
||||
//cout << "Unknown type when iterating through props: " << pData->type << "\n";
|
||||
pData->float_value = it->second->getFloatValue();
|
||||
break;
|
||||
}
|
||||
|
||||
motionInfo.properties.push_back(pData);
|
||||
}
|
||||
|
||||
FGMultiplayMgr* mpmgr = (FGMultiplayMgr*) globals->get_subsystem("mp");
|
||||
mpmgr->SendMyPosition(motionInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: close
|
||||
* Description: Closes the multiplayer mgrs to stop any further
|
||||
* network processing
|
||||
******************************************************************/
|
||||
bool FGMultiplay::close()
|
||||
{
|
||||
mPropertyMap.clear();
|
||||
|
||||
FGMultiplayMgr* mgr = (FGMultiplayMgr*) globals->get_subsystem("mp");
|
||||
|
||||
if (mgr == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (get_direction() == SG_IO_IN) {
|
||||
|
||||
mgr->Close();
|
||||
|
||||
} else if (get_direction() == SG_IO_OUT) {
|
||||
|
||||
mgr->Close();
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
// multiplay.hxx -- protocol object for multiplay in Flightgear
|
||||
//
|
||||
// Written by Diarmuid Tyson, started February 2003.
|
||||
// diarmuid.tyson@airservicesaustralia.com
|
||||
//
|
||||
// With additions by Vivian Meazza, January 2006
|
||||
//
|
||||
// Copyright (C) 2003 Airservices Australia
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef _FG_MULTIPLAY_HXX
|
||||
#define _FG_MULTIPLAY_HXX
|
||||
|
||||
#define FG_MULTIPLAY_HID "$Id$"
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Model/acmodel.hxx>
|
||||
#include <MultiPlayer/multiplaymgr.hxx>
|
||||
|
||||
#include "protocol.hxx"
|
||||
|
||||
using std::string;
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* @version $Id$
|
||||
*
|
||||
* Description: FGMultiplay is an FGProtocol object used as the basic
|
||||
* interface for the multiplayer code into FlightGears generic IO
|
||||
* subsystem. It only implements the basic FGProtocol methods: open(),
|
||||
* process() and close(). It does not use Sim Gear's IO channels, as
|
||||
* the MultiplayMgrs creates their own sockets through plib.
|
||||
*
|
||||
* It will set up it's direction and rate protocol properties when
|
||||
* created. Subsequent calls to process will prompt the
|
||||
* MultiplayMgr to either send or receive data over the network.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
class FGMultiplay : public FGProtocol {
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
FGMultiplay (const string &dir, const int rate, const string &host, const int port);
|
||||
|
||||
/** Destructor. */
|
||||
~FGMultiplay ();
|
||||
|
||||
/** Enables the FGMultiplay object. */
|
||||
bool open();
|
||||
|
||||
/** Tells the multiplayer_mgr to send/receive data.
|
||||
*/
|
||||
bool process();
|
||||
|
||||
/** Closes the multiplayer_mgr.
|
||||
*/
|
||||
bool close();
|
||||
|
||||
void setPropertiesChanged()
|
||||
{
|
||||
mPropertiesChanged = true;
|
||||
}
|
||||
private:
|
||||
bool mPropertiesChanged;
|
||||
|
||||
void findProperties();
|
||||
|
||||
// Map between the property id's from the multiplayers network packets
|
||||
// and the property nodes
|
||||
typedef std::map<unsigned, SGSharedPtr<SGPropertyNode> > PropertyMap;
|
||||
PropertyMap mPropertyMap;
|
||||
};
|
||||
|
||||
|
||||
#endif // _FG_MULTIPLAY_HXX
|
|
@ -476,10 +476,9 @@ static naRef f_systime(naContext c, naRef me, int argc, naRef* args)
|
|||
// Converts from 100ns units in 1601 epoch to unix epoch in sec
|
||||
return naNum((t * 1e-7) - 11644473600.0);
|
||||
#else
|
||||
time_t t;
|
||||
struct timeval td;
|
||||
do { t = time(0); gettimeofday(&td, 0); } while(t != time(0));
|
||||
return naNum(t + 1e-6 * td.tv_usec);
|
||||
gettimeofday(&td, 0);
|
||||
return naNum(td.tv_sec + 1e-6 * td.tv_usec);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -805,10 +804,19 @@ void FGNasalSys::update(double)
|
|||
_context = naNewContext();
|
||||
}
|
||||
|
||||
bool pathSortPredicate(const SGPath& p1, const SGPath& p2)
|
||||
{
|
||||
return p1.file() < p2.file();
|
||||
}
|
||||
|
||||
// Loads all scripts in given directory
|
||||
void FGNasalSys::loadScriptDirectory(simgear::Dir nasalDir)
|
||||
{
|
||||
simgear::PathList scripts = nasalDir.children(simgear::Dir::TYPE_FILE, ".nas");
|
||||
// sort scripts, avoid loading sequence effects due to file system's
|
||||
// random directory order
|
||||
std::sort(scripts.begin(), scripts.end(), pathSortPredicate);
|
||||
|
||||
for (unsigned int i=0; i<scripts.size(); ++i) {
|
||||
SGPath fullpath(scripts[i]);
|
||||
SGPath file = fullpath.file();
|
||||
|
|
|
@ -80,7 +80,7 @@ FGSampleQueue::update (double dt)
|
|||
last_volume = volume;
|
||||
}
|
||||
|
||||
// process mesage queue
|
||||
// process message queue
|
||||
const string msgid = "Sequential Audio Message";
|
||||
bool now_playing = false;
|
||||
if ( exists( msgid ) ) {
|
||||
|
|
|
@ -77,6 +77,8 @@ FGLight::FGLight ()
|
|||
_adj_fog_color(0, 0, 0, 0),
|
||||
_adj_sky_color(0, 0, 0, 0),
|
||||
_saturation(1.0),
|
||||
_scattering(0.8),
|
||||
_overcast(0.0),
|
||||
_dt_total(0)
|
||||
{
|
||||
}
|
||||
|
@ -140,8 +142,14 @@ void FGLight::reinit () {
|
|||
|
||||
void FGLight::bind () {
|
||||
SGPropertyNode *prop = globals->get_props();
|
||||
prop->tie("/sim/time/sun-angle-rad",SGRawValuePointer<double>(&_sun_angle));
|
||||
|
||||
// Write Only
|
||||
prop->tie("/rendering/scene/saturation",SGRawValuePointer<float>(&_saturation));
|
||||
prop->tie("/rendering/scene/scattering",SGRawValuePointer<float>(&_scattering));
|
||||
prop->tie("/rendering/scene/overcast",SGRawValuePointer<float>(&_overcast));
|
||||
|
||||
// Read Only
|
||||
prop->tie("/sim/time/sun-angle-rad",SGRawValuePointer<double>(&_sun_angle));
|
||||
prop->tie("/rendering/scene/ambient/red",SGRawValuePointer<float>(&_scene_ambient[0]));
|
||||
prop->tie("/rendering/scene/ambient/green",SGRawValuePointer<float>(&_scene_ambient[1]));
|
||||
prop->tie("/rendering/scene/ambient/blue",SGRawValuePointer<float>(&_scene_ambient[2]));
|
||||
|
@ -170,8 +178,11 @@ void FGLight::bind () {
|
|||
|
||||
void FGLight::unbind () {
|
||||
SGPropertyNode *prop = globals->get_props();
|
||||
prop->untie("/sim/time/sun-angle-rad");
|
||||
prop->untie("/rendering/scene/saturation");
|
||||
prop->untie("/rendering/scene/scattering");
|
||||
prop->untie("/rendering/scene/overcast");
|
||||
|
||||
prop->untie("/sim/time/sun-angle-rad");
|
||||
prop->untie("/rendering/scene/ambient/red");
|
||||
prop->untie("/rendering/scene/ambient/green");
|
||||
prop->untie("/rendering/scene/ambient/blue");
|
||||
|
@ -224,6 +235,10 @@ void FGLight::update_sky_color () {
|
|||
|
||||
if (_saturation < 0.0) _saturation = 0.0;
|
||||
else if (_saturation > 1.0) _saturation = 1.0;
|
||||
if (_scattering < 0.0) _scattering = 0.0;
|
||||
else if (_scattering > 1.0) _scattering = 1.0;
|
||||
if (_overcast < 0.0) _overcast = 0.0;
|
||||
else if (_overcast > 1.0) _overcast = 1.0;
|
||||
|
||||
float ambient = _ambient_tbl->interpolate( deg ) + visibility_inv/10;
|
||||
float diffuse = _diffuse_tbl->interpolate( deg );
|
||||
|
@ -242,7 +257,7 @@ void FGLight::update_sky_color () {
|
|||
// sky_brightness = 0.15; // used to force a dark sky (when testing)
|
||||
|
||||
// set fog and cloud color
|
||||
float sqrt_sky_brightness = 1.0 - sqrt(1.0 - sky_brightness);
|
||||
float sqrt_sky_brightness = (1.0 - sqrt(1.0 - sky_brightness))*_scattering;
|
||||
_fog_color[0] = base_fog_color[0] * sqrt_sky_brightness;
|
||||
_fog_color[1] = base_fog_color[1] * sqrt_sky_brightness;
|
||||
_fog_color[2] = base_fog_color[2] * sqrt_sky_brightness;
|
||||
|
@ -250,9 +265,9 @@ void FGLight::update_sky_color () {
|
|||
gamma_correct_rgb( _fog_color.data() );
|
||||
|
||||
// set sky color
|
||||
_sky_color[0] = base_sky_color[0] * sky_brightness;
|
||||
_sky_color[1] = base_sky_color[1] * sky_brightness;
|
||||
_sky_color[2] = base_sky_color[2] * sky_brightness;
|
||||
_sky_color[0] = (base_sky_color[0] + (1.0f-base_sky_color[0]) * _overcast) * sky_brightness;
|
||||
_sky_color[1] = (base_sky_color[1] + (1.0f-base_sky_color[1]) * _overcast) * sky_brightness;
|
||||
_sky_color[2] = (base_sky_color[2] + (1.0f-base_sky_color[2]) * _overcast) * sky_brightness;
|
||||
_sky_color[3] = base_sky_color[3];
|
||||
gamma_correct_rgb( _sky_color.data() );
|
||||
|
||||
|
@ -345,7 +360,7 @@ void FGLight::update_adj_fog_color () {
|
|||
else
|
||||
hor_rotation = fmod(hor_rotation, SGD_2PI);
|
||||
|
||||
// revert to unmodified values before usign them.
|
||||
// revert to unmodified values before using them.
|
||||
//
|
||||
SGVec4f color = thesky->get_scene_color();
|
||||
|
||||
|
@ -359,7 +374,7 @@ void FGLight::update_adj_fog_color () {
|
|||
float s_green = color[1]*color[1]*color[1];
|
||||
float s_blue = color[2]*color[2];
|
||||
|
||||
// interpolate beween the sunrise/sunset color and the color
|
||||
// interpolate between the sunrise/sunset color and the color
|
||||
// at the opposite direction of this effect. Take in account
|
||||
// the current visibility.
|
||||
//
|
||||
|
@ -373,11 +388,10 @@ void FGLight::update_adj_fog_color () {
|
|||
sif = 1e-4;
|
||||
|
||||
float rf1 = fabs((hor_rotation - SGD_PI) / SGD_PI); // 0.0 .. 1.0
|
||||
float rf2 = avf * pow(rf1*rf1, 1/sif) * 1.0639 * _saturation;
|
||||
float rf2 = avf * pow(rf1*rf1, 1/sif) * 1.0639 * _saturation * _scattering;
|
||||
float rf3 = 1.0 - rf2;
|
||||
|
||||
gamma = system_gamma * (0.9 - sif*avf);
|
||||
|
||||
_adj_fog_color[0] = rf3 * _fog_color[0] + rf2 * s_red;
|
||||
_adj_fog_color[1] = rf3 * _fog_color[1] + rf2 * s_green;
|
||||
_adj_fog_color[2] = rf3 * _fog_color[2] + rf2 * s_blue;
|
||||
|
@ -399,23 +413,19 @@ void FGLight::updateSunPos()
|
|||
SG_LOG( SG_EVENT, SG_DEBUG, " Updating Sun position" );
|
||||
SG_LOG( SG_EVENT, SG_DEBUG, " Gst = " << t->getGst() );
|
||||
|
||||
double sun_l;
|
||||
double sun_gc_lat;
|
||||
fgSunPositionGST(t->getGst(), &sun_l, &sun_gc_lat);
|
||||
set_sun_lon(sun_l);
|
||||
fgSunPositionGST(t->getGst(), &_sun_lon, &_sun_lat);
|
||||
// It might seem that sun_gc_lat needs to be converted to geodetic
|
||||
// latitude here, but it doesn't. The sun latitude is the latitude
|
||||
// of the point on the earth where the up vector has the same
|
||||
// angle from geocentric Z as the sun direction. But geodetic
|
||||
// latitude is defined as 90 - angle of up vector from Z!
|
||||
set_sun_lat(sun_gc_lat);
|
||||
SGVec3d sunpos(SGVec3d::fromGeoc(SGGeoc::fromRadM(sun_l, sun_gc_lat,
|
||||
SGVec3d sunpos(SGVec3d::fromGeoc(SGGeoc::fromRadM(_sun_lon, _sun_lat,
|
||||
SGGeodesy::EQURAD)));
|
||||
|
||||
SG_LOG( SG_EVENT, SG_DEBUG, " t->cur_time = " << t->get_cur_time() );
|
||||
SG_LOG( SG_EVENT, SG_DEBUG,
|
||||
" Sun Geocentric lat = " << sun_gc_lat
|
||||
<< " Geodcentric lat = " << sun_gc_lat );
|
||||
" Sun Geocentric lat = " << _sun_lat
|
||||
<< " Geodcentric lat = " << _sun_lat );
|
||||
|
||||
// update the sun light vector
|
||||
sun_vec() = SGVec4f(toVec3f(normalize(sunpos)), 0);
|
||||
|
@ -431,15 +441,16 @@ void FGLight::updateSunPos()
|
|||
// cout << "nsun = " << nsun[0] << "," << nsun[1] << ","
|
||||
// << nsun[2] << endl;
|
||||
|
||||
set_sun_angle( acos( dot ( world_up, nsun ) ) );
|
||||
_sun_angle = acos( dot ( world_up, nsun ) );
|
||||
SG_LOG( SG_EVENT, SG_DEBUG, "sun angle relative to current location = "
|
||||
<< get_sun_angle() );
|
||||
|
||||
// Get direction to the sun in the local frame.
|
||||
SGVec3d local_sun_vec = hlOr.transform(nsun);
|
||||
|
||||
// Angle from south. XXX Is this correct in the southern hemisphere?
|
||||
double angle = atan2(local_sun_vec.x(), -local_sun_vec.y());
|
||||
set_sun_rotation(angle);
|
||||
// cout << " Sky needs to rotate = " << angle << " rads = "
|
||||
// << angle * SGD_RADIANS_TO_DEGREES << " degrees." << endl;
|
||||
_sun_rotation = atan2(local_sun_vec.x(), -local_sun_vec.y());
|
||||
|
||||
// cout << " Sky needs to rotate = " << _sun_rotation << " rads = "
|
||||
// << _sun_rotation * SGD_RADIANS_TO_DEGREES << " degrees." << endl;
|
||||
}
|
||||
|
|
|
@ -96,7 +96,11 @@ private:
|
|||
// clear sky and fog color adjusted for sunset effects
|
||||
SGVec4f _adj_fog_color;
|
||||
SGVec4f _adj_sky_color;
|
||||
|
||||
// input parameters affected by the weather system
|
||||
float _saturation;
|
||||
float _scattering;
|
||||
float _overcast;
|
||||
|
||||
double _dt_total;
|
||||
|
||||
|
|
|
@ -5,3 +5,7 @@ add_subdirectory(GPSsmooth)
|
|||
if (FLTK_FOUND)
|
||||
add_subdirectory(fgadmin)
|
||||
endif (FLTK_FOUND)
|
||||
|
||||
if (WITH_FGPANEL)
|
||||
add_subdirectory(fgpanel)
|
||||
endif (WITH_FGPANEL)
|
||||
|
|
25
utils/fgpanel/CMakeLists.txt
Normal file
25
utils/fgpanel/CMakeLists.txt
Normal file
|
@ -0,0 +1,25 @@
|
|||
#FIXME: does this work in *nix/windows?
|
||||
find_package(png REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(glut REQUIRED)
|
||||
|
||||
add_executable(fgpanel main.cxx
|
||||
FGGLApplication.cxx
|
||||
FGPanelApplication.cxx
|
||||
FGPNGTextureLoader.cxx
|
||||
FGRGBTextureLoader.cxx
|
||||
FGPanelProtocol.cxx
|
||||
FGFontCache.cxx
|
||||
panel.cxx
|
||||
panel_io.cxx)
|
||||
|
||||
target_link_libraries(fgpanel
|
||||
${PNG_LIBRARIES}
|
||||
${GLUT_LIBRARIES}
|
||||
${SIMGEAR_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${PLIB_LIBRARIES}
|
||||
)
|
||||
|
||||
install(TARGETS fgpanel RUNTIME DESTINATION bin)
|
|
@ -21,12 +21,19 @@
|
|||
#endif
|
||||
|
||||
#include "FGGLApplication.hxx"
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#define snprintf sprintf_s
|
||||
#define snprintf sprintf_s
|
||||
#endif
|
||||
#if defined (SG_MAC)
|
||||
#include <OpenGL/gl.h>
|
||||
#include <GLUT/glut.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glut.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
|
|
|
@ -22,7 +22,11 @@
|
|||
#endif
|
||||
#include "FGPNGTextureLoader.hxx"
|
||||
|
||||
#include <GL/glu.h>
|
||||
#if defined (SG_MAC)
|
||||
#include <GLUT/glut.h>
|
||||
#else
|
||||
#include <GL/glut.h>
|
||||
#endif
|
||||
#include <png.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
|
@ -26,8 +26,13 @@
|
|||
|
||||
#include "FGGLApplication.hxx"
|
||||
#include "FGPanelApplication.hxx"
|
||||
#if defined (SG_MAC)
|
||||
#include <OpenGL/gl.h>
|
||||
#include <GLUT/glut.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glut.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/math/SGMisc.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
@ -98,7 +103,7 @@ FGPanelApplication::FGPanelApplication( int argc, char ** argv ) :
|
|||
string arg = argv[i];
|
||||
if( arg.find( "--prop:" ) == 0 ) {
|
||||
string s2 = arg.substr( 7 );
|
||||
unsigned p = s2.find( "=" );
|
||||
string::size_type p = s2.find( "=" );
|
||||
if( p != string::npos ) {
|
||||
string propertyName = s2.substr( 0, p );
|
||||
string propertyValue = s2.substr( p+1 );
|
||||
|
|
|
@ -26,8 +26,13 @@
|
|||
#endif
|
||||
|
||||
#include "FGRGBTextureLoader.hxx"
|
||||
#if defined (SG_MAC)
|
||||
#include <OpenGL/gl.h>
|
||||
#include <GLUT/glut.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glut.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
|
@ -17,8 +17,12 @@
|
|||
//
|
||||
#ifndef __FGTEXTURELOADERINTERFACE_HXX
|
||||
#define __FGTEXTURELOADERINTERFACE_HXX
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#if defined (SG_MAC)
|
||||
#include <OpenGL/gl.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
#include <string>
|
||||
class FGTextureLoaderInterface {
|
||||
public:
|
||||
|
|
|
@ -31,7 +31,11 @@
|
|||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#if defined (SG_MAC)
|
||||
#include <GLUT/glut.h>
|
||||
#else
|
||||
#include <GL/glut.h>
|
||||
#endif
|
||||
|
||||
#include <plib/fnt.h>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue