1
0
Fork 0

Merge branch 'next' of D:\Git_New\flightgear into next

This commit is contained in:
Vivian Meazza 2011-06-05 22:25:10 +01:00
commit 87082859d8
85 changed files with 1977 additions and 1688 deletions

View file

@ -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 (

View 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

View 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
View 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
View 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

View file

@ -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

View file

@ -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;
}

View file

@ -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_

View file

@ -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 =

View file

@ -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

View file

@ -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;}

View file

@ -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);
}

View file

@ -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");
}
}

View file

@ -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

View file

@ -3,7 +3,6 @@ include(FlightGearComponent)
set(SOURCES
ATC.cxx
atis.cxx
commlist.cxx
ATCDialog.cxx
ATCVoice.cxx
ATCmgr.cxx

View file

@ -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 \

View file

@ -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;

View file

@ -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;

View file

@ -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));
}

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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));
}

View file

@ -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);
};

View file

@ -26,6 +26,7 @@
#endif
#include <simgear/compiler.h>
#include <simgear/props/props.hxx>
#include "runwaybase.hxx"

View file

@ -85,6 +85,7 @@ public:
{ return _surface_code; }
protected:
double _heading;
double _length;
double _width;

View file

@ -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);
}

View file

@ -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

View file

@ -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 )
{

View file

@ -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

View file

@ -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;
}
}

View file

@ -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);

View file

@ -16,6 +16,7 @@ set(SOURCES
ridge_lift.cxx
terrainsampler.cxx
presets.cxx
gravity.cxx
)
flightgear_component(Environment "${SOURCES}")

View file

@ -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

View file

@ -31,8 +31,6 @@
#include <cmath>
#include <utility>
using namespace std;
/**
* Model the atmosphere in a way consistent with the laws
* of physics.

View file

@ -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 )
{

View file

@ -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

View file

@ -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());

View file

@ -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

View 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

View 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

View file

@ -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 );

View file

@ -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

View file

@ -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" );
}

View file

@ -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);
}
//******************************************************************************

View file

@ -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);

View file

@ -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;

View file

@ -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
}

View file

@ -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@"

View file

@ -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) {

View file

@ -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");

View file

@ -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
};

View file

@ -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
////////////////////////////////////////////////////////////////////

View file

@ -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

View file

@ -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();

View file

@ -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, ' ');

View file

@ -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 );

View file

@ -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()

View file

@ -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());
}
}

View file

@ -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

View file

@ -13,6 +13,7 @@ set(SOURCES
route.cxx
routePath.cxx
waypoint.cxx
PositionedBinding.cxx
)
flightgear_component(Navaids "${SOURCES}")

View file

@ -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

View 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

View 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

View file

@ -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)

View file

@ -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 {

View file

@ -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;
}

View file

@ -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);

View file

@ -15,7 +15,6 @@ set(SOURCES
jpg-httpd.cxx
jsclient.cxx
lfsglass.cxx
multiplay.cxx
native.cxx
native_ctrls.cxx
native_fdm.cxx

View file

@ -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"));

View file

@ -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 \

View file

@ -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;
}

View file

@ -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

View file

@ -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();

View 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 ) ) {

View file

@ -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;
}

View file

@ -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;

View file

@ -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)

View 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)

View file

@ -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>

View file

@ -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>

View file

@ -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 );

View file

@ -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>

View file

@ -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:

View file

@ -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>