1
0
Fork 0

Merge branch 'next' into durk-atc

Resolving merge conflicts indicated below.
Conflicts:
	src/ATC/CMakeLists.txt
	src/ATC/Makefile.am
	src/Main/fg_init.cxx
This commit is contained in:
Durk Talsma 2011-06-01 20:46:34 +02:00
commit f9a5f921a4
42 changed files with 1102 additions and 993 deletions

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"
>
@ -3381,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"
>
@ -3405,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"
>
@ -3429,22 +3445,6 @@
RelativePath="..\..\..\src\Environment\terrainsampler.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Environment\presets.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Environment\presets.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Environment\gravity.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Environment\gravity.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"
>
@ -3801,14 +3809,6 @@
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,9 +1,9 @@
include(FlightGearComponent)
set(SOURCES
atis_mgr.cxx
atc_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,9 +1,9 @@
noinst_LIBRARIES = libATC.a
libATC_a_SOURCES = \
atis_mgr.cxx atis_mgr.hxx \
atcdialog.cxx atcdialog.hxx \
atc_mgr.cxx atc_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

@ -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>
@ -287,21 +287,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;
class AirportsWithATC : public FGAirport::AirportFilter
{
public:
virtual FGPositioned::Type maxType() const {
return FGPositioned::SEAPORT;
}
bool operator<(const atcdata& a) const {
return id != a.id && distance < a.distance;
virtual bool passAirport(FGAirport* aApt) const
{
return (!aApt->commStations().empty());
}
bool operator==(const atcdata& a) const {
return id == a.id && distance == a.distance;
}
string id;
string name;
double distance;
};
void FGATCDialog::FreqDialog() {
@ -316,38 +312,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);
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", uit->first.id.c_str());
entry->setStringValue("binding[0]/value", uit->first.id.c_str());
}
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);
}
@ -378,42 +361,32 @@ 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
const flightgear::CommStationList& comms(a->commStations());
if (comms.empty()) {
label = "No frequencies found for airport " + ident;
mkDialog(label.c_str());
return;
}
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;
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);
ostringstream ostr;
ostr << itr->type;
entry->setStringValue("text[0]/label", ostr.str());
entry->setStringValue("text[0]/label", comm->ident());
char buf[8];
snprintf(buf, 8, "%.2f", (itr->freq / 100.0)); // Convert from KHz to MHz
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++;
}
}
if(n == 0) {
label = "No frequencies found for airport " + ident;
mkDialog(label.c_str());
return;
++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,22 +244,22 @@ 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:
string svc_name = data.ident+decimalNumeral(data.type);
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:
@ -330,22 +271,17 @@ void FGATCMgr::FreqSearch(const string navcomm, const int unit) {
return;
}
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) {
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->SetData(&data);
svc->SetStation(sta);
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,8 +80,6 @@ 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
@ -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>
@ -56,7 +55,6 @@
#include <Airports/runways.hxx>
#include "commlist.hxx"
#include "ATCutils.hxx"
#include "ATCmgr.hxx"
@ -230,6 +228,47 @@ int Apt_US_CA(const string id) {
return 0;
}
// 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;
static atis_log_type atislog;
int FGATIS::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));
}
// Generate the actual broadcast ATIS transmission.
// Regen means regenerate the /current/ transmission.
// Special means generate a new transmission, with a new sequence.
@ -245,8 +284,8 @@ int FGATIS::GenTransmission(const int regen, const int special) {
int interval = _type == ATIS ?
ATIS_interval // ATIS updated hourly
: 2*minute; // AWOS updated more frequently
int sequence = current_commlist->GetAtisSequence(ident,
tstamp, interval, special);
int sequence = GetAtisSequence(ident, tstamp, 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,9 @@ class FGATIS : public FGATC {
void TreeOut(int msgOK);
friend std::istream& operator>> ( std::istream&, FGATIS& );
int GetAtisSequence( const std::string& apt_id,
const double tstamp, const int interval, const int special);
};
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,
SGGeod pos = 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;
// 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;
// generate cartesian coordinates
a.cart = SGVec3d::fromGeod(a.geod);
comm_list->commlist_freq[a.freq].push_back(a);
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");
}
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

@ -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;
@ -662,6 +664,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;
@ -190,16 +199,6 @@ private:
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);
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

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

@ -42,7 +42,6 @@ Somigliana::Somigliana()
Somigliana::~Somigliana()
{
}
#include <stdio.h>
double Somigliana::getGravity( const SGGeod & position ) const
{

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

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

@ -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);
@ -500,37 +458,34 @@ void KLN89AptPage::SetId(const string& s) {
void KLN89AptPage::UpdateAirport(const string& id) {
// Frequencies
_aptFreqs.clear();
ATCData ad;
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;
//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);
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;
}
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);
}
_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

@ -75,8 +75,6 @@
#include <AIModel/AIManager.hxx>
#include <ATCDCL/ATCmgr.hxx>
#include <ATCDCL/commlist.hxx>
#include <ATC/atis_mgr.hxx>
#include <ATC/atc_mgr.hxx>
#include <Autopilot/route_mgr.hxx>
@ -1085,14 +1083,9 @@ 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;
@ -1435,7 +1428,7 @@ bool fgInitSubsystems() {
////////////////////////////////////////////////////////////////////
// Initialise the ATIS Subsystem
////////////////////////////////////////////////////////////////////
globals->add_subsystem("atis", new FGAtisManager, SGSubsystemMgr::POST_FDM);
//globals->add_subsystem("atis", new FGAtisManager, SGSubsystemMgr::POST_FDM);
////////////////////////////////////////////////////////////////////

View file

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

View file

@ -0,0 +1,173 @@
#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());
int count = nd->getChildren(tynm).size();
SGPropertyNode* commNode = nd->getChild(tynm, count, true);
commNode->setStringValue("ident", comm->ident());
commNode->setDoubleValue("frequency-mhz", comm->freqMHz());
}
}
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

@ -35,11 +35,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 +633,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 +685,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 +837,145 @@ FGPositioned::sortByRange(List& aResult, const SGGeod& aPos)
aResult[i] = r[i].get();
}
}
FGPositioned::Filter* createSearchFilter(const SGPropertyNode* arg)
{
string sty(arg->getStringValue("type", 0));
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;
}
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::findAllWithName(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);