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"
|
RelativePath="..\..\..\src\ATCDCL\atis.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\..\src\ATCDCL\commlist.cxx"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\..\src\ATCDCL\commlist.hxx"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Lib_Autopilot"
|
Name="Lib_Autopilot"
|
||||||
|
@ -2449,14 +2441,6 @@
|
||||||
RelativePath="..\..\..\src\FDM\fdm_shell.hxx"
|
RelativePath="..\..\..\src\FDM\fdm_shell.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\..\src\FDM\TankProperties.cxx"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\..\src\FDM\TankProperties.hxx"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\FDM\flight.cxx"
|
RelativePath="..\..\..\src\FDM\flight.cxx"
|
||||||
>
|
>
|
||||||
|
@ -2489,6 +2473,14 @@
|
||||||
RelativePath="..\..\..\src\FDM\NullFDM.hxx"
|
RelativePath="..\..\..\src\FDM\NullFDM.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\FDM\TankProperties.cxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\FDM\TankProperties.hxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Lib_GUI"
|
Name="Lib_GUI"
|
||||||
|
@ -2893,6 +2885,14 @@
|
||||||
RelativePath="..\..\..\src\Navaids\positioned.hxx"
|
RelativePath="..\..\..\src\Navaids\positioned.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\Navaids\PositionedBinding.cxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\Navaids\PositionedBinding.hxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\Navaids\procedure.cxx"
|
RelativePath="..\..\..\src\Navaids\procedure.cxx"
|
||||||
>
|
>
|
||||||
|
@ -3220,7 +3220,7 @@
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\Sound\voice.hxx"
|
RelativePath="..\..\..\src\Sound\voice.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\Sound\voiceplayer.cxx"
|
RelativePath="..\..\..\src\Sound\voiceplayer.cxx"
|
||||||
>
|
>
|
||||||
|
@ -3381,6 +3381,14 @@
|
||||||
RelativePath="..\..\..\src\Environment\fgwind.hxx"
|
RelativePath="..\..\..\src\Environment\fgwind.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\Environment\gravity.cxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\Environment\gravity.hxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\Environment\metarairportfilter.cxx"
|
RelativePath="..\..\..\src\Environment\metarairportfilter.cxx"
|
||||||
>
|
>
|
||||||
|
@ -3405,6 +3413,14 @@
|
||||||
RelativePath="..\..\..\src\Environment\precipitation_mgr.hxx"
|
RelativePath="..\..\..\src\Environment\precipitation_mgr.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\Environment\presets.cxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\Environment\presets.hxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\Environment\realwx_ctrl.cxx"
|
RelativePath="..\..\..\src\Environment\realwx_ctrl.cxx"
|
||||||
>
|
>
|
||||||
|
@ -3429,22 +3445,6 @@
|
||||||
RelativePath="..\..\..\src\Environment\terrainsampler.hxx"
|
RelativePath="..\..\..\src\Environment\terrainsampler.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</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>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Lib_Model"
|
Name="Lib_Model"
|
||||||
|
@ -3769,6 +3769,14 @@
|
||||||
RelativePath="..\..\..\src\Instrumentation\tacan.hxx"
|
RelativePath="..\..\..\src\Instrumentation\tacan.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\Instrumentation\tcas.cxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\Instrumentation\tcas.hxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\Instrumentation\transponder.cxx"
|
RelativePath="..\..\..\src\Instrumentation\transponder.cxx"
|
||||||
>
|
>
|
||||||
|
@ -3800,14 +3808,6 @@
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\Instrumentation\wxradar.hxx"
|
RelativePath="..\..\..\src\Instrumentation\wxradar.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\..\src\Instrumentation\tcas.cxx"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\..\src\Instrumentation\tcas.hxx"
|
|
||||||
>
|
|
||||||
</File>
|
</File>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Lib_HUD"
|
Name="Lib_HUD"
|
||||||
|
@ -4310,11 +4310,11 @@
|
||||||
Name="Lib_ATC"
|
Name="Lib_ATC"
|
||||||
>
|
>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\ATC\atis_mgr.cxx"
|
RelativePath="..\..\..\src\ATC\CommStation.cxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\ATC\atis_mgr.hxx"
|
RelativePath="..\..\..\src\ATC\CommStation.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
include(FlightGearComponent)
|
include(FlightGearComponent)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
atis_mgr.cxx
|
|
||||||
atc_mgr.cxx
|
atc_mgr.cxx
|
||||||
trafficcontrol.cxx
|
trafficcontrol.cxx
|
||||||
|
CommStation.cxx
|
||||||
)
|
)
|
||||||
|
|
||||||
flightgear_component(ATC "${SOURCES}")
|
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
|
noinst_LIBRARIES = libATC.a
|
||||||
|
|
||||||
libATC_a_SOURCES = \
|
libATC_a_SOURCES = \
|
||||||
atis_mgr.cxx atis_mgr.hxx \
|
|
||||||
atcdialog.cxx atcdialog.hxx \
|
atcdialog.cxx atcdialog.hxx \
|
||||||
atc_mgr.cxx atc_mgr.hxx \
|
atc_mgr.cxx atc_mgr.hxx \
|
||||||
|
CommStation.cxx CommStation.hxx \
|
||||||
trafficcontrol.cxx trafficcontrol.hxx
|
trafficcontrol.cxx trafficcontrol.hxx
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
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/globals.hxx>
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
|
#include <ATC/CommStation.hxx>
|
||||||
|
#include <Airports/simple.hxx>
|
||||||
|
|
||||||
FGATC::FGATC() :
|
FGATC::FGATC() :
|
||||||
_playing(false),
|
_playing(false),
|
||||||
|
@ -181,14 +181,20 @@ void FGATC::NotifyTransmissionFinished(const string& rid) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGATC::SetData(ATCData* d) {
|
void FGATC::SetStation(flightgear::CommStation* sta) {
|
||||||
_type = d->type;
|
switch (sta->type()) {
|
||||||
_geod = d->geod;
|
case FGPositioned::FREQ_ATIS: _type = ATIS; break;
|
||||||
_cart = d->cart;
|
case FGPositioned::FREQ_AWOS: _type = AWOS; break;
|
||||||
range = d->range;
|
default:
|
||||||
ident = d->ident;
|
throw sg_exception("unsupported comm station type");
|
||||||
name = d->name;
|
}
|
||||||
freq = d->freq;
|
|
||||||
|
_geod = sta->geod();
|
||||||
|
_cart = sta->cart();
|
||||||
|
range = sta->rangeNm();
|
||||||
|
ident = sta->airport()->ident();
|
||||||
|
name = sta->airport()->name();
|
||||||
|
freq = sta->freqKHz();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render a transmission
|
// Render a transmission
|
||||||
|
|
|
@ -37,6 +37,11 @@
|
||||||
|
|
||||||
class SGSampleGroup;
|
class SGSampleGroup;
|
||||||
|
|
||||||
|
namespace flightgear
|
||||||
|
{
|
||||||
|
class CommStation;
|
||||||
|
}
|
||||||
|
|
||||||
// Convert a frequency in MHz to tens of kHz
|
// Convert a frequency in MHz to tens of kHz
|
||||||
// so we can use it e.g. as an index into commlist_freq
|
// so we can use it e.g. as an index into commlist_freq
|
||||||
//
|
//
|
||||||
|
@ -140,7 +145,7 @@ public:
|
||||||
inline atc_type GetType() { return _type; }
|
inline atc_type GetType() { return _type; }
|
||||||
|
|
||||||
// Set the core ATC data
|
// Set the core ATC data
|
||||||
void SetData(ATCData* d);
|
void SetStation(flightgear::CommStation* sta);
|
||||||
|
|
||||||
inline int get_freq() const { return freq; }
|
inline int get_freq() const { return freq; }
|
||||||
inline void set_freq(const int fq) {freq = fq;}
|
inline void set_freq(const int fq) {freq = fq;}
|
||||||
|
|
|
@ -34,9 +34,9 @@
|
||||||
#include "ATCDialog.hxx"
|
#include "ATCDialog.hxx"
|
||||||
#include "ATC.hxx"
|
#include "ATC.hxx"
|
||||||
#include "ATCmgr.hxx"
|
#include "ATCmgr.hxx"
|
||||||
#include "commlist.hxx"
|
|
||||||
#include "ATCutils.hxx"
|
#include "ATCutils.hxx"
|
||||||
#include <Airports/simple.hxx>
|
#include <Airports/simple.hxx>
|
||||||
|
#include <ATC/CommStation.hxx>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
@ -287,21 +287,17 @@ void FGATCDialog::PopupCallback(int num) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// map() key data type (removes duplicates and sorts by distance)
|
class AirportsWithATC : public FGAirport::AirportFilter
|
||||||
struct atcdata {
|
{
|
||||||
atcdata() {}
|
public:
|
||||||
atcdata(const string i, const string n, const double d) {
|
virtual FGPositioned::Type maxType() const {
|
||||||
id = i, name = n, distance = d;
|
return FGPositioned::SEAPORT;
|
||||||
}
|
}
|
||||||
bool operator<(const atcdata& a) const {
|
|
||||||
return id != a.id && distance < a.distance;
|
virtual bool passAirport(FGAirport* aApt) const
|
||||||
}
|
{
|
||||||
bool operator==(const atcdata& a) const {
|
return (!aApt->commStations().empty());
|
||||||
return id == a.id && distance == a.distance;
|
}
|
||||||
}
|
|
||||||
string id;
|
|
||||||
string name;
|
|
||||||
double distance;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void FGATCDialog::FreqDialog() {
|
void FGATCDialog::FreqDialog() {
|
||||||
|
@ -316,38 +312,25 @@ void FGATCDialog::FreqDialog() {
|
||||||
// remove all dynamic airport/ATC buttons
|
// remove all dynamic airport/ATC buttons
|
||||||
button_group->removeChildren("button", false);
|
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"),
|
SGGeod geod(SGGeod::fromDegFt(fgGetDouble("/position/longitude-deg"),
|
||||||
fgGetDouble("/position/latitude-deg"), fgGetDouble("/position/altitude-ft")));
|
fgGetDouble("/position/latitude-deg"), fgGetDouble("/position/altitude-ft")));
|
||||||
SGVec3d aircraft = SGVec3d::fromGeod(geod);
|
|
||||||
|
|
||||||
// search stations in range
|
|
||||||
int num_stat = current_commlist->FindByPos(geod, 50.0, &atc_stations);
|
|
||||||
if (num_stat != 0) {
|
|
||||||
map<atcdata, bool> uniq;
|
|
||||||
// fill map (sorts by distance and removes duplicates)
|
|
||||||
comm_list_iterator itr = atc_stations.begin();
|
|
||||||
for (; itr != atc_stations.end(); ++itr) {
|
|
||||||
double distance = distSqr(aircraft, itr->cart);
|
|
||||||
uniq[atcdata(itr->ident, itr->name, distance)] = true;
|
|
||||||
}
|
|
||||||
// create button per map entry (modified copy of <button-template>)
|
|
||||||
map<atcdata, bool>::iterator uit = uniq.begin();
|
|
||||||
for (int n = 0; uit != uniq.end() && n < 6; ++uit, ++n) { // max 6 buttons
|
|
||||||
SGPropertyNode *entry = button_group->getNode("button", n, true);
|
|
||||||
copyProperties(button_group->getNode("button-template", true), entry);
|
|
||||||
entry->removeChildren("enabled", true);
|
|
||||||
entry->setStringValue("legend", uit->first.id.c_str());
|
|
||||||
entry->setStringValue("binding[0]/value", uit->first.id.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
AirportsWithATC filt;
|
||||||
|
FGPositioned::List results = FGPositioned::findWithinRange(geod, 50.0, &filt);
|
||||||
|
FGPositioned::sortByRange(results, geod);
|
||||||
|
for (unsigned int r=0; (r<results.size()) && (r < 6); ++r) {
|
||||||
|
|
||||||
|
SGPropertyNode *entry = button_group->getNode("button", r, true);
|
||||||
|
copyProperties(button_group->getNode("button-template", true), entry);
|
||||||
|
entry->removeChildren("enabled", true);
|
||||||
|
entry->setStringValue("legend", results[r]->ident());
|
||||||
|
entry->setStringValue("binding[0]/value", results[r]->ident());
|
||||||
|
}
|
||||||
|
|
||||||
// (un)hide message saying no things in range
|
// (un)hide message saying no things in range
|
||||||
SGPropertyNode_ptr range_error = getNamedNode(dlg, "no-atc-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);
|
_gui->showDialog(dialog_name);
|
||||||
}
|
}
|
||||||
|
@ -378,43 +361,33 @@ void FGATCDialog::FreqDisplay(string& ident) {
|
||||||
label = ident + " Frequencies";
|
label = ident + " Frequencies";
|
||||||
dlg->setStringValue("text/label", label.c_str());
|
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()) {
|
||||||
comm_list_type stations;
|
label = "No frequencies found for airport " + ident;
|
||||||
int found = current_commlist->FindByPos(a->geod(), 20.0, &stations);
|
|
||||||
if(found) {
|
|
||||||
comm_list_iterator itr = stations.begin();
|
|
||||||
for (n = 0; itr != stations.end(); ++itr) {
|
|
||||||
if(itr->ident != ident)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(itr->type == INVALID)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// add frequency line (modified copy of <group-template>)
|
|
||||||
SGPropertyNode *entry = freq_group->getNode("group", n, true);
|
|
||||||
copyProperties(freq_group->getNode("group-template", true), entry);
|
|
||||||
entry->removeChildren("enabled", true);
|
|
||||||
|
|
||||||
ostringstream ostr;
|
|
||||||
ostr << itr->type;
|
|
||||||
entry->setStringValue("text[0]/label", ostr.str());
|
|
||||||
|
|
||||||
char buf[8];
|
|
||||||
snprintf(buf, 8, "%.2f", (itr->freq / 100.0)); // Convert from KHz to MHz
|
|
||||||
if(buf[5] == '3') buf[5] = '2';
|
|
||||||
if(buf[5] == '8') buf[5] = '7';
|
|
||||||
buf[7] = '\0';
|
|
||||||
|
|
||||||
entry->setStringValue("text[1]/label", buf);
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(n == 0) {
|
|
||||||
label = "No frequencies found for airport " + ident;
|
|
||||||
mkDialog(label.c_str());
|
mkDialog(label.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
for (unsigned int c=0; c < comms.size(); ++c) {
|
||||||
|
flightgear::CommStation* comm = comms[c];
|
||||||
|
|
||||||
|
// add frequency line (modified copy of <group-template>)
|
||||||
|
SGPropertyNode *entry = freq_group->getNode("group", n, true);
|
||||||
|
copyProperties(freq_group->getNode("group-template", true), entry);
|
||||||
|
entry->removeChildren("enabled", true);
|
||||||
|
|
||||||
|
entry->setStringValue("text[0]/label", comm->ident());
|
||||||
|
|
||||||
|
char buf[8];
|
||||||
|
snprintf(buf, 8, "%.2f", comm->freqMHz());
|
||||||
|
if(buf[5] == '3') buf[5] = '2';
|
||||||
|
if(buf[5] == '8') buf[5] = '7';
|
||||||
|
buf[7] = '\0';
|
||||||
|
|
||||||
|
entry->setStringValue("text[1]/label", buf);
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
|
||||||
_gui->showDialog(dialog_name);
|
_gui->showDialog(dialog_name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,29 +24,18 @@
|
||||||
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <simgear/structure/exception.hxx>
|
||||||
|
|
||||||
#include <Airports/simple.hxx>
|
#include <Airports/simple.hxx>
|
||||||
|
#include <ATC/CommStation.hxx>
|
||||||
|
#include <Main/fg_props.hxx>
|
||||||
|
|
||||||
#include "ATCmgr.hxx"
|
#include "ATCmgr.hxx"
|
||||||
#include "commlist.hxx"
|
|
||||||
#include "ATCDialog.hxx"
|
#include "ATCDialog.hxx"
|
||||||
#include "ATCutils.hxx"
|
#include "ATCutils.hxx"
|
||||||
|
#include "atis.hxx"
|
||||||
|
|
||||||
|
using flightgear::CommStation;
|
||||||
/*
|
|
||||||
// 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();
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
FGATCMgr::FGATCMgr() :
|
FGATCMgr::FGATCMgr() :
|
||||||
initDone(false),
|
initDone(false),
|
||||||
|
@ -148,44 +137,6 @@ void FGATCMgr::update(double dt) {
|
||||||
//cout << "Leaving update..." << endl;
|
//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;
|
typedef map<string,int> MSI;
|
||||||
|
|
||||||
void FGATCMgr::ZapOtherService(const string ncunit, const string svc_name){
|
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];
|
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
|
// Return a pointer to an appropriate voice for a given type of ATC
|
||||||
// creating the voice if necessary - ie. make sure exactly one copy
|
// creating the voice if necessary - ie. make sure exactly one copy
|
||||||
// of every voice in use exists in memory.
|
// of every voice in use exists in memory.
|
||||||
|
@ -303,49 +244,44 @@ void FGATCMgr::FreqSearch(const string navcomm, const int unit) {
|
||||||
if (!comm_node) return; // no such radio unit
|
if (!comm_node) return; // no such radio unit
|
||||||
|
|
||||||
ATCData data;
|
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(),
|
_aircraftPos = SGGeod::fromDegFt(lon_node->getDoubleValue(),
|
||||||
lat_node->getDoubleValue(), elev_node->getDoubleValue());
|
lat_node->getDoubleValue(), elev_node->getDoubleValue());
|
||||||
|
|
||||||
// Query the data store and get the closest match if any
|
CommStation* sta = CommStation::findByFreq(freqKhz, _aircraftPos);
|
||||||
//cout << "Will FindByFreq: " << lat << " " << lon << " " << elev
|
if (!sta) {
|
||||||
// << " freq: " << freq << endl;
|
ZapOtherService(ncunit, "x x x");
|
||||||
if(current_commlist->FindByFreq(_aircraftPos, freq, &data)) {
|
return;
|
||||||
//cout << "FoundByFreq: " << freq
|
}
|
||||||
// << " ident: " << data.ident
|
|
||||||
// << " type: " << data.type << " ***" << endl;
|
// Get rid of any *other* service that was on this radio unit:
|
||||||
// We are in range of something.
|
FGPositioned::Type ty = sta->type();
|
||||||
|
string svc_name = sta->ident() + FGPositioned::nameForType(ty);
|
||||||
|
ZapOtherService(ncunit, svc_name);
|
||||||
|
// See if the service already exists, possibly connected to
|
||||||
|
// some other radio unit:
|
||||||
|
if (atc_list->count(svc_name)) {
|
||||||
|
// make sure the service knows it's tuned on this radio:
|
||||||
|
FGATC* svc = (*atc_list)[svc_name];
|
||||||
|
svc->active_on[ncunit] = 1;
|
||||||
|
svc->SetDisplay();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This was a switch-case statement but the compiler didn't like
|
||||||
// Get rid of any *other* service that was on this radio unit:
|
// the new variable creation with it.
|
||||||
string svc_name = data.ident+decimalNumeral(data.type);
|
if(ty == FGPositioned::FREQ_ATIS || ty == FGPositioned::FREQ_AWOS) {
|
||||||
ZapOtherService(ncunit, svc_name);
|
(*atc_list)[svc_name] = new FGATIS;
|
||||||
// See if the service already exists, possibly connected to
|
FGATC* svc = (*atc_list)[svc_name];
|
||||||
// some other radio unit:
|
if(svc != NULL) {
|
||||||
if (atc_list->count(svc_name)) {
|
svc->SetStation(sta);
|
||||||
// make sure the service knows it's tuned on this radio:
|
|
||||||
FGATC* svc = (*atc_list)[svc_name];
|
|
||||||
svc->active_on[ncunit] = 1;
|
svc->active_on[ncunit] = 1;
|
||||||
svc->SetDisplay();
|
svc->SetDisplay();
|
||||||
return;
|
svc->Init();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CommRegisterAirport(data.ident, unit, data.type);
|
|
||||||
|
|
||||||
// This was a switch-case statement but the compiler didn't like
|
|
||||||
// the new variable creation with it.
|
|
||||||
if(data.type == ATIS || data.type == AWOS) {
|
|
||||||
(*atc_list)[svc_name] = new FGATIS;
|
|
||||||
FGATC* svc = (*atc_list)[svc_name];
|
|
||||||
if(svc != NULL) {
|
|
||||||
svc->SetData(&data);
|
|
||||||
svc->active_on[ncunit] = 1;
|
|
||||||
svc->SetDisplay();
|
|
||||||
svc->Init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No services in range. Zap any service on this unit.
|
|
||||||
ZapOtherService(ncunit, "x x x");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,31 +24,12 @@
|
||||||
|
|
||||||
#include <simgear/structure/subsystem_mgr.hxx>
|
#include <simgear/structure/subsystem_mgr.hxx>
|
||||||
|
|
||||||
#include <Main/fg_props.hxx>
|
|
||||||
#include <GUI/gui.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "ATC.hxx"
|
#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
|
class FGATCMgr : public SGSubsystem
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -56,16 +37,8 @@ private:
|
||||||
|
|
||||||
bool initDone; // Hack - guard against update getting called before init
|
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
|
// 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::iterator atc_list_iterator;
|
||||||
typedef atc_list_type::const_iterator atc_list_const_iterator;
|
typedef atc_list_type::const_iterator atc_list_const_iterator;
|
||||||
|
|
||||||
|
@ -107,9 +80,7 @@ public:
|
||||||
|
|
||||||
void update(double dt);
|
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
|
// Return a pointer to an appropriate voice for a given type of ATC
|
||||||
// creating the voice if necessary - ie. make sure exactly one copy
|
// creating the voice if necessary - ie. make sure exactly one copy
|
||||||
// of every voice in use exists in memory.
|
// of every voice in use exists in memory.
|
||||||
|
@ -124,26 +95,20 @@ public:
|
||||||
atc_type GetComm2ATCType() { return(INVALID); }
|
atc_type GetComm2ATCType() { return(INVALID); }
|
||||||
FGATC* GetComm2ATCPointer() { return(0/* kludge */); }
|
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:
|
private:
|
||||||
|
|
||||||
// Remove a class from the atc_list and delete it from memory
|
// Remove a class from the atc_list and delete it from memory
|
||||||
// *if* no other comm channel or AI plane is using it.
|
// *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 a pointer to a class in the list given ICAO code and type
|
||||||
// Return NULL if the given service is not in the list
|
// Return NULL if the given service is not in the list
|
||||||
// - *** THE CALLING FUNCTION MUST CHECK FOR THIS ***
|
// - *** 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.
|
// 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
|
#endif // _FG_ATCMGR_HXX
|
||||||
|
|
|
@ -3,7 +3,6 @@ include(FlightGearComponent)
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
ATC.cxx
|
ATC.cxx
|
||||||
atis.cxx
|
atis.cxx
|
||||||
commlist.cxx
|
|
||||||
ATCDialog.cxx
|
ATCDialog.cxx
|
||||||
ATCVoice.cxx
|
ATCVoice.cxx
|
||||||
ATCmgr.cxx
|
ATCmgr.cxx
|
||||||
|
|
|
@ -3,7 +3,6 @@ noinst_LIBRARIES = libATCDCL.a
|
||||||
libATCDCL_a_SOURCES = \
|
libATCDCL_a_SOURCES = \
|
||||||
ATC.hxx ATC.cxx \
|
ATC.hxx ATC.cxx \
|
||||||
atis.hxx atis.cxx \
|
atis.hxx atis.cxx \
|
||||||
commlist.hxx commlist.cxx \
|
|
||||||
ATCDialog.hxx ATCDialog.cxx \
|
ATCDialog.hxx ATCDialog.cxx \
|
||||||
ATCVoice.hxx ATCVoice.cxx \
|
ATCVoice.hxx ATCVoice.cxx \
|
||||||
ATCmgr.hxx ATCmgr.cxx \
|
ATCmgr.hxx ATCmgr.cxx \
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
#include "atis_lexicon.hxx"
|
#include "atis_lexicon.hxx"
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/math/sg_random.h>
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
|
||||||
#include <stdlib.h> // atoi()
|
#include <stdlib.h> // atoi()
|
||||||
#include <stdio.h> // sprintf
|
#include <stdio.h> // sprintf
|
||||||
|
@ -44,9 +46,6 @@
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
#include <boost/algorithm/string/case_conv.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
|
||||||
|
|
||||||
#include <Environment/environment_mgr.hxx>
|
#include <Environment/environment_mgr.hxx>
|
||||||
#include <Environment/environment.hxx>
|
#include <Environment/environment.hxx>
|
||||||
#include <Environment/atmosphere.hxx>
|
#include <Environment/atmosphere.hxx>
|
||||||
|
@ -56,7 +55,6 @@
|
||||||
#include <Airports/runways.hxx>
|
#include <Airports/runways.hxx>
|
||||||
|
|
||||||
|
|
||||||
#include "commlist.hxx"
|
|
||||||
#include "ATCutils.hxx"
|
#include "ATCutils.hxx"
|
||||||
#include "ATCmgr.hxx"
|
#include "ATCmgr.hxx"
|
||||||
|
|
||||||
|
@ -230,6 +228,47 @@ int Apt_US_CA(const string id) {
|
||||||
return 0;
|
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.
|
// Generate the actual broadcast ATIS transmission.
|
||||||
// Regen means regenerate the /current/ transmission.
|
// Regen means regenerate the /current/ transmission.
|
||||||
// Special means generate a new transmission, with a new sequence.
|
// 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 ?
|
int interval = _type == ATIS ?
|
||||||
ATIS_interval // ATIS updated hourly
|
ATIS_interval // ATIS updated hourly
|
||||||
: 2*minute; // AWOS updated more frequently
|
: 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) {
|
if (!regen && sequence > LTRS) {
|
||||||
//xx if (msg_OK) cout << "ATIS: no change: " << sequence << endl;
|
//xx if (msg_OK) cout << "ATIS: no change: " << sequence << endl;
|
||||||
//xx msg_time = cur_time;
|
//xx msg_time = cur_time;
|
||||||
|
|
|
@ -95,6 +95,9 @@ class FGATIS : public FGATC {
|
||||||
void TreeOut(int msgOK);
|
void TreeOut(int msgOK);
|
||||||
|
|
||||||
friend std::istream& operator>> ( std::istream&, FGATIS& );
|
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;
|
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 "simple.hxx"
|
||||||
#include "runways.hxx"
|
#include "runways.hxx"
|
||||||
#include "pavement.hxx"
|
#include "pavement.hxx"
|
||||||
#include <ATCDCL/commlist.hxx>
|
|
||||||
|
#include <ATC/CommStation.hxx>
|
||||||
|
|
||||||
#include <iostream>
|
#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 );
|
sg_gzifstream in( aptdb_file );
|
||||||
|
|
||||||
|
@ -157,12 +158,8 @@ public:
|
||||||
// custom startup locations (ignore)
|
// custom startup locations (ignore)
|
||||||
} else if ( line_id == 0 ) {
|
} else if ( line_id == 0 ) {
|
||||||
// ??
|
// ??
|
||||||
} else if ( line_id == 50 ) {
|
} else if ( line_id >= 50 && line_id <= 56) {
|
||||||
|
parseCommLine(line_id, simgear::strutils::split(line));
|
||||||
parseATISLine(comm_list, simgear::strutils::split(line));
|
|
||||||
|
|
||||||
} else if ( line_id >= 51 && line_id <= 56 ) {
|
|
||||||
// other frequency entries (ignore)
|
|
||||||
} else if ( line_id == 110 ) {
|
} else if ( line_id == 110 ) {
|
||||||
pavement = true;
|
pavement = true;
|
||||||
parsePavementLine850(simgear::strutils::split(line, 0, 4));
|
parsePavementLine850(simgear::strutils::split(line, 0, 4));
|
||||||
|
@ -206,6 +203,7 @@ private:
|
||||||
vector<FGRunwayPtr> runways;
|
vector<FGRunwayPtr> runways;
|
||||||
vector<FGTaxiwayPtr> taxiways;
|
vector<FGTaxiwayPtr> taxiways;
|
||||||
vector<FGPavementPtr> pavements;
|
vector<FGPavementPtr> pavements;
|
||||||
|
vector<flightgear::CommStation*> commStations;
|
||||||
|
|
||||||
void addAirport()
|
void addAirport()
|
||||||
{
|
{
|
||||||
|
@ -235,6 +233,7 @@ private:
|
||||||
FGAirport* apt = new FGAirport(last_apt_id, pos, tower, last_apt_name, false,
|
FGAirport* apt = new FGAirport(last_apt_id, pos, tower, last_apt_name, false,
|
||||||
fptypeFromRobinType(atoi(last_apt_type.c_str())));
|
fptypeFromRobinType(atoi(last_apt_type.c_str())));
|
||||||
apt->setRunwaysAndTaxiways(runways, taxiways, pavements);
|
apt->setRunwaysAndTaxiways(runways, taxiways, pavements);
|
||||||
|
apt->setCommStations(commStations);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseAirportLine(const vector<string>& token)
|
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 ) {
|
if ( rwy_count <= 0 ) {
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
SG_LOG( SG_GENERAL, SG_ALERT, "No runways; skipping comm for " + last_apt_id);
|
||||||
"No runways; skipping AWOS for " + last_apt_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This assumes/requires that any code-50 line (ATIS or AWOS)
|
SGGeod pos = SGGeod::fromDegFt(rwy_lon_accum / (double)rwy_count,
|
||||||
// applies to the preceding code-1 line (airport ID and name)
|
rwy_lat_accum / (double)rwy_count, last_apt_elev);
|
||||||
// and that a full set of code-10 lines (runway descriptors)
|
|
||||||
// has come between the code-1 and code-50 lines.
|
|
||||||
// typical code-50 lines:
|
|
||||||
// 50 11770 ATIS
|
|
||||||
// 50 11770 AWOS 3
|
|
||||||
// This code parallels code found in "operator>>" in ATC.hxx;
|
|
||||||
// FIXME: unify the code.
|
|
||||||
ATCData a;
|
|
||||||
a.geod = SGGeod::fromDegFt(rwy_lon_accum / (double)rwy_count,
|
|
||||||
rwy_lat_accum / (double)rwy_count, last_apt_elev);
|
|
||||||
a.range = 50; // give all ATISs small range
|
|
||||||
a.ident = last_apt_id;
|
|
||||||
a.name = last_apt_name;
|
|
||||||
// short int representing tens of kHz:
|
// short int representing tens of kHz:
|
||||||
a.freq = atoi(token[1].c_str());
|
int freqKhz = atoi(token[1].c_str());
|
||||||
if (token[2] == "ATIS") a.type = ATIS;
|
int rangeNm = 50;
|
||||||
else a.type = AWOS; // ASOS same as AWOS
|
FGPositioned::Type ty;
|
||||||
|
switch (lineId) {
|
||||||
|
case 50:
|
||||||
|
ty = FGPositioned::FREQ_AWOS;
|
||||||
|
if (token[2] == "ATIS") {
|
||||||
|
ty = FGPositioned::FREQ_ATIS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 51: ty = FGPositioned::FREQ_UNICOM; break;
|
||||||
|
case 52: ty = FGPositioned::FREQ_CLEARANCE; break;
|
||||||
|
case 53: ty = FGPositioned::FREQ_GROUND; break;
|
||||||
|
case 54: ty = FGPositioned::FREQ_TOWER; break;
|
||||||
|
case 55:
|
||||||
|
case 56: ty = FGPositioned::FREQ_APP_DEP; break;
|
||||||
|
default:
|
||||||
|
throw sg_range_exception("unupported apt.dat comm station type");
|
||||||
|
}
|
||||||
|
|
||||||
// generate cartesian coordinates
|
commStations.push_back(new flightgear::CommStation(token[2], ty, pos, rangeNm, freqKhz));
|
||||||
a.cart = SGVec3d::fromGeod(a.geod);
|
|
||||||
comm_list->commlist_freq[a.freq].push_back(a);
|
|
||||||
|
|
||||||
SGBucket bucket(a.geod);
|
|
||||||
int bucknum = bucket.gen_index();
|
|
||||||
comm_list->commlist_bck[bucknum].push_back(a);
|
|
||||||
#if 0
|
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
|
||||||
"Loaded ATIS/AWOS for airport: " << a.ident
|
|
||||||
<< " lat: " << a.geod.getLatitudeDeg()
|
|
||||||
<< " lon: " << a.geod.getLongitudeDeg()
|
|
||||||
<< " freq: " << a.freq
|
|
||||||
<< " type: " << a.type );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -516,12 +505,11 @@ private:
|
||||||
// Load the airport data base from the specified aptdb file. The
|
// Load the airport data base from the specified aptdb file. The
|
||||||
// metar file is used to mark the airports as having metar available
|
// metar file is used to mark the airports as having metar available
|
||||||
// or not.
|
// or not.
|
||||||
bool fgAirportDBLoad( const string &aptdb_file,
|
bool fgAirportDBLoad( const string &aptdb_file, const std::string &metar_file )
|
||||||
FGCommList *comm_list, const std::string &metar_file )
|
|
||||||
{
|
{
|
||||||
|
|
||||||
APTLoader ld;
|
APTLoader ld;
|
||||||
ld.parseAPT(aptdb_file, comm_list);
|
ld.parseAPT(aptdb_file);
|
||||||
//
|
//
|
||||||
// Load the metar.dat file and update apt db with stations that
|
// Load the metar.dat file and update apt db with stations that
|
||||||
// have metar data.
|
// have metar data.
|
||||||
|
|
|
@ -29,14 +29,11 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
// forward decls
|
|
||||||
class FGCommList;
|
|
||||||
|
|
||||||
// Load the airport data base from the specified aptdb file. The
|
// Load the airport data base from the specified aptdb file. The
|
||||||
// metar file is used to mark the airports as having metar available
|
// metar file is used to mark the airports as having metar available
|
||||||
// or not.
|
// or not.
|
||||||
|
|
||||||
bool fgAirportDBLoad( const std::string &aptdb_file,
|
bool fgAirportDBLoad( const std::string &aptdb_file,
|
||||||
FGCommList *comm_list, const std::string &metar_file );
|
const std::string &metar_file );
|
||||||
|
|
||||||
#endif // _FG_APT_LOADER_HXX
|
#endif // _FG_APT_LOADER_HXX
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
|
|
||||||
#include "runwaybase.hxx"
|
#include "runwaybase.hxx"
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,7 @@ public:
|
||||||
{ return _surface_code; }
|
{ return _surface_code; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
double _heading;
|
double _heading;
|
||||||
double _length;
|
double _length;
|
||||||
double _width;
|
double _width;
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
|
|
||||||
#include <Airports/simple.hxx>
|
#include <Airports/simple.hxx>
|
||||||
#include <Navaids/procedure.hxx>
|
#include <Navaids/procedure.hxx>
|
||||||
|
#include <Navaids/navrecord.hxx>
|
||||||
|
#include <Navaids/PositionedBinding.hxx>
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
|
@ -197,4 +199,9 @@ std::vector<flightgear::STAR*> FGRunway::getSTARs()
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flightgear::PositionedBinding*
|
||||||
|
FGRunway::createBinding(SGPropertyNode* nd) const
|
||||||
|
{
|
||||||
|
return new flightgear::RunwayBinding(this, nd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,8 @@ public:
|
||||||
{ return _reciprocal; }
|
{ return _reciprocal; }
|
||||||
void setReciprocalRunway(FGRunway* other);
|
void setReciprocalRunway(FGRunway* other);
|
||||||
|
|
||||||
|
virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to process property data loaded from an ICAO.threshold.xml file
|
* Helper to process property data loaded from an ICAO.threshold.xml file
|
||||||
*/
|
*/
|
||||||
|
@ -130,6 +132,7 @@ public:
|
||||||
* Get STARs associared with this runway
|
* Get STARs associared with this runway
|
||||||
*/
|
*/
|
||||||
std::vector<flightgear::STAR*> getSTARs();
|
std::vector<flightgear::STAR*> getSTARs();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _FG_RUNWAYS_HXX
|
#endif // _FG_RUNWAYS_HXX
|
||||||
|
|
|
@ -47,6 +47,8 @@
|
||||||
#include <Airports/xmlloader.hxx>
|
#include <Airports/xmlloader.hxx>
|
||||||
#include <Navaids/procedure.hxx>
|
#include <Navaids/procedure.hxx>
|
||||||
#include <Navaids/waypoint.hxx>
|
#include <Navaids/waypoint.hxx>
|
||||||
|
#include <Navaids/PositionedBinding.hxx>
|
||||||
|
#include <ATC/CommStation.hxx>
|
||||||
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using namespace flightgear;
|
using namespace flightgear;
|
||||||
|
@ -662,6 +664,61 @@ Approach* FGAirport::getApproachByIndex(unsigned int aIndex) const
|
||||||
return mApproaches[aIndex];
|
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
|
// get airport elevation
|
||||||
double fgGetAirportElev( const string& id )
|
double fgGetAirportElev( const string& id )
|
||||||
{
|
{
|
||||||
|
|
|
@ -50,10 +50,12 @@ namespace flightgear {
|
||||||
class STAR;
|
class STAR;
|
||||||
class Approach;
|
class Approach;
|
||||||
class Waypt;
|
class Waypt;
|
||||||
|
class CommStation;
|
||||||
|
|
||||||
typedef SGSharedPtr<Waypt> WayptRef;
|
typedef SGSharedPtr<Waypt> WayptRef;
|
||||||
typedef std::vector<WayptRef> WayptVec;
|
typedef std::vector<WayptRef> WayptVec;
|
||||||
|
|
||||||
|
typedef std::vector<CommStation*> CommStationList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -185,6 +187,8 @@ public:
|
||||||
unsigned int numApproaches() const;
|
unsigned int numApproaches() const;
|
||||||
flightgear::Approach* getApproachByIndex(unsigned int aIndex) const;
|
flightgear::Approach* getApproachByIndex(unsigned int aIndex) const;
|
||||||
|
|
||||||
|
static void installPropertyListener();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Syntactic wrapper around FGPositioned::findClosest - find the closest
|
* Syntactic wrapper around FGPositioned::findClosest - find the closest
|
||||||
* match for filter, and return it cast to FGAirport. The default filter
|
* 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);
|
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:
|
private:
|
||||||
typedef std::vector<FGRunwayPtr>::const_iterator Runway_iterator;
|
typedef std::vector<FGRunwayPtr>::const_iterator Runway_iterator;
|
||||||
/**
|
/**
|
||||||
|
@ -275,6 +287,8 @@ private:
|
||||||
std::vector<flightgear::SID*> mSIDs;
|
std::vector<flightgear::SID*> mSIDs;
|
||||||
std::vector<flightgear::STAR*> mSTARs;
|
std::vector<flightgear::STAR*> mSTARs;
|
||||||
std::vector<flightgear::Approach*> mApproaches;
|
std::vector<flightgear::Approach*> mApproaches;
|
||||||
|
|
||||||
|
flightgear::CommStationList mCommStations;
|
||||||
};
|
};
|
||||||
|
|
||||||
// find basic airport location info from airport database
|
// find basic airport location info from airport database
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
|
|
||||||
#include <simgear/misc/strutils.hxx>
|
#include <simgear/misc/strutils.hxx>
|
||||||
#include <simgear/structure/exception.hxx>
|
#include <simgear/structure/exception.hxx>
|
||||||
|
#include <simgear/structure/commands.hxx>
|
||||||
#include <simgear/misc/sgstream.hxx>
|
#include <simgear/misc/sgstream.hxx>
|
||||||
|
|
||||||
#include <simgear/props/props_io.hxx>
|
#include <simgear/props/props_io.hxx>
|
||||||
|
@ -109,6 +110,151 @@ PropertyWatcher* createWatcher(T* obj, void (T::*m)())
|
||||||
return new MethodPropertyWatcher<T>(obj, 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() :
|
FGRouteMgr::FGRouteMgr() :
|
||||||
_currentIndex(0),
|
_currentIndex(0),
|
||||||
input(fgGetNode( RM "input", true )),
|
input(fgGetNode( RM "input", true )),
|
||||||
|
@ -117,6 +263,14 @@ FGRouteMgr::FGRouteMgr() :
|
||||||
listener = new InputListener(this);
|
listener = new InputListener(this);
|
||||||
input->setStringValue("");
|
input->setStringValue("");
|
||||||
input->addChangeListener(listener);
|
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());
|
SGPath path(_pathNode->getStringValue());
|
||||||
if (path.exists()) {
|
if (path.exists()) {
|
||||||
SG_LOG(SG_AUTOPILOT, SG_INFO, "loading flight-plan from:" << path.str());
|
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
|
// 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"))
|
else if (!strcmp(s, "@ACTIVATE"))
|
||||||
mgr->activate();
|
mgr->activate();
|
||||||
else if (!strcmp(s, "@LOAD")) {
|
else if (!strcmp(s, "@LOAD")) {
|
||||||
mgr->loadRoute();
|
SGPath path(mgr->_pathNode->getStringValue());
|
||||||
|
mgr->loadRoute(path);
|
||||||
} else if (!strcmp(s, "@SAVE")) {
|
} else if (!strcmp(s, "@SAVE")) {
|
||||||
mgr->saveRoute();
|
SGPath path(mgr->_pathNode->getStringValue());
|
||||||
} else if (!strcmp(s, "@POP")) {
|
mgr->saveRoute(path);
|
||||||
SG_LOG(SG_AUTOPILOT, SG_WARN, "route-manager @POP command is deprecated");
|
|
||||||
} else if (!strcmp(s, "@NEXT")) {
|
} else if (!strcmp(s, "@NEXT")) {
|
||||||
mgr->jumpToIndex(mgr->_currentIndex + 1);
|
mgr->jumpToIndex(mgr->_currentIndex + 1);
|
||||||
} else if (!strcmp(s, "@PREVIOUS")) {
|
} else if (!strcmp(s, "@PREVIOUS")) {
|
||||||
|
@ -1119,9 +1273,8 @@ Waypt* FGRouteMgr::wayptAtIndex(int index) const
|
||||||
return _route[index];
|
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());
|
SG_LOG(SG_IO, SG_INFO, "Saving route to " << path.str());
|
||||||
try {
|
try {
|
||||||
SGPropertyNode_ptr d(new SGPropertyNode);
|
SGPropertyNode_ptr d(new SGPropertyNode);
|
||||||
|
@ -1148,18 +1301,19 @@ void FGRouteMgr::saveRoute()
|
||||||
wpt->saveAsNode(routeNode->getChild("wp", i, true));
|
wpt->saveAsNode(routeNode->getChild("wp", i, true));
|
||||||
} // of waypoint iteration
|
} // of waypoint iteration
|
||||||
writeProperties(path.str(), d, true /* write-all */);
|
writeProperties(path.str(), d, true /* write-all */);
|
||||||
|
return true;
|
||||||
} catch (sg_exception& e) {
|
} catch (sg_exception& e) {
|
||||||
SG_LOG(SG_IO, SG_WARN, "failed to save flight-plan:" << e.getMessage());
|
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
|
// deactivate route first
|
||||||
active->setBoolValue(false);
|
active->setBoolValue(false);
|
||||||
|
|
||||||
SGPropertyNode_ptr routeData(new SGPropertyNode);
|
SGPropertyNode_ptr routeData(new SGPropertyNode);
|
||||||
SGPath path(_pathNode->getStringValue());
|
|
||||||
|
|
||||||
SG_LOG(SG_IO, SG_INFO, "going to read flight-plan from:" << path.str());
|
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);
|
readProperties(path.str(), routeData);
|
||||||
} catch (sg_exception& ) {
|
} catch (sg_exception& ) {
|
||||||
// if XML parsing fails, the file might be simple textual list of waypoints
|
// if XML parsing fails, the file might be simple textual list of waypoints
|
||||||
loadPlainTextRoute(path);
|
return loadPlainTextRoute(path);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -1180,9 +1333,11 @@ void FGRouteMgr::loadRoute()
|
||||||
} else {
|
} else {
|
||||||
throw sg_io_exception("unsupported XML route version");
|
throw sg_io_exception("unsupported XML route version");
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
} catch (sg_exception& e) {
|
} catch (sg_exception& e) {
|
||||||
SG_LOG(SG_IO, SG_WARN, "failed to load flight-plan (from '" << e.getOrigin()
|
SG_LOG(SG_IO, SG_WARN, "failed to load flight-plan (from '" << e.getOrigin()
|
||||||
<< "'):" << e.getMessage());
|
<< "'):" << e.getMessage());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1299,11 +1454,11 @@ WayptRef FGRouteMgr::parseVersion1XMLWaypt(SGPropertyNode* aWP)
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGRouteMgr::loadPlainTextRoute(const SGPath& path)
|
bool FGRouteMgr::loadPlainTextRoute(const SGPath& path)
|
||||||
{
|
{
|
||||||
sg_gzifstream in(path.str().c_str());
|
sg_gzifstream in(path.str().c_str());
|
||||||
if (!in.is_open()) {
|
if (!in.is_open()) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -1330,8 +1485,10 @@ void FGRouteMgr::loadPlainTextRoute(const SGPath& path)
|
||||||
} // of line iteration
|
} // of line iteration
|
||||||
|
|
||||||
_route = wpts;
|
_route = wpts;
|
||||||
|
return true;
|
||||||
} catch (sg_exception& e) {
|
} catch (sg_exception& e) {
|
||||||
SG_LOG(SG_IO, SG_WARN, "failed to load route from:" << path.str() << ":" << e.getMessage());
|
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 jumpToIndex(int index);
|
||||||
|
|
||||||
void saveRoute();
|
bool saveRoute(const SGPath& p);
|
||||||
void loadRoute();
|
bool loadRoute(const SGPath& p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper command to setup current airport/runway if necessary
|
* Helper command to setup current airport/runway if necessary
|
||||||
*/
|
*/
|
||||||
void initAtPosition();
|
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:
|
private:
|
||||||
flightgear::WayptVec _route;
|
flightgear::WayptVec _route;
|
||||||
int _currentIndex;
|
int _currentIndex;
|
||||||
|
@ -188,17 +197,7 @@ private:
|
||||||
SGPropertyNode_ptr weightOnWheels;
|
SGPropertyNode_ptr weightOnWheels;
|
||||||
|
|
||||||
InputListener *listener;
|
InputListener *listener;
|
||||||
SGPropertyNode_ptr mirror;
|
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 departureChanged();
|
||||||
void buildDeparture(flightgear::WayptRef enroute, flightgear::WayptVec& wps);
|
void buildDeparture(flightgear::WayptRef enroute, flightgear::WayptVec& wps);
|
||||||
|
@ -229,7 +228,7 @@ private:
|
||||||
bool checkFinished();
|
bool checkFinished();
|
||||||
|
|
||||||
|
|
||||||
void loadPlainTextRoute(const SGPath& path);
|
bool loadPlainTextRoute(const SGPath& path);
|
||||||
|
|
||||||
void loadVersion1XMLRoute(SGPropertyNode_ptr routeData);
|
void loadVersion1XMLRoute(SGPropertyNode_ptr routeData);
|
||||||
void loadVersion2XMLRoute(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
|
y = w * (y - 0.5) + pos[1]; // E/W
|
||||||
z = h * z + pos[2]; // Up/Down. pos[2] is the cloudbase
|
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);
|
SGNewCloud cld = SGNewCloud(texture_root, cld_def);
|
||||||
|
|
||||||
//layer->addCloud(newpos, cld.genCloud());
|
//layer->addCloud(newpos, cld.genCloud());
|
||||||
|
|
|
@ -42,7 +42,6 @@ Somigliana::Somigliana()
|
||||||
Somigliana::~Somigliana()
|
Somigliana::~Somigliana()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
double Somigliana::getGravity( const SGGeod & position ) const
|
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";
|
static const char * LAYER = "layer";
|
||||||
SGPropertyNode_ptr cloudsNode = _rootNode->getNode("clouds", true );
|
SGPropertyNode_ptr cloudsNode = _rootNode->getNode("clouds", true );
|
||||||
|
|
|
@ -285,6 +285,7 @@ void AreaSampler::analyse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
double alt_low_min = 0.0;
|
double alt_low_min = 0.0;
|
||||||
double n_max = 0.0;
|
double n_max = 0.0;
|
||||||
sum = 0.0;
|
sum = 0.0;
|
||||||
|
@ -296,7 +297,7 @@ void AreaSampler::analyse()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
_altLayered = 0.5 * (_altMin + _altOffset);
|
_altLayered = 0.5 * (_altMin + _altOffset);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
|
@ -270,12 +270,10 @@ float Turbulence::iturb(unsigned int x, unsigned int y)
|
||||||
xfrac = xfrac*xfrac*(3 - 2*xfrac); // ... as cubics
|
xfrac = xfrac*xfrac*(3 - 2*xfrac); // ... as cubics
|
||||||
yfrac = yfrac*yfrac*(3 - 2*yfrac);
|
yfrac = yfrac*yfrac*(3 - 2*yfrac);
|
||||||
|
|
||||||
#define WRAP(a) (a) >= wrapmax ? 0 : (a)
|
float p00 = lattice(xl, yl); // lattice values
|
||||||
float p00 = lattice(WRAP(xl), WRAP(yl)); // lattice values
|
float p01 = lattice(xl, yl+1);
|
||||||
float p01 = lattice(WRAP(xl), WRAP(yl+1));
|
float p10 = lattice(xl+1, yl);
|
||||||
float p10 = lattice(WRAP(xl+1), WRAP(yl));
|
float p11 = lattice(xl+1, yl+1);
|
||||||
float p11 = lattice(WRAP(xl+1), WRAP(yl+1));
|
|
||||||
#undef WRAP
|
|
||||||
|
|
||||||
float p0 = p00 * (1-yfrac) + p01 * yfrac;
|
float p0 = p00 * (1-yfrac) + p01 * yfrac;
|
||||||
float p1 = p10 * (1-yfrac) + p11 * yfrac;
|
float p1 = p10 * (1-yfrac) + p11 * yfrac;
|
||||||
|
|
|
@ -27,58 +27,14 @@
|
||||||
|
|
||||||
#include "kln89_page_apt.hxx"
|
#include "kln89_page_apt.hxx"
|
||||||
|
|
||||||
|
#include <simgear/structure/exception.hxx>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include <ATCDCL/commlist.hxx>
|
#include <ATC/CommStation.hxx>
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Airports/runways.hxx>
|
#include <Airports/runways.hxx>
|
||||||
#include <Airports/simple.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)
|
KLN89AptPage::KLN89AptPage(KLN89* parent)
|
||||||
: KLN89Page(parent) {
|
: KLN89Page(parent) {
|
||||||
_nSubPages = 8;
|
_nSubPages = 8;
|
||||||
|
@ -230,7 +186,8 @@ void KLN89AptPage::Update(double dt) {
|
||||||
string s = _aptRwys[i]->ident();
|
string s = _aptRwys[i]->ident();
|
||||||
_kln89->DrawText(s, 2, 9, 3);
|
_kln89->DrawText(s, 2, 9, 3);
|
||||||
_kln89->DrawText("/", 2, 12, 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
|
// Length
|
||||||
s = GPSitoa(int(float(_aptRwys[i]->lengthFt()) * (_kln89->_altUnits == GPS_ALT_UNITS_FT ? 1.0 : SG_FEET_TO_METER) + 0.5));
|
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);
|
_kln89->DrawText(s, 2, 5 - s.size(), 2);
|
||||||
|
@ -278,7 +235,8 @@ void KLN89AptPage::Update(double dt) {
|
||||||
string s = _aptRwys[i]->ident();
|
string s = _aptRwys[i]->ident();
|
||||||
_kln89->DrawText(s, 2, 9, 1);
|
_kln89->DrawText(s, 2, 9, 1);
|
||||||
_kln89->DrawText("/", 2, 12, 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
|
// Length
|
||||||
s = GPSitoa(int(float(_aptRwys[i]->lengthFt()) * (_kln89->_altUnits == GPS_ALT_UNITS_FT ? 1.0 : SG_FEET_TO_METER) + 0.5));
|
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);
|
_kln89->DrawText(s, 2, 5 - s.size(), 0);
|
||||||
|
@ -499,38 +457,35 @@ void KLN89AptPage::SetId(const string& s) {
|
||||||
// Update the cached airport details
|
// Update the cached airport details
|
||||||
void KLN89AptPage::UpdateAirport(const string& id) {
|
void KLN89AptPage::UpdateAirport(const string& id) {
|
||||||
// Frequencies
|
// Frequencies
|
||||||
_aptFreqs.clear();
|
_aptFreqs.clear();
|
||||||
ATCData ad;
|
|
||||||
AptFreq aq;
|
const FGAirport* apt = fgFindAirportID(id);
|
||||||
//cout << "UpdateAirport called, id = " << id << '\n';
|
if (!apt) {
|
||||||
// TODO - the logic below only returns one service per type per airport - they can be on more than one freq though.
|
throw sg_exception("UpdateAirport: unknown airport id " + id);
|
||||||
if(current_commlist->FindByCode(id, ad, ATIS)) {
|
}
|
||||||
//cout << "Found ATIS\n";
|
|
||||||
aq.service = "ATIS*";
|
for (unsigned int c=0; c<apt->commStations().size(); ++c) {
|
||||||
aq.freq = ad.freq;
|
flightgear::CommStation* comm = apt->commStations()[c];
|
||||||
_aptFreqs.push_back(aq);
|
AptFreq aq;
|
||||||
}
|
aq.freq = comm->freqKHz();
|
||||||
if(current_commlist->FindByCode(id, ad, GROUND)) {
|
switch (comm->type()) {
|
||||||
aq.service = "GRND*";
|
case FGPositioned::FREQ_ATIS:
|
||||||
aq.freq = ad.freq;
|
aq.service = "ATIS*"; break;
|
||||||
_aptFreqs.push_back(aq);
|
case FGPositioned::FREQ_GROUND:
|
||||||
}
|
aq.service = "GRND*"; break;
|
||||||
if(current_commlist->FindByCode(id, ad, TOWER)) {
|
case FGPositioned::FREQ_TOWER:
|
||||||
aq.service = "TWR *";
|
aq.service = "TWR *"; break;
|
||||||
aq.freq = ad.freq;
|
case FGPositioned::FREQ_APP_DEP:
|
||||||
_aptFreqs.push_back(aq);
|
aq.service = "APR *"; break;
|
||||||
}
|
default:
|
||||||
if(current_commlist->FindByCode(id, ad, APPROACH)) {
|
continue;
|
||||||
aq.service = "APR";
|
}
|
||||||
aq.freq = ad.freq;
|
}
|
||||||
_aptFreqs.push_back(aq);
|
|
||||||
}
|
|
||||||
_nFreqPages = (unsigned int)ceil((float(_aptFreqs.size())) / 3.0f);
|
_nFreqPages = (unsigned int)ceil((float(_aptFreqs.size())) / 3.0f);
|
||||||
|
|
||||||
// Runways
|
// Runways
|
||||||
_aptRwys.clear();
|
_aptRwys.clear();
|
||||||
const FGAirport* apt = fgFindAirportID(id);
|
|
||||||
assert(apt);
|
|
||||||
|
|
||||||
// build local array, longest runway first
|
// build local array, longest runway first
|
||||||
for (unsigned int r=0; r<apt->numRunways(); ++r) {
|
for (unsigned int r=0; r<apt->numRunways(); ++r) {
|
||||||
|
|
|
@ -75,8 +75,6 @@
|
||||||
#include <AIModel/AIManager.hxx>
|
#include <AIModel/AIManager.hxx>
|
||||||
|
|
||||||
#include <ATCDCL/ATCmgr.hxx>
|
#include <ATCDCL/ATCmgr.hxx>
|
||||||
#include <ATCDCL/commlist.hxx>
|
|
||||||
#include <ATC/atis_mgr.hxx>
|
|
||||||
#include <ATC/atc_mgr.hxx>
|
#include <ATC/atc_mgr.hxx>
|
||||||
|
|
||||||
#include <Autopilot/route_mgr.hxx>
|
#include <Autopilot/route_mgr.hxx>
|
||||||
|
@ -1085,15 +1083,10 @@ fgInitNav ()
|
||||||
SGPath p_metar( globals->get_fg_root() );
|
SGPath p_metar( globals->get_fg_root() );
|
||||||
p_metar.append( "Airports/metar.dat" );
|
p_metar.append( "Airports/metar.dat" );
|
||||||
|
|
||||||
// Initialise the frequency search map BEFORE reading
|
fgAirportDBLoad( aptdb.str(), p_metar.str() );
|
||||||
// the airport database:
|
FGAirport::installPropertyListener();
|
||||||
|
FGPositioned::installCommands();
|
||||||
|
|
||||||
|
|
||||||
current_commlist = new FGCommList;
|
|
||||||
current_commlist->init( globals->get_fg_root() );
|
|
||||||
fgAirportDBLoad( aptdb.str(), current_commlist, p_metar.str() );
|
|
||||||
|
|
||||||
FGNavList *navlist = new FGNavList;
|
FGNavList *navlist = new FGNavList;
|
||||||
FGNavList *loclist = new FGNavList;
|
FGNavList *loclist = new FGNavList;
|
||||||
FGNavList *gslist = new FGNavList;
|
FGNavList *gslist = new FGNavList;
|
||||||
|
@ -1435,7 +1428,7 @@ bool fgInitSubsystems() {
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Initialise the ATIS Subsystem
|
// 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
|
route.cxx
|
||||||
routePath.cxx
|
routePath.cxx
|
||||||
waypoint.cxx
|
waypoint.cxx
|
||||||
|
PositionedBinding.cxx
|
||||||
)
|
)
|
||||||
|
|
||||||
flightgear_component(Navaids "${SOURCES}")
|
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 <Airports/xmlloader.hxx>
|
||||||
|
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
|
#include <Navaids/PositionedBinding.hxx>
|
||||||
|
|
||||||
FGNavRecord::FGNavRecord(Type aTy, const std::string& aIdent,
|
FGNavRecord::FGNavRecord(Type aTy, const std::string& aIdent,
|
||||||
const std::string& aName, const SGGeod& aPos,
|
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) :
|
FGTACANRecord::FGTACANRecord(void) :
|
||||||
channel(""),
|
channel(""),
|
||||||
freq(0)
|
freq(0)
|
||||||
|
|
|
@ -89,12 +89,17 @@ public:
|
||||||
*/
|
*/
|
||||||
FGRunway* runway() const { return mRunway; }
|
FGRunway* runway() const { return mRunway; }
|
||||||
|
|
||||||
|
virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return the localizer width, in degrees
|
* return the localizer width, in degrees
|
||||||
* computation is based up ICAO stdandard width at the runway threshold
|
* computation is based up ICAO stdandard width at the runway threshold
|
||||||
* see implementation for further details.
|
* see implementation for further details.
|
||||||
*/
|
*/
|
||||||
double localizerWidth() const;
|
double localizerWidth() const;
|
||||||
|
|
||||||
|
void bindToNode(SGPropertyNode* nd) const;
|
||||||
|
void unbindFromNode(SGPropertyNode* nd) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FGTACANRecord : public SGReferenced {
|
class FGTACANRecord : public SGReferenced {
|
||||||
|
|
|
@ -35,11 +35,16 @@
|
||||||
#include <osg/Math> // for osg::isNaN
|
#include <osg/Math> // for osg::isNaN
|
||||||
|
|
||||||
#include <simgear/timing/timestamp.hxx>
|
#include <simgear/timing/timestamp.hxx>
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <simgear/structure/exception.hxx>
|
#include <simgear/structure/exception.hxx>
|
||||||
#include <simgear/math/SGGeometry.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::multimap<std::string, FGPositioned*> NamedPositionedIndex;
|
||||||
typedef std::pair<NamedPositionedIndex::const_iterator, NamedPositionedIndex::const_iterator> NamedIndexRange;
|
typedef std::pair<NamedPositionedIndex::const_iterator, NamedPositionedIndex::const_iterator> NamedIndexRange;
|
||||||
|
@ -628,7 +633,15 @@ FGPositioned::Type FGPositioned::typeFromName(const std::string& aName)
|
||||||
{"fix", FIX},
|
{"fix", FIX},
|
||||||
{"tacan", TACAN},
|
{"tacan", TACAN},
|
||||||
{"dme", DME},
|
{"dme", DME},
|
||||||
|
{"atis", FREQ_ATIS},
|
||||||
|
{"awos", FREQ_AWOS},
|
||||||
|
{"tower", FREQ_TOWER},
|
||||||
|
{"ground", FREQ_GROUND},
|
||||||
|
{"approach", FREQ_APP_DEP},
|
||||||
|
{"departure", FREQ_APP_DEP},
|
||||||
// aliases
|
// aliases
|
||||||
|
{"gnd", FREQ_GROUND},
|
||||||
|
{"twr", FREQ_TOWER},
|
||||||
{"waypoint", WAYPOINT},
|
{"waypoint", WAYPOINT},
|
||||||
{"apt", AIRPORT},
|
{"apt", AIRPORT},
|
||||||
{"arpt", AIRPORT},
|
{"arpt", AIRPORT},
|
||||||
|
@ -672,11 +685,24 @@ const char* FGPositioned::nameForType(Type aTy)
|
||||||
case WAYPOINT: return "waypoint";
|
case WAYPOINT: return "waypoint";
|
||||||
case DME: return "dme";
|
case DME: return "dme";
|
||||||
case TACAN: return "tacan";
|
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:
|
default:
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flightgear::PositionedBinding*
|
||||||
|
FGPositioned::createBinding(SGPropertyNode* node) const
|
||||||
|
{
|
||||||
|
return new flightgear::PositionedBinding(this, node);
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// search / query functions
|
// search / query functions
|
||||||
|
|
||||||
|
@ -811,3 +837,145 @@ FGPositioned::sortByRange(List& aResult, const SGGeod& aPos)
|
||||||
aResult[i] = r[i].get();
|
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>
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
|
||||||
class FGPositioned;
|
class FGPositioned;
|
||||||
|
class SGPropertyNode;
|
||||||
|
|
||||||
typedef SGSharedPtr<FGPositioned> FGPositionedRef;
|
typedef SGSharedPtr<FGPositioned> FGPositionedRef;
|
||||||
|
|
||||||
|
namespace flightgear
|
||||||
|
{
|
||||||
|
class PositionedBinding;
|
||||||
|
}
|
||||||
|
|
||||||
class FGPositioned : public SGReferenced
|
class FGPositioned : public SGReferenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -56,9 +62,14 @@ public:
|
||||||
DME,
|
DME,
|
||||||
TACAN,
|
TACAN,
|
||||||
OBSTACLE,
|
OBSTACLE,
|
||||||
FREQ_GND,
|
FREQ_GROUND,
|
||||||
FREQ_TWR,
|
FREQ_TOWER,
|
||||||
FREQ_ATIS,
|
FREQ_ATIS,
|
||||||
|
FREQ_AWOS,
|
||||||
|
FREQ_APP_DEP,
|
||||||
|
FREQ_ENROUTE,
|
||||||
|
FREQ_CLEARANCE,
|
||||||
|
FREQ_UNICOM,
|
||||||
LAST_TYPE
|
LAST_TYPE
|
||||||
} Type;
|
} Type;
|
||||||
|
|
||||||
|
@ -97,6 +108,9 @@ public:
|
||||||
double elevation() const
|
double elevation() const
|
||||||
{ return mPosition.getElevationFt(); }
|
{ return mPosition.getElevationFt(); }
|
||||||
|
|
||||||
|
|
||||||
|
virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Predicate class to support custom filtering of FGPositioned queries
|
* Predicate class to support custom filtering of FGPositioned queries
|
||||||
* Default implementation of this passes any FGPositioned instance.
|
* Default implementation of this passes any FGPositioned instance.
|
||||||
|
@ -135,13 +149,15 @@ public:
|
||||||
class TypeFilter : public Filter
|
class TypeFilter : public Filter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TypeFilter(Type aTy) : mType(aTy) { ; }
|
TypeFilter(Type aTy);
|
||||||
virtual bool pass(FGPositioned* aPos) const
|
virtual bool pass(FGPositioned* aPos) const;
|
||||||
{ return (mType == aPos->type()); }
|
void addType(Type aTy);
|
||||||
private:
|
private:
|
||||||
const Type mType;
|
std::vector<Type> types;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void installCommands();
|
||||||
|
|
||||||
static List findWithinRange(const SGGeod& aPos, double aRangeNm, Filter* aFilter = NULL);
|
static List findWithinRange(const SGGeod& aPos, double aRangeNm, Filter* aFilter = NULL);
|
||||||
|
|
||||||
static FGPositionedRef findClosestWithIdent(const std::string& aIdent, const SGGeod& aPos, Filter* aFilter = NULL);
|
static FGPositionedRef findClosestWithIdent(const std::string& aIdent, const SGGeod& aPos, Filter* aFilter = NULL);
|
||||||
|
|
Loading…
Add table
Reference in a new issue