include(FlightGearComponent)
set(SOURCES
- atis_mgr.cxx
trafficcontrol.cxx
+ CommStation.cxx
)
flightgear_component(ATC "${SOURCES}")
--- /dev/null
+#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
--- /dev/null
+#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
+
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
+++ /dev/null
-/******************************************************************************
- * 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;
-}
+++ /dev/null
-/* -*- 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_
\ No newline at end of file
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
-
-
+#include <ATC/CommStation.hxx>
+#include <Airports/simple.hxx>
FGATC::FGATC() :
_playing(false),
}
}
-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
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
//
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;}
#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>
}
}
-// 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() {
// 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);
}
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);
+ 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);
- 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
- if(buf[5] == '3') buf[5] = '2';
- if(buf[5] == '8') buf[5] = '7';
- buf[7] = '\0';
+ 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++;
- }
- }
- if(n == 0) {
- label = "No frequencies found for airport " + ident;
- mkDialog(label.c_str());
- return;
- }
+ entry->setStringValue("text[1]/label", buf);
+ ++n;
+ }
_gui->showDialog(dialog_name);
}
#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),
//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){
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.
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");
- }
}
#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
{
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;
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.
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
set(SOURCES
ATC.cxx
atis.cxx
- commlist.cxx
ATCDialog.cxx
ATCVoice.cxx
ATCmgr.cxx
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 \
#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
#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>
#include <Airports/runways.hxx>
-#include "commlist.hxx"
#include "ATCutils.hxx"
#include "ATCmgr.hxx"
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.
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;
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;
+++ /dev/null
-// 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));
-}
+++ /dev/null
-// 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
-
-
#include "simple.hxx"
#include "runways.hxx"
#include "pavement.hxx"
-#include <ATCDCL/commlist.hxx>
+
+#include <ATC/CommStation.hxx>
#include <iostream>
- void parseAPT(const string &aptdb_file, FGCommList *comm_list)
+ void parseAPT(const string &aptdb_file)
{
sg_gzifstream in( aptdb_file );
// 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));
vector<FGRunwayPtr> runways;
vector<FGTaxiwayPtr> taxiways;
vector<FGPavementPtr> pavements;
+ vector<flightgear::CommStation*> commStations;
void addAirport()
{
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)
}
}
- 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
-
- // 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
+ 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");
+ }
+
+ commStations.push_back(new flightgear::CommStation(token[2], ty, pos, rangeNm, freqKhz));
}
};
// 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.
#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
#endif
#include <simgear/compiler.h>
+#include <simgear/props/props.hxx>
#include "runwaybase.hxx"
{ return _surface_code; }
protected:
+
double _heading;
double _length;
double _width;
#include <Airports/simple.hxx>
#include <Navaids/procedure.hxx>
+#include <Navaids/navrecord.hxx>
+#include <Navaids/PositionedBinding.hxx>
using std::string;
return result;
}
+flightgear::PositionedBinding*
+FGRunway::createBinding(SGPropertyNode* nd) const
+{
+ return new flightgear::RunwayBinding(this, nd);
+}
{ 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
*/
* Get STARs associared with this runway
*/
std::vector<flightgear::STAR*> getSTARs();
+
};
#endif // _FG_RUNWAYS_HXX
#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;
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 )
{
class STAR;
class Approach;
class Waypt;
-
+ class CommStation;
typedef SGSharedPtr<Waypt> WayptRef;
typedef std::vector<WayptRef> WayptVec;
+
+ typedef std::vector<CommStation*> CommStationList;
}
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
*/
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;
/**
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
#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;
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);
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);
// 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) {
#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>
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;
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
////////////////////////////////////////////////////////////////////
route.cxx
routePath.cxx
waypoint.cxx
+ PositionedBinding.cxx
)
flightgear_component(Navaids "${SOURCES}")
\ No newline at end of file
--- /dev/null
+#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
+
--- /dev/null
+#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
#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,
}
+flightgear::PositionedBinding*
+FGNavRecord::createBinding(SGPropertyNode* nd) const
+{
+ return new flightgear::NavaidBinding(this, nd);
+}
+
+
FGTACANRecord::FGTACANRecord(void) :
channel(""),
freq(0)
*/
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 {
#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;
{"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},
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
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;
+}
+
#include <simgear/math/SGMath.hxx>
class FGPositioned;
+class SGPropertyNode;
typedef SGSharedPtr<FGPositioned> FGPositionedRef;
+namespace flightgear
+{
+ class PositionedBinding;
+}
+
class FGPositioned : public SGReferenced
{
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;
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.
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);