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:
commit
f9a5f921a4
42 changed files with 1102 additions and 993 deletions
|
@ -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
|
||||
|
|
|
@ -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
67
src/ATC/CommStation.cxx
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "CommStation.hxx"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <Navaids/PositionedBinding.hxx>
|
||||
|
||||
namespace {
|
||||
|
||||
typedef std::multimap<int, flightgear::CommStation*> FrequencyMap;
|
||||
static FrequencyMap static_frequencies;
|
||||
|
||||
typedef std::pair<FrequencyMap::const_iterator, FrequencyMap::const_iterator> FrequencyMapRange;
|
||||
|
||||
} // of anonymous namespace
|
||||
|
||||
namespace flightgear {
|
||||
|
||||
CommStation::CommStation(const std::string& name, FGPositioned::Type t, const SGGeod& pos, int range, int freq) :
|
||||
FGPositioned(t, name, pos),
|
||||
mRangeNM(range),
|
||||
mFreqKhz(freq),
|
||||
mAirport(NULL)
|
||||
{
|
||||
static_frequencies.insert(std::make_pair(freq, this));
|
||||
|
||||
init(true);
|
||||
}
|
||||
|
||||
void CommStation::setAirport(FGAirport* apt)
|
||||
{
|
||||
mAirport = apt;
|
||||
}
|
||||
|
||||
double CommStation::freqMHz() const
|
||||
{
|
||||
return mFreqKhz / 100.0;
|
||||
}
|
||||
|
||||
PositionedBinding*
|
||||
CommStation::createBinding(SGPropertyNode* nd) const
|
||||
{
|
||||
return new CommStationBinding(this, nd);
|
||||
}
|
||||
|
||||
CommStation*
|
||||
CommStation::findByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt)
|
||||
{
|
||||
FrequencyMapRange range = static_frequencies.equal_range(freqKhz);
|
||||
FGPositioned::List results;
|
||||
for (; range.first != range.second; ++range.first) {
|
||||
CommStation* sta = range.first->second;
|
||||
if (filt && !filt->pass(sta)) {
|
||||
continue; // filtered out
|
||||
}
|
||||
|
||||
results.push_back(sta);
|
||||
}
|
||||
|
||||
if (results.empty()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FGPositioned::sortByRange(results, pos);
|
||||
return (CommStation*) results.front().ptr();
|
||||
}
|
||||
|
||||
} // of namespace flightgear
|
39
src/ATC/CommStation.hxx
Normal file
39
src/ATC/CommStation.hxx
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef FG_ATC_COMM_STATION_HXX
|
||||
#define FG_ATC_COMM_STATION_HXX
|
||||
|
||||
#include <Navaids/positioned.hxx>
|
||||
|
||||
class FGAirport;
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
|
||||
class CommStation : public FGPositioned
|
||||
{
|
||||
public:
|
||||
CommStation(const std::string& name, FGPositioned::Type t, const SGGeod& pos, int range, int freq);
|
||||
|
||||
void setAirport(FGAirport* apt);
|
||||
FGAirport* airport() const { return mAirport; }
|
||||
|
||||
virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const;
|
||||
|
||||
int rangeNm() const
|
||||
{ return mRangeNM; }
|
||||
|
||||
int freqKHz() const
|
||||
{ return mFreqKhz; }
|
||||
|
||||
double freqMHz() const;
|
||||
|
||||
static CommStation* findByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt = NULL);
|
||||
private:
|
||||
int mRangeNM;
|
||||
int mFreqKhz;
|
||||
FGAirport* mAirport;
|
||||
};
|
||||
|
||||
} // of namespace flightgear
|
||||
|
||||
#endif // of FG_ATC_COMM_STATION_HXX
|
||||
|
|
@ -1,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
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/******************************************************************************
|
||||
* atis.cxx
|
||||
* Written by Durk Talsma, started August 1, 2010.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include "atis_mgr.hxx"
|
||||
|
||||
FGAtisManager::FGAtisManager() {
|
||||
|
||||
}
|
||||
|
||||
FGAtisManager::~FGAtisManager() {
|
||||
|
||||
}
|
||||
|
||||
void FGAtisManager::init() {
|
||||
SGSubsystem::init();
|
||||
}
|
||||
|
||||
void FGAtisManager::update ( double time ) {
|
||||
//cerr << "ATIS code is running at time: " << time << endl;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/* -*- Mode: C++ -*- *****************************************************
|
||||
* atic.hxx
|
||||
* Written by Durk Talsma. Started August 1, 2010; based on earlier work
|
||||
* by David C. Luff
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef _ATIS_HXX_
|
||||
#define _ATIS_HXX_
|
||||
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
class FGAtisManager : public SGSubsystem
|
||||
{
|
||||
private:
|
||||
|
||||
public:
|
||||
FGAtisManager();
|
||||
~FGAtisManager();
|
||||
void init();
|
||||
void update(double time);
|
||||
};
|
||||
|
||||
#endif // _ATIS_HXX_
|
|
@ -31,8 +31,8 @@
|
|||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
|
||||
#include <ATC/CommStation.hxx>
|
||||
#include <Airports/simple.hxx>
|
||||
|
||||
FGATC::FGATC() :
|
||||
_playing(false),
|
||||
|
@ -181,14 +181,20 @@ void FGATC::NotifyTransmissionFinished(const string& rid) {
|
|||
}
|
||||
}
|
||||
|
||||
void FGATC::SetData(ATCData* d) {
|
||||
_type = d->type;
|
||||
_geod = d->geod;
|
||||
_cart = d->cart;
|
||||
range = d->range;
|
||||
ident = d->ident;
|
||||
name = d->name;
|
||||
freq = d->freq;
|
||||
void FGATC::SetStation(flightgear::CommStation* sta) {
|
||||
switch (sta->type()) {
|
||||
case FGPositioned::FREQ_ATIS: _type = ATIS; break;
|
||||
case FGPositioned::FREQ_AWOS: _type = AWOS; break;
|
||||
default:
|
||||
throw sg_exception("unsupported comm station type");
|
||||
}
|
||||
|
||||
_geod = sta->geod();
|
||||
_cart = sta->cart();
|
||||
range = sta->rangeNm();
|
||||
ident = sta->airport()->ident();
|
||||
name = sta->airport()->name();
|
||||
freq = sta->freqKHz();
|
||||
}
|
||||
|
||||
// Render a transmission
|
||||
|
|
|
@ -37,6 +37,11 @@
|
|||
|
||||
class SGSampleGroup;
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
class CommStation;
|
||||
}
|
||||
|
||||
// Convert a frequency in MHz to tens of kHz
|
||||
// so we can use it e.g. as an index into commlist_freq
|
||||
//
|
||||
|
@ -140,7 +145,7 @@ public:
|
|||
inline atc_type GetType() { return _type; }
|
||||
|
||||
// Set the core ATC data
|
||||
void SetData(ATCData* d);
|
||||
void SetStation(flightgear::CommStation* sta);
|
||||
|
||||
inline int get_freq() const { return freq; }
|
||||
inline void set_freq(const int fq) {freq = fq;}
|
||||
|
|
|
@ -34,9 +34,9 @@
|
|||
#include "ATCDialog.hxx"
|
||||
#include "ATC.hxx"
|
||||
#include "ATCmgr.hxx"
|
||||
#include "commlist.hxx"
|
||||
#include "ATCutils.hxx"
|
||||
#include <Airports/simple.hxx>
|
||||
#include <ATC/CommStation.hxx>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -3,7 +3,6 @@ include(FlightGearComponent)
|
|||
set(SOURCES
|
||||
ATC.cxx
|
||||
atis.cxx
|
||||
commlist.cxx
|
||||
ATCDialog.cxx
|
||||
ATCVoice.cxx
|
||||
ATCmgr.cxx
|
||||
|
|
|
@ -3,7 +3,6 @@ noinst_LIBRARIES = libATCDCL.a
|
|||
libATCDCL_a_SOURCES = \
|
||||
ATC.hxx ATC.cxx \
|
||||
atis.hxx atis.cxx \
|
||||
commlist.hxx commlist.cxx \
|
||||
ATCDialog.hxx ATCDialog.cxx \
|
||||
ATCVoice.hxx ATCVoice.cxx \
|
||||
ATCmgr.hxx ATCmgr.cxx \
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "atis_lexicon.hxx"
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/math/sg_random.h>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include <stdlib.h> // atoi()
|
||||
#include <stdio.h> // sprintf
|
||||
|
@ -44,9 +46,6 @@
|
|||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include <Environment/environment_mgr.hxx>
|
||||
#include <Environment/environment.hxx>
|
||||
#include <Environment/atmosphere.hxx>
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,302 +0,0 @@
|
|||
// commlist.cxx -- comm frequency lookup class
|
||||
//
|
||||
// Written by David Luff and Alexander Kappes, started Jan 2003.
|
||||
// Based on navlist.cxx by Curtis Olson, started April 2000.
|
||||
//
|
||||
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "commlist.hxx"
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/math/sg_random.h>
|
||||
#include <simgear/bucket/newbucket.hxx>
|
||||
#include <Airports/simple.hxx>
|
||||
|
||||
#include "ATCutils.hxx"
|
||||
|
||||
|
||||
FGCommList *current_commlist;
|
||||
|
||||
|
||||
// Constructor
|
||||
FGCommList::FGCommList( void ) {
|
||||
sg_srandom_time();
|
||||
}
|
||||
|
||||
|
||||
// Destructor
|
||||
FGCommList::~FGCommList( void ) {
|
||||
}
|
||||
|
||||
|
||||
// load the navaids and build the map
|
||||
bool FGCommList::init( const SGPath& path ) {
|
||||
|
||||
SGPath temp = path;
|
||||
commlist_freq.erase(commlist_freq.begin(), commlist_freq.end());
|
||||
commlist_bck.erase(commlist_bck.begin(), commlist_bck.end());
|
||||
temp.append( "ATC/default.atis" );
|
||||
LoadComms(temp);
|
||||
temp = path;
|
||||
temp.append( "ATC/default.tower" );
|
||||
LoadComms(temp);
|
||||
temp = path;
|
||||
temp.append( "ATC/default.ground" );
|
||||
LoadComms(temp);
|
||||
temp = path;
|
||||
temp.append( "ATC/default.approach" );
|
||||
LoadComms(temp);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FGCommList::LoadComms(const SGPath& path) {
|
||||
|
||||
sg_gzifstream fin( path.str() );
|
||||
if ( !fin.is_open() ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// read in each line of the file
|
||||
fin >> skipcomment;
|
||||
|
||||
while ( !fin.eof() ) {
|
||||
ATCData a;
|
||||
fin >> a;
|
||||
if(a.type == INVALID) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "WARNING - INVALID type found in " << path.str() << '\n');
|
||||
} else {
|
||||
// Push all stations onto frequency map
|
||||
commlist_freq[a.freq].push_back(a);
|
||||
|
||||
// Push non-atis stations onto bucket map as well
|
||||
// In fact, push all stations onto bucket map for now so FGATCMgr::GetFrequency() works.
|
||||
//if(a.type != ATIS and/or AWOS?) {
|
||||
// get bucket number
|
||||
SGBucket bucket(a.geod);
|
||||
int bucknum = bucket.gen_index();
|
||||
commlist_bck[bucknum].push_back(a);
|
||||
//}
|
||||
}
|
||||
|
||||
fin >> skipcomment;
|
||||
}
|
||||
|
||||
fin.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// query the database for the specified frequency, lon and lat are in
|
||||
// degrees, elev is in meters
|
||||
// If no atc_type is specified, it returns true if any non-invalid type is found
|
||||
// If atc_type is specifed, returns true only if the specified type is found
|
||||
bool FGCommList::FindByFreq(const SGGeod& aPos, double freq,
|
||||
ATCData* ad, atc_type tp )
|
||||
{
|
||||
comm_list_type stations;
|
||||
stations = commlist_freq[kHz10(freq)];
|
||||
comm_list_iterator current = stations.begin();
|
||||
comm_list_iterator last = stations.end();
|
||||
|
||||
// double az1, az2, s;
|
||||
SGVec3d aircraft = SGVec3d::fromGeod(aPos);
|
||||
const double orig_max_d = 1e100;
|
||||
double max_d = orig_max_d;
|
||||
double d;
|
||||
// TODO - at the moment this loop returns the first match found in range
|
||||
// We want to return the closest match in the event of a frequency conflict
|
||||
for ( ; current != last ; ++current ) {
|
||||
d = distSqr(aircraft, current->cart);
|
||||
|
||||
//cout << " dist = " << sqrt(d)
|
||||
// << " range = " << current->range * SG_NM_TO_METER << endl;
|
||||
|
||||
// TODO - match up to twice the published range so we can model
|
||||
// reduced signal strength
|
||||
// NOTE The below is squared since we match to distance3Dsquared (above) to avoid a sqrt.
|
||||
if ( d < (current->range * SG_NM_TO_METER
|
||||
* current->range * SG_NM_TO_METER ) ) {
|
||||
//cout << "matched = " << current->ident << endl;
|
||||
if((tp == INVALID) || (tp == (*current).type)) {
|
||||
if(d < max_d) {
|
||||
max_d = d;
|
||||
*ad = *current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(max_d < orig_max_d) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int FGCommList::FindByPos(const SGGeod& aPos, double range, comm_list_type* stations, atc_type tp)
|
||||
{
|
||||
// number of relevant stations found within range
|
||||
int found = 0;
|
||||
stations->erase(stations->begin(), stations->end());
|
||||
|
||||
// get bucket number for plane position
|
||||
SGBucket buck(aPos);
|
||||
|
||||
// get neigboring buckets
|
||||
int bx = (int)( range*SG_NM_TO_METER / buck.get_width_m() / 2) + 1;
|
||||
int by = (int)( range*SG_NM_TO_METER / buck.get_height_m() / 2 ) + 1;
|
||||
|
||||
// loop over bucket range
|
||||
for ( int i=-bx; i<=bx; i++) {
|
||||
for ( int j=-by; j<=by; j++) {
|
||||
buck = sgBucketOffset(aPos.getLongitudeDeg(), aPos.getLatitudeDeg(), i, j);
|
||||
long int bucket = buck.gen_index();
|
||||
comm_map_const_iterator Fstations = commlist_bck.find(bucket);
|
||||
if (Fstations == commlist_bck.end()) continue;
|
||||
comm_list_const_iterator current = Fstations->second.begin();
|
||||
comm_list_const_iterator last = Fstations->second.end();
|
||||
|
||||
|
||||
// double az1, az2, s;
|
||||
SGVec3d aircraft = SGVec3d::fromGeod(aPos);
|
||||
double d;
|
||||
for(; current != last; ++current) {
|
||||
if((current->type == tp) || (tp == INVALID)) {
|
||||
d = distSqr(aircraft, current->cart);
|
||||
// NOTE The below is squared since we match to distance3Dsquared (above) to avoid a sqrt.
|
||||
if ( d < (current->range * SG_NM_TO_METER
|
||||
* current->range * SG_NM_TO_METER ) ) {
|
||||
stations->push_back(*current);
|
||||
++found;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
// Returns the distance in meters to the closest station of a given type,
|
||||
// with the details written into ATCData& ad. If no type is specifed simply
|
||||
// returns the distance to the closest station of any type.
|
||||
// Returns -9999 if no stations found within max_range in nautical miles (default 100 miles).
|
||||
// Note that the search algorithm starts at 10 miles and multiplies by 10 thereafter, so if
|
||||
// say 300 miles is specifed 10, then 100, then 1000 will be searched, breaking at first result
|
||||
// and giving up after 1000.
|
||||
double FGCommList::FindClosest(const SGGeod& aPos, ATCData& ad, atc_type tp, double max_range) {
|
||||
int num_stations = 0;
|
||||
int range = 10;
|
||||
comm_list_type stations;
|
||||
comm_list_iterator itr;
|
||||
double distance = -9999.0;
|
||||
|
||||
while(num_stations == 0) {
|
||||
num_stations = FindByPos(aPos, range, &stations, tp);
|
||||
if(num_stations) {
|
||||
double closest = max_range * SG_NM_TO_METER;
|
||||
double tmp;
|
||||
for(itr = stations.begin(); itr != stations.end(); ++itr) {
|
||||
ATCData ad2 = *itr;
|
||||
const FGAirport *a = fgFindAirportID(ad2.ident);
|
||||
if (a) {
|
||||
tmp = dclGetHorizontalSeparation(ad2.geod, aPos);
|
||||
if(tmp <= closest) {
|
||||
closest = tmp;
|
||||
distance = tmp;
|
||||
ad = *itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
//cout << "Closest station is " << ad.ident << " at a range of " << distance << " meters\n";
|
||||
return(distance);
|
||||
}
|
||||
if(range > max_range) {
|
||||
break;
|
||||
}
|
||||
range *= 10;
|
||||
}
|
||||
return(-9999.0);
|
||||
}
|
||||
|
||||
|
||||
// Find by Airport code.
|
||||
// This is basically a wrapper for a call to the airport database to get the airport
|
||||
// position followed by a call to FindByPos(...)
|
||||
bool FGCommList::FindByCode( const string& ICAO, ATCData& ad, atc_type tp ) {
|
||||
const FGAirport *a = fgFindAirportID( ICAO);
|
||||
if ( a) {
|
||||
comm_list_type stations;
|
||||
int found = FindByPos(a->geod(), 10.0, &stations, tp);
|
||||
if(found) {
|
||||
comm_list_iterator itr = stations.begin();
|
||||
while(itr != stations.end()) {
|
||||
if(((*itr).ident == ICAO) && ((*itr).type == tp)) {
|
||||
ad = *itr;
|
||||
//cout << "FindByCode returns " << ICAO
|
||||
// << " type: " << tp
|
||||
// << " freq: " << itr->freq
|
||||
// << endl;
|
||||
return true;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO - this function should move somewhere else eventually!
|
||||
// Return an appropriate sequence number for an ATIS transmission.
|
||||
// Return sequence number + 2600 if sequence is unchanged since
|
||||
// last time.
|
||||
int FGCommList::GetAtisSequence( const string& apt_id,
|
||||
const double tstamp, const int interval, const int special)
|
||||
{
|
||||
atis_transmission_type tran;
|
||||
|
||||
if(atislog.find(apt_id) == atislog.end()) { // New station
|
||||
tran.tstamp = tstamp - interval;
|
||||
// Random number between 0 and 25 inclusive, i.e. 26 equiprobable outcomes:
|
||||
tran.sequence = int(sg_random() * LTRS);
|
||||
atislog[apt_id] = tran;
|
||||
//cout << "New ATIS station: " << apt_id << " seq-1: "
|
||||
// << tran.sequence << endl;
|
||||
}
|
||||
|
||||
// calculate the appropriate identifier and update the log
|
||||
tran = atislog[apt_id];
|
||||
|
||||
int delta = int((tstamp - tran.tstamp) / interval);
|
||||
tran.tstamp += delta * interval;
|
||||
if (special && !delta) delta++; // a "special" ATIS update is required
|
||||
tran.sequence = (tran.sequence + delta) % LTRS;
|
||||
atislog[apt_id] = tran;
|
||||
//if (delta) cout << "New ATIS sequence: " << tran.sequence
|
||||
// << " Delta: " << delta << endl;
|
||||
return(tran.sequence + (delta ? 0 : LTRS*1000));
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
// commlist.hxx -- comm frequency lookup class
|
||||
//
|
||||
// Written by David Luff and Alexander Kappes, started Jan 2003.
|
||||
// Based on navlist.hxx by Curtis Olson, started April 2000.
|
||||
//
|
||||
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
/*****************************************************************
|
||||
*
|
||||
* FGCommList is used to store communication frequency information
|
||||
* for the ATC and AI subsystems. Two maps are maintained - one
|
||||
* searchable by location and one searchable by frequency. The
|
||||
* data structure returned from the search is the ATCData struct
|
||||
* defined in ATC.hxx, containing location, frequency, name, range
|
||||
* and type of the returned station.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
#ifndef _FG_COMMLIST_HXX
|
||||
#define _FG_COMMLIST_HXX
|
||||
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "ATC.hxx"
|
||||
#include "atis.hxx"
|
||||
|
||||
class SGPath;
|
||||
|
||||
// A list of ATC stations
|
||||
typedef std::list < ATCData > comm_list_type;
|
||||
typedef comm_list_type::iterator comm_list_iterator;
|
||||
typedef comm_list_type::const_iterator comm_list_const_iterator;
|
||||
|
||||
// A map of ATC station lists
|
||||
typedef std::map < int, comm_list_type > comm_map_type;
|
||||
typedef comm_map_type::iterator comm_map_iterator;
|
||||
typedef comm_map_type::const_iterator comm_map_const_iterator;
|
||||
|
||||
|
||||
class FGCommList {
|
||||
|
||||
public:
|
||||
|
||||
FGCommList();
|
||||
~FGCommList();
|
||||
|
||||
// load all comm frequencies and build the map
|
||||
bool init( const SGPath& path );
|
||||
|
||||
// query the database for the specified frequency, lon and lat are
|
||||
// If no atc_type is specified, it returns true if any non-invalid type is found.
|
||||
// If atc_type is specifed, returns true only if the specified type is found.
|
||||
// Returns the station closest to the supplied position.
|
||||
// The data found is written into the passed-in ATCData structure.
|
||||
bool FindByFreq(const SGGeod& aPos, double freq, ATCData* ad, atc_type tp = INVALID );
|
||||
|
||||
// query the database by location, lon and lat are in degrees, elev is in meters, range is in nautical miles.
|
||||
// Returns the number of stations of the specified atc_type tp that are in range of the position defined by
|
||||
// lon, lat and elev, and pushes them into stations.
|
||||
// If no atc_type is specifed, returns the number of all stations in range, and pushes them into stations
|
||||
// ** stations is erased before use **
|
||||
int FindByPos(const SGGeod& aPos, double range, comm_list_type* stations, atc_type tp = INVALID );
|
||||
|
||||
// Returns the distance in meters to the closest station of a given type,
|
||||
// with the details written into ATCData& ad. If no type is specifed simply
|
||||
// returns the distance to the closest station of any type.
|
||||
// Returns -9999 if no stations found within max_range in nautical miles (default 100 miles).
|
||||
// Note that the search algorithm starts at 10 miles and multiplies by 10 thereafter, so if
|
||||
// say 300 miles is specifed 10, then 100, then 1000 will be searched, breaking at first result
|
||||
// and giving up after 1000.
|
||||
// !!!Be warned that searching anything over 100 miles will pause the sim unacceptably!!!
|
||||
// (The ability to search longer ranges should be used during init only).
|
||||
double FindClosest(const SGGeod& aPos, ATCData& ad, atc_type tp = INVALID, double max_range = 100.0 );
|
||||
|
||||
// Find by Airport code.
|
||||
bool FindByCode( const std::string& ICAO, ATCData& ad, atc_type tp = INVALID );
|
||||
|
||||
// Return the sequence letter for an ATIS transmission given transmission time and airport id
|
||||
// This maybe should get moved somewhere else!!
|
||||
int GetAtisSequence( const std::string& apt_id, const double tstamp,
|
||||
const int interval, const int flush=0);
|
||||
|
||||
// Comm stations mapped by frequency
|
||||
comm_map_type commlist_freq;
|
||||
|
||||
// Comm stations mapped by bucket
|
||||
comm_map_type commlist_bck;
|
||||
|
||||
// Load comms from a specified path (which must include the filename)
|
||||
private:
|
||||
|
||||
bool LoadComms(const SGPath& path);
|
||||
|
||||
//----------- This stuff is left over from atislist.[ch]xx and maybe should move somewhere else
|
||||
// Add structure and map for storing a log of atis transmissions
|
||||
// made in this session of FlightGear. This allows the callsign
|
||||
// to be allocated correctly wrt time.
|
||||
typedef struct {
|
||||
double tstamp;
|
||||
int sequence;
|
||||
} atis_transmission_type;
|
||||
|
||||
typedef std::map < std::string, atis_transmission_type > atis_log_type;
|
||||
typedef atis_log_type::iterator atis_log_iterator;
|
||||
typedef atis_log_type::const_iterator atis_log_const_iterator;
|
||||
|
||||
atis_log_type atislog;
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
||||
};
|
||||
|
||||
|
||||
extern FGCommList *current_commlist;
|
||||
|
||||
#endif // _FG_COMMLIST_HXX
|
||||
|
||||
|
|
@ -46,7 +46,8 @@
|
|||
#include "simple.hxx"
|
||||
#include "runways.hxx"
|
||||
#include "pavement.hxx"
|
||||
#include <ATCDCL/commlist.hxx>
|
||||
|
||||
#include <ATC/CommStation.hxx>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
@ -78,7 +79,7 @@ public:
|
|||
|
||||
|
||||
|
||||
void parseAPT(const string &aptdb_file, FGCommList *comm_list)
|
||||
void parseAPT(const string &aptdb_file)
|
||||
{
|
||||
sg_gzifstream in( aptdb_file );
|
||||
|
||||
|
@ -157,12 +158,8 @@ public:
|
|||
// custom startup locations (ignore)
|
||||
} else if ( line_id == 0 ) {
|
||||
// ??
|
||||
} else if ( line_id == 50 ) {
|
||||
|
||||
parseATISLine(comm_list, simgear::strutils::split(line));
|
||||
|
||||
} else if ( line_id >= 51 && line_id <= 56 ) {
|
||||
// other frequency entries (ignore)
|
||||
} else if ( line_id >= 50 && line_id <= 56) {
|
||||
parseCommLine(line_id, simgear::strutils::split(line));
|
||||
} else if ( line_id == 110 ) {
|
||||
pavement = true;
|
||||
parsePavementLine850(simgear::strutils::split(line, 0, 4));
|
||||
|
@ -206,6 +203,7 @@ private:
|
|||
vector<FGRunwayPtr> runways;
|
||||
vector<FGTaxiwayPtr> taxiways;
|
||||
vector<FGPavementPtr> pavements;
|
||||
vector<flightgear::CommStation*> commStations;
|
||||
|
||||
void addAirport()
|
||||
{
|
||||
|
@ -235,6 +233,7 @@ private:
|
|||
FGAirport* apt = new FGAirport(last_apt_id, pos, tower, last_apt_name, false,
|
||||
fptypeFromRobinType(atoi(last_apt_type.c_str())));
|
||||
apt->setRunwaysAndTaxiways(runways, taxiways, pavements);
|
||||
apt->setCommStations(commStations);
|
||||
}
|
||||
|
||||
void parseAirportLine(const vector<string>& token)
|
||||
|
@ -466,48 +465,38 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void parseATISLine(FGCommList *comm_list, const vector<string>& token)
|
||||
void parseCommLine(int lineId, const vector<string>& token)
|
||||
{
|
||||
if ( rwy_count <= 0 ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||
"No runways; skipping AWOS for " + last_apt_id);
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "No runways; skipping comm for " + last_apt_id);
|
||||
}
|
||||
|
||||
// This assumes/requires that any code-50 line (ATIS or AWOS)
|
||||
// applies to the preceding code-1 line (airport ID and name)
|
||||
// and that a full set of code-10 lines (runway descriptors)
|
||||
// has come between the code-1 and code-50 lines.
|
||||
// typical code-50 lines:
|
||||
// 50 11770 ATIS
|
||||
// 50 11770 AWOS 3
|
||||
// This code parallels code found in "operator>>" in ATC.hxx;
|
||||
// FIXME: unify the code.
|
||||
ATCData a;
|
||||
a.geod = SGGeod::fromDegFt(rwy_lon_accum / (double)rwy_count,
|
||||
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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
#include "runwaybase.hxx"
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@ public:
|
|||
{ return _surface_code; }
|
||||
|
||||
protected:
|
||||
|
||||
double _heading;
|
||||
double _length;
|
||||
double _width;
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
|
||||
#include <Airports/simple.hxx>
|
||||
#include <Navaids/procedure.hxx>
|
||||
#include <Navaids/navrecord.hxx>
|
||||
#include <Navaids/PositionedBinding.hxx>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -197,4 +199,9 @@ std::vector<flightgear::STAR*> FGRunway::getSTARs()
|
|||
return result;
|
||||
}
|
||||
|
||||
flightgear::PositionedBinding*
|
||||
FGRunway::createBinding(SGPropertyNode* nd) const
|
||||
{
|
||||
return new flightgear::RunwayBinding(this, nd);
|
||||
}
|
||||
|
||||
|
|
|
@ -116,6 +116,8 @@ public:
|
|||
{ return _reciprocal; }
|
||||
void setReciprocalRunway(FGRunway* other);
|
||||
|
||||
virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const;
|
||||
|
||||
/**
|
||||
* Helper to process property data loaded from an ICAO.threshold.xml file
|
||||
*/
|
||||
|
@ -130,6 +132,7 @@ public:
|
|||
* Get STARs associared with this runway
|
||||
*/
|
||||
std::vector<flightgear::STAR*> getSTARs();
|
||||
|
||||
};
|
||||
|
||||
#endif // _FG_RUNWAYS_HXX
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
#include <Airports/xmlloader.hxx>
|
||||
#include <Navaids/procedure.hxx>
|
||||
#include <Navaids/waypoint.hxx>
|
||||
#include <Navaids/PositionedBinding.hxx>
|
||||
#include <ATC/CommStation.hxx>
|
||||
|
||||
using std::vector;
|
||||
using namespace flightgear;
|
||||
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -50,10 +50,12 @@ namespace flightgear {
|
|||
class STAR;
|
||||
class Approach;
|
||||
class Waypt;
|
||||
|
||||
class CommStation;
|
||||
|
||||
typedef SGSharedPtr<Waypt> WayptRef;
|
||||
typedef std::vector<WayptRef> WayptVec;
|
||||
|
||||
typedef std::vector<CommStation*> CommStationList;
|
||||
}
|
||||
|
||||
|
||||
|
@ -185,6 +187,8 @@ public:
|
|||
unsigned int numApproaches() const;
|
||||
flightgear::Approach* getApproachByIndex(unsigned int aIndex) const;
|
||||
|
||||
static void installPropertyListener();
|
||||
|
||||
/**
|
||||
* Syntactic wrapper around FGPositioned::findClosest - find the closest
|
||||
* match for filter, and return it cast to FGAirport. The default filter
|
||||
|
@ -228,6 +232,14 @@ public:
|
|||
*/
|
||||
std::pair<flightgear::STAR*, flightgear::WayptRef> selectSTAR(const SGGeod& aOrigin, FGRunway* aRwy);
|
||||
|
||||
virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const;
|
||||
|
||||
void setCommStations(flightgear::CommStationList& comms);
|
||||
|
||||
flightgear::CommStationList commStationsOfType(FGPositioned::Type aTy) const;
|
||||
|
||||
const flightgear::CommStationList& commStations() const
|
||||
{ return mCommStations; }
|
||||
private:
|
||||
typedef std::vector<FGRunwayPtr>::const_iterator Runway_iterator;
|
||||
/**
|
||||
|
@ -275,6 +287,8 @@ private:
|
|||
std::vector<flightgear::SID*> mSIDs;
|
||||
std::vector<flightgear::STAR*> mSTARs;
|
||||
std::vector<flightgear::Approach*> mApproaches;
|
||||
|
||||
flightgear::CommStationList mCommStations;
|
||||
};
|
||||
|
||||
// find basic airport location info from airport database
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/structure/commands.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
|
||||
#include <simgear/props/props_io.hxx>
|
||||
|
@ -109,6 +110,151 @@ PropertyWatcher* createWatcher(T* obj, void (T::*m)())
|
|||
return new MethodPropertyWatcher<T>(obj, m);
|
||||
}
|
||||
|
||||
static bool commandLoadFlightPlan(const SGPropertyNode* arg)
|
||||
{
|
||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||
SGPath path(arg->getStringValue("path"));
|
||||
return self->loadRoute(path);
|
||||
}
|
||||
|
||||
static bool commandSaveFlightPlan(const SGPropertyNode* arg)
|
||||
{
|
||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||
SGPath path(arg->getStringValue("path"));
|
||||
return self->saveRoute(path);
|
||||
}
|
||||
|
||||
static bool commandActivateFlightPlan(const SGPropertyNode* arg)
|
||||
{
|
||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||
bool activate = arg->getBoolValue("activate", true);
|
||||
if (activate) {
|
||||
self->activate();
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool commandClearFlightPlan(const SGPropertyNode*)
|
||||
{
|
||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||
self->clearRoute();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool commandSetActiveWaypt(const SGPropertyNode* arg)
|
||||
{
|
||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||
int index = arg->getIntValue("index");
|
||||
if ((index < 0) || (index >= self->numWaypts())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self->jumpToIndex(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool commandInsertWaypt(const SGPropertyNode* arg)
|
||||
{
|
||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||
int index = arg->getIntValue("index");
|
||||
std::string ident(arg->getStringValue("id"));
|
||||
int alt = arg->getIntValue("altitude-ft", -999);
|
||||
int ias = arg->getIntValue("speed-knots", -999);
|
||||
|
||||
WayptRef wp;
|
||||
// lat/lon may be supplied to narrow down navaid search, or to specify
|
||||
// a raw waypoint
|
||||
SGGeod pos;
|
||||
if (arg->hasChild("longitude-deg")) {
|
||||
pos = SGGeod::fromDeg(arg->getDoubleValue("longitude-deg"),
|
||||
arg->getDoubleValue("latitude-deg"));
|
||||
}
|
||||
|
||||
if (arg->hasChild("navaid")) {
|
||||
FGPositionedRef p = FGPositioned::findClosestWithIdent(arg->getStringValue("navaid"), pos);
|
||||
|
||||
if (arg->hasChild("navaid", 1)) {
|
||||
// intersection of two radials
|
||||
FGPositionedRef p2 = FGPositioned::findClosestWithIdent(arg->getStringValue("navaid[1]"), pos);
|
||||
if (!p2) {
|
||||
SG_LOG( SG_AUTOPILOT, SG_INFO, "Unable to find FGPositioned with ident:" << arg->getStringValue("navaid[1]"));
|
||||
return false;
|
||||
}
|
||||
|
||||
double r1 = arg->getDoubleValue("radial"),
|
||||
r2 = arg->getDoubleValue("radial[1]");
|
||||
|
||||
SGGeod intersection;
|
||||
bool ok = SGGeodesy::radialIntersection(p->geod(), r1, p2->geod(), r2, intersection);
|
||||
if (!ok) {
|
||||
SG_LOG(SG_AUTOPILOT, SG_INFO, "no valid intersection for:" << p->ident()
|
||||
<< "," << p2->ident());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string name = p->ident() + "-" + p2->ident();
|
||||
wp = new BasicWaypt(intersection, name, NULL);
|
||||
} else if (arg->hasChild("offset-nm") && arg->hasChild("radial")) {
|
||||
// offset radial from navaid
|
||||
double radial = arg->getDoubleValue("radial");
|
||||
double distanceNm = arg->getDoubleValue("offset-nm");
|
||||
//radial += magvar->getDoubleValue(); // convert to true bearing
|
||||
wp = new OffsetNavaidWaypoint(p, NULL, radial, distanceNm);
|
||||
} else {
|
||||
wp = new NavaidWaypoint(p, NULL);
|
||||
}
|
||||
} else if (arg->hasChild("airport")) {
|
||||
const FGAirport* apt = fgFindAirportID(arg->getStringValue("airport"));
|
||||
if (!apt) {
|
||||
SG_LOG(SG_AUTOPILOT, SG_INFO, "no such airport" << arg->getStringValue("airport"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arg->hasChild("runway")) {
|
||||
if (!apt->hasRunwayWithIdent(arg->getStringValue("runway"))) {
|
||||
SG_LOG(SG_AUTOPILOT, SG_INFO, "No runway: " << arg->getStringValue("runway") << " at " << apt->ident());
|
||||
return false;
|
||||
}
|
||||
|
||||
FGRunway* runway = apt->getRunwayByIdent(arg->getStringValue("runway"));
|
||||
wp = new RunwayWaypt(runway, NULL);
|
||||
} else {
|
||||
wp = new NavaidWaypoint((FGAirport*) apt, NULL);
|
||||
}
|
||||
} else if (arg->hasChild("text")) {
|
||||
wp = self->waypointFromString(arg->getStringValue("text"));
|
||||
} else if (!(pos == SGGeod())) {
|
||||
// just a raw lat/lon
|
||||
wp = new BasicWaypt(pos, ident, NULL);
|
||||
} else {
|
||||
return false; // failed to build waypoint
|
||||
}
|
||||
|
||||
if (alt >= 0) {
|
||||
wp->setAltitude(alt, flightgear::RESTRICT_AT);
|
||||
}
|
||||
|
||||
if (ias > 0) {
|
||||
wp->setSpeed(ias, flightgear::RESTRICT_AT);
|
||||
}
|
||||
|
||||
self->insertWayptAtIndex(wp, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool commandDeleteWaypt(const SGPropertyNode* arg)
|
||||
{
|
||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||
int index = arg->getIntValue("index");
|
||||
self->removeWayptAtIndex(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FGRouteMgr::FGRouteMgr() :
|
||||
_currentIndex(0),
|
||||
input(fgGetNode( RM "input", true )),
|
||||
|
@ -117,6 +263,14 @@ FGRouteMgr::FGRouteMgr() :
|
|||
listener = new InputListener(this);
|
||||
input->setStringValue("");
|
||||
input->addChangeListener(listener);
|
||||
|
||||
SGCommandMgr::instance()->addCommand("load-flightplan", commandLoadFlightPlan);
|
||||
SGCommandMgr::instance()->addCommand("save-flightplan", commandSaveFlightPlan);
|
||||
SGCommandMgr::instance()->addCommand("activate-flightplan", commandActivateFlightPlan);
|
||||
SGCommandMgr::instance()->addCommand("clear-flightplan", commandClearFlightPlan);
|
||||
SGCommandMgr::instance()->addCommand("set-active-waypt", commandSetActiveWaypt);
|
||||
SGCommandMgr::instance()->addCommand("insert-waypt", commandInsertWaypt);
|
||||
SGCommandMgr::instance()->addCommand("delete-waypt", commandDeleteWaypt);
|
||||
}
|
||||
|
||||
|
||||
|
@ -227,7 +381,7 @@ void FGRouteMgr::postinit()
|
|||
SGPath path(_pathNode->getStringValue());
|
||||
if (path.exists()) {
|
||||
SG_LOG(SG_AUTOPILOT, SG_INFO, "loading flight-plan from:" << path.str());
|
||||
loadRoute();
|
||||
loadRoute(path);
|
||||
}
|
||||
|
||||
// this code only matters for the --wp option now - perhaps the option
|
||||
|
@ -897,11 +1051,11 @@ void FGRouteMgr::InputListener::valueChanged(SGPropertyNode *prop)
|
|||
else if (!strcmp(s, "@ACTIVATE"))
|
||||
mgr->activate();
|
||||
else if (!strcmp(s, "@LOAD")) {
|
||||
mgr->loadRoute();
|
||||
SGPath path(mgr->_pathNode->getStringValue());
|
||||
mgr->loadRoute(path);
|
||||
} else if (!strcmp(s, "@SAVE")) {
|
||||
mgr->saveRoute();
|
||||
} else if (!strcmp(s, "@POP")) {
|
||||
SG_LOG(SG_AUTOPILOT, SG_WARN, "route-manager @POP command is deprecated");
|
||||
SGPath path(mgr->_pathNode->getStringValue());
|
||||
mgr->saveRoute(path);
|
||||
} else if (!strcmp(s, "@NEXT")) {
|
||||
mgr->jumpToIndex(mgr->_currentIndex + 1);
|
||||
} else if (!strcmp(s, "@PREVIOUS")) {
|
||||
|
@ -1119,9 +1273,8 @@ Waypt* FGRouteMgr::wayptAtIndex(int index) const
|
|||
return _route[index];
|
||||
}
|
||||
|
||||
void FGRouteMgr::saveRoute()
|
||||
bool FGRouteMgr::saveRoute(const SGPath& path)
|
||||
{
|
||||
SGPath path(_pathNode->getStringValue());
|
||||
SG_LOG(SG_IO, SG_INFO, "Saving route to " << path.str());
|
||||
try {
|
||||
SGPropertyNode_ptr d(new SGPropertyNode);
|
||||
|
@ -1148,18 +1301,19 @@ void FGRouteMgr::saveRoute()
|
|||
wpt->saveAsNode(routeNode->getChild("wp", i, true));
|
||||
} // of waypoint iteration
|
||||
writeProperties(path.str(), d, true /* write-all */);
|
||||
return true;
|
||||
} catch (sg_exception& e) {
|
||||
SG_LOG(SG_IO, SG_WARN, "failed to save flight-plan:" << e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FGRouteMgr::loadRoute()
|
||||
bool FGRouteMgr::loadRoute(const SGPath& path)
|
||||
{
|
||||
// deactivate route first
|
||||
active->setBoolValue(false);
|
||||
|
||||
SGPropertyNode_ptr routeData(new SGPropertyNode);
|
||||
SGPath path(_pathNode->getStringValue());
|
||||
|
||||
SG_LOG(SG_IO, SG_INFO, "going to read flight-plan from:" << path.str());
|
||||
|
||||
|
@ -1167,8 +1321,7 @@ void FGRouteMgr::loadRoute()
|
|||
readProperties(path.str(), routeData);
|
||||
} catch (sg_exception& ) {
|
||||
// if XML parsing fails, the file might be simple textual list of waypoints
|
||||
loadPlainTextRoute(path);
|
||||
return;
|
||||
return loadPlainTextRoute(path);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -1180,9 +1333,11 @@ void FGRouteMgr::loadRoute()
|
|||
} else {
|
||||
throw sg_io_exception("unsupported XML route version");
|
||||
}
|
||||
return true;
|
||||
} catch (sg_exception& e) {
|
||||
SG_LOG(SG_IO, SG_WARN, "failed to load flight-plan (from '" << e.getOrigin()
|
||||
<< "'):" << e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1299,11 +1454,11 @@ WayptRef FGRouteMgr::parseVersion1XMLWaypt(SGPropertyNode* aWP)
|
|||
return w;
|
||||
}
|
||||
|
||||
void FGRouteMgr::loadPlainTextRoute(const SGPath& path)
|
||||
bool FGRouteMgr::loadPlainTextRoute(const SGPath& path)
|
||||
{
|
||||
sg_gzifstream in(path.str().c_str());
|
||||
if (!in.is_open()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -1330,8 +1485,10 @@ void FGRouteMgr::loadPlainTextRoute(const SGPath& path)
|
|||
} // of line iteration
|
||||
|
||||
_route = wpts;
|
||||
return true;
|
||||
} catch (sg_exception& e) {
|
||||
SG_LOG(SG_IO, SG_WARN, "failed to load route from:" << path.str() << ":" << e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -118,13 +118,22 @@ public:
|
|||
*/
|
||||
void jumpToIndex(int index);
|
||||
|
||||
void saveRoute();
|
||||
void loadRoute();
|
||||
bool saveRoute(const SGPath& p);
|
||||
bool loadRoute(const SGPath& p);
|
||||
|
||||
/**
|
||||
* Helper command to setup current airport/runway if necessary
|
||||
*/
|
||||
void initAtPosition();
|
||||
|
||||
/**
|
||||
* Create a WayPoint from a string in the following format:
|
||||
* - simple identifier
|
||||
* - decimal-lon,decimal-lat
|
||||
* - airport-id/runway-id
|
||||
* - navaid/radial-deg/offset-nm
|
||||
*/
|
||||
flightgear::WayptRef waypointFromString(const std::string& target);
|
||||
private:
|
||||
flightgear::WayptVec _route;
|
||||
int _currentIndex;
|
||||
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -42,7 +42,6 @@ Somigliana::Somigliana()
|
|||
Somigliana::~Somigliana()
|
||||
{
|
||||
}
|
||||
#include <stdio.h>
|
||||
|
||||
double Somigliana::getGravity( const SGGeod & position ) const
|
||||
{
|
||||
|
|
|
@ -301,9 +301,6 @@ void MetarProperties::set_metar( const char * metar )
|
|||
}
|
||||
}
|
||||
|
||||
vector<SGMetarCloud> cv = m->getClouds();
|
||||
vector<SGMetarCloud>::const_iterator cloud, cloud_end = cv.end();
|
||||
|
||||
{
|
||||
static const char * LAYER = "layer";
|
||||
SGPropertyNode_ptr cloudsNode = _rootNode->getNode("clouds", true );
|
||||
|
|
|
@ -285,6 +285,7 @@ void AreaSampler::analyse()
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
double alt_low_min = 0.0;
|
||||
double n_max = 0.0;
|
||||
sum = 0.0;
|
||||
|
@ -296,7 +297,7 @@ void AreaSampler::analyse()
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
_altLayered = 0.5 * (_altMin + _altOffset);
|
||||
|
||||
#if 0
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -13,6 +13,7 @@ set(SOURCES
|
|||
route.cxx
|
||||
routePath.cxx
|
||||
waypoint.cxx
|
||||
PositionedBinding.cxx
|
||||
)
|
||||
|
||||
flightgear_component(Navaids "${SOURCES}")
|
173
src/Navaids/PositionedBinding.cxx
Normal file
173
src/Navaids/PositionedBinding.cxx
Normal 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
|
||||
|
63
src/Navaids/PositionedBinding.hxx
Normal file
63
src/Navaids/PositionedBinding.hxx
Normal file
|
@ -0,0 +1,63 @@
|
|||
#ifndef FG_POSITIONED_BINDING_HXX
|
||||
#define FG_POSITIONED_BINDING_HXX
|
||||
|
||||
#include <simgear/props/tiedpropertylist.hxx>
|
||||
|
||||
#include "positioned.hxx"
|
||||
|
||||
// forward decls
|
||||
class FGNavRecord;
|
||||
class FGRunway;
|
||||
class FGAirport;
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
|
||||
// forward decls
|
||||
class CommStation;
|
||||
|
||||
class PositionedBinding
|
||||
{
|
||||
public:
|
||||
virtual ~PositionedBinding();
|
||||
|
||||
static void bind(FGPositioned* pos, SGPropertyNode* node);
|
||||
|
||||
|
||||
PositionedBinding(const FGPositioned* pos, SGPropertyNode* node);
|
||||
|
||||
protected:
|
||||
FGPositionedRef p; // bindings own a reference to their positioned
|
||||
simgear::TiedPropertyList tied;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
class NavaidBinding : public PositionedBinding
|
||||
{
|
||||
public:
|
||||
NavaidBinding(const FGNavRecord* nav, SGPropertyNode* node);
|
||||
};
|
||||
|
||||
class RunwayBinding : public PositionedBinding
|
||||
{
|
||||
public:
|
||||
RunwayBinding(const FGRunway* rwy, SGPropertyNode* node);
|
||||
};
|
||||
|
||||
class AirportBinding : public PositionedBinding
|
||||
{
|
||||
public:
|
||||
AirportBinding(const FGAirport* apt, SGPropertyNode* node);
|
||||
};
|
||||
|
||||
class CommStationBinding : public PositionedBinding
|
||||
{
|
||||
public:
|
||||
CommStationBinding(const CommStation* sta, SGPropertyNode* node);
|
||||
};
|
||||
|
||||
} // of namespace flightgear
|
||||
|
||||
#endif // of FG_POSITIONED_BINDING_HXX
|
|
@ -41,6 +41,7 @@
|
|||
#include <Airports/xmlloader.hxx>
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Navaids/PositionedBinding.hxx>
|
||||
|
||||
FGNavRecord::FGNavRecord(Type aTy, const std::string& aIdent,
|
||||
const std::string& aName, const SGGeod& aPos,
|
||||
|
@ -187,6 +188,13 @@ double FGNavRecord::localizerWidth() const
|
|||
|
||||
}
|
||||
|
||||
flightgear::PositionedBinding*
|
||||
FGNavRecord::createBinding(SGPropertyNode* nd) const
|
||||
{
|
||||
return new flightgear::NavaidBinding(this, nd);
|
||||
}
|
||||
|
||||
|
||||
FGTACANRecord::FGTACANRecord(void) :
|
||||
channel(""),
|
||||
freq(0)
|
||||
|
|
|
@ -89,12 +89,17 @@ public:
|
|||
*/
|
||||
FGRunway* runway() const { return mRunway; }
|
||||
|
||||
virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const;
|
||||
|
||||
/**
|
||||
* return the localizer width, in degrees
|
||||
* computation is based up ICAO stdandard width at the runway threshold
|
||||
* see implementation for further details.
|
||||
*/
|
||||
double localizerWidth() const;
|
||||
|
||||
void bindToNode(SGPropertyNode* nd) const;
|
||||
void unbindFromNode(SGPropertyNode* nd) const;
|
||||
};
|
||||
|
||||
class FGTACANRecord : public SGReferenced {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue