Cleanup of ATCDCL
- move FGATCAlignedProjection class as AlignedProjection to dclgps, the only place where it's currently used - remove now obsolete files in ATCDCL
This commit is contained in:
parent
1c5c1b2cb1
commit
d2c000699f
19 changed files with 76 additions and 3061 deletions
|
@ -1,413 +0,0 @@
|
|||
// Implementation of FGATC - ATC subsystem base class.
|
||||
//
|
||||
// Written by David Luff, started February 2002.
|
||||
//
|
||||
// Copyright (C) 2002 David C Luff - david.luff@nottingham.ac.uk
|
||||
//
|
||||
// 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 "ATC.hxx"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <simgear/sound/soundmgr_openal.hxx>
|
||||
#include <simgear/sound/sample_group.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <ATC/CommStation.hxx>
|
||||
#include <Airports/airport.hxx>
|
||||
|
||||
FGATC::FGATC() :
|
||||
freq(0),
|
||||
_currentStation(NULL),
|
||||
range(0),
|
||||
_voice(true),
|
||||
_playing(false),
|
||||
_sgr(NULL),
|
||||
_type(INVALID),
|
||||
_display(false)
|
||||
#ifdef OLD_ATC_MGR
|
||||
,freqClear(true),
|
||||
receiving(false),
|
||||
respond(false),
|
||||
responseID(""),
|
||||
runResponseCounter(false),
|
||||
_runReleaseCounter(false),
|
||||
responseReqd(false),
|
||||
// Transmission timing stuff
|
||||
pending_transmission(""),
|
||||
_timeout(0),
|
||||
_pending(false),
|
||||
_transmit(false),
|
||||
_transmitting(false),
|
||||
_counter(0.0),
|
||||
_max_count(5.0)
|
||||
#endif
|
||||
{
|
||||
SGSoundMgr *smgr = globals->get_soundmgr();
|
||||
_sgr = smgr->find("atc", true);
|
||||
_sgr->tie_to_listener();
|
||||
|
||||
_masterVolume = fgGetNode("/sim/sound/atc/volume", true);
|
||||
_enabled = fgGetNode("/sim/sound/atc/enabled", true);
|
||||
_atc_external = fgGetNode("/sim/sound/atc/external-view", true);
|
||||
_internal = fgGetNode("/sim/current-view/internal", true);
|
||||
}
|
||||
|
||||
FGATC::~FGATC() {
|
||||
}
|
||||
|
||||
#ifndef OLD_ATC_MGR
|
||||
// Derived classes wishing to use the response counter should
|
||||
// call this from their own Update(...).
|
||||
void FGATC::update(double dt) {
|
||||
|
||||
// TODO This doesn't really do anything specific to this instance.
|
||||
// All FGATCs share the same "_sgr" sound group. So this really should
|
||||
// only be done once for all FGATCs.
|
||||
#ifdef ENABLE_AUDIO_SUPPORT
|
||||
bool active = _atc_external->getBoolValue() ||
|
||||
_internal->getBoolValue();
|
||||
|
||||
if ( active && _enabled->getBoolValue() ) {
|
||||
_sgr->set_volume( _masterVolume->getFloatValue() );
|
||||
_sgr->resume(); // no-op if already in resumed state
|
||||
} else {
|
||||
_sgr->suspend();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void FGATC::SetStation(flightgear::CommStation* sta) {
|
||||
if (_currentStation == sta)
|
||||
return;
|
||||
_currentStation = sta;
|
||||
|
||||
if (sta)
|
||||
{
|
||||
switch (sta->type()) {
|
||||
case FGPositioned::FREQ_ATIS: _type = ATIS; break;
|
||||
case FGPositioned::FREQ_AWOS: _type = AWOS; break;
|
||||
default:
|
||||
sta = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sta == NULL)
|
||||
{
|
||||
range = 0;
|
||||
ident = "";
|
||||
name = "";
|
||||
freq = 0;
|
||||
|
||||
SetNoDisplay();
|
||||
update(0); // one last update
|
||||
}
|
||||
else
|
||||
{
|
||||
_geod = sta->geod();
|
||||
_cart = sta->cart();
|
||||
|
||||
range = sta->rangeNm();
|
||||
ident = sta->airport()->ident();
|
||||
name = sta->airport()->name();
|
||||
freq = sta->freqKHz();
|
||||
SetDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
// Render a transmission
|
||||
// Outputs the transmission either on screen or as audio depending on user preference
|
||||
// The refname is a string to identify this sample to the sound manager
|
||||
// The repeating flag indicates whether the message should be repeated continuously or played once.
|
||||
void FGATC::Render(std::string& msg, const float volume,
|
||||
const std::string& refname, const bool repeating) {
|
||||
if ((!_display) ||(volume < 0.05))
|
||||
{
|
||||
NoRender(refname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (repeating)
|
||||
fgSetString("/sim/messages/atis", msg.c_str());
|
||||
else
|
||||
fgSetString("/sim/messages/atc", msg.c_str());
|
||||
|
||||
#ifdef ENABLE_AUDIO_SUPPORT
|
||||
bool useVoice = _voice && fgGetBool("/sim/sound/voice") && fgGetBool("/sim/sound/atc/enabled");
|
||||
SGSoundSample *simple = _sgr->find(refname);
|
||||
if(useVoice) {
|
||||
if (simple && (_currentMsg == msg))
|
||||
{
|
||||
simple->set_volume(volume);
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentMsg = msg;
|
||||
size_t len;
|
||||
void* buf = NULL;
|
||||
FGATCVoice* vPtr = GetVoicePointer();
|
||||
if (vPtr)
|
||||
buf = vPtr->WriteMessage((char*)msg.c_str(), &len);
|
||||
NoRender(refname);
|
||||
if(buf) {
|
||||
try {
|
||||
// >>> Beware: must pass a (new) object to the (add) method,
|
||||
// >>> because the (remove) method is going to do a (delete)
|
||||
// >>> whether that's what you want or not.
|
||||
simple = new SGSoundSample(&buf, len, 8000);
|
||||
simple->set_volume(volume);
|
||||
_sgr->add(simple, refname);
|
||||
_sgr->play(refname, repeating);
|
||||
} catch ( sg_io_exception &e ) {
|
||||
SG_LOG(SG_ATC, SG_ALERT, e.getFormattedMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (simple)
|
||||
{
|
||||
NoRender(refname);
|
||||
}
|
||||
#else
|
||||
bool useVoice = false;
|
||||
#endif // ENABLE_AUDIO_SUPPORT
|
||||
|
||||
if (!useVoice)
|
||||
{
|
||||
// first rip the underscores and the pause hints out of the string - these are for the convenience of the voice parser
|
||||
for(unsigned int i = 0; i < msg.length(); ++i) {
|
||||
if((msg.substr(i,1) == "_") || (msg.substr(i,1) == "/")) {
|
||||
msg[i] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
_playing = true;
|
||||
}
|
||||
|
||||
|
||||
// Cease rendering a transmission.
|
||||
void FGATC::NoRender(const std::string& refname) {
|
||||
if(_playing) {
|
||||
if(_voice) {
|
||||
#ifdef ENABLE_AUDIO_SUPPORT
|
||||
_sgr->stop(refname);
|
||||
_sgr->remove(refname);
|
||||
#endif
|
||||
}
|
||||
_playing = false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef OLD_ATC_MGR
|
||||
// Derived classes wishing to use the response counter should
|
||||
// call this from their own Update(...).
|
||||
void FGATC::Update(double dt) {
|
||||
|
||||
#ifdef ENABLE_AUDIO_SUPPORT
|
||||
bool active = _atc_external->getBoolValue() ||
|
||||
_internal->getBoolValue();
|
||||
|
||||
if ( active && _enabled->getBoolValue() ) {
|
||||
_sgr->set_volume( _masterVolume->getFloatValue() );
|
||||
_sgr->resume(); // no-op if already in resumed state
|
||||
} else {
|
||||
_sgr->suspend();
|
||||
}
|
||||
#endif
|
||||
|
||||
if(runResponseCounter) {
|
||||
//cout << responseCounter << '\t' << responseTime << '\n';
|
||||
if(responseCounter >= responseTime) {
|
||||
runResponseCounter = false;
|
||||
respond = true;
|
||||
//cout << "RESPOND\n";
|
||||
} else {
|
||||
responseCounter += dt;
|
||||
}
|
||||
}
|
||||
|
||||
if(_runReleaseCounter) {
|
||||
if(_releaseCounter >= _releaseTime) {
|
||||
freqClear = true;
|
||||
_runReleaseCounter = false;
|
||||
} else {
|
||||
_releaseCounter += dt;
|
||||
}
|
||||
}
|
||||
|
||||
// Transmission stuff cribbed from AIPlane.cxx
|
||||
if(_pending) {
|
||||
if(GetFreqClear()) {
|
||||
//cout << "TUNED STATION FREQ CLEAR\n";
|
||||
SetFreqInUse();
|
||||
_pending = false;
|
||||
_transmit = true;
|
||||
_transmitting = false;
|
||||
} else {
|
||||
if(_timeout > 0.0) { // allows count down to be avoided by initially setting it to zero
|
||||
_timeout -= dt;
|
||||
if(_timeout <= 0.0) {
|
||||
_timeout = 0.0;
|
||||
_pending = false;
|
||||
// timed out - don't render.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(_transmit) {
|
||||
_counter = 0.0;
|
||||
_max_count = 5.0; // FIXME - hardwired length of message - need to calculate it!
|
||||
|
||||
//cout << "Transmission = " << pending_transmission << '\n';
|
||||
if(_display) {
|
||||
//Render(pending_transmission, ident, false);
|
||||
Render(pending_transmission);
|
||||
}
|
||||
_transmit = false;
|
||||
_transmitting = true;
|
||||
} else if(_transmitting) {
|
||||
if(_counter >= _max_count) {
|
||||
//NoRender(plane.callsign); commented out since at the moment NoRender is designed just to stop repeating messages,
|
||||
// and this will be primarily used on single messages.
|
||||
_transmitting = false;
|
||||
//if(tuned_station) tuned_station->NotifyTransmissionFinished(plane.callsign);
|
||||
// TODO - need to let the plane the transmission is aimed at that it's finished.
|
||||
// However, for now we'll just release the frequency since if we don't it all goes pear-shaped
|
||||
_releaseCounter = 0.0;
|
||||
_releaseTime = 0.9;
|
||||
_runReleaseCounter = true;
|
||||
}
|
||||
_counter += dt;
|
||||
}
|
||||
}
|
||||
|
||||
void FGATC::ReceiveUserCallback(int code) {
|
||||
SG_LOG(SG_ATC, SG_WARN, "WARNING - whichever ATC class was intended to receive callback code " << code << " didn't get it!!!");
|
||||
}
|
||||
|
||||
void FGATC::SetResponseReqd(const string& rid) {
|
||||
receiving = false;
|
||||
responseReqd = true;
|
||||
respond = false; // TODO - this ignores the fact that more than one plane could call this before response
|
||||
// Shouldn't happen with AI only, but user could confuse things??
|
||||
responseID = rid;
|
||||
runResponseCounter = true;
|
||||
responseCounter = 0.0;
|
||||
responseTime = 1.8; // TODO - randomize this slightly.
|
||||
}
|
||||
|
||||
void FGATC::NotifyTransmissionFinished(const string& rid) {
|
||||
//cout << "Transmission finished, callsign = " << rid << '\n';
|
||||
receiving = false;
|
||||
responseID = rid;
|
||||
if(responseReqd) {
|
||||
runResponseCounter = true;
|
||||
responseCounter = 0.0;
|
||||
responseTime = 1.2; // TODO - randomize this slightly, and allow it to be dependent on the transmission and how busy the ATC is.
|
||||
respond = false; // TODO - this ignores the fact that more than one plane could call this before response
|
||||
// Shouldn't happen with AI only, but user could confuse things??
|
||||
} else {
|
||||
freqClear = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the text of a message from its parameters and the current context.
|
||||
string FGATC::GenText(const string& m, int c) {
|
||||
return("");
|
||||
}
|
||||
|
||||
ostream& operator << (ostream& os, atc_type atc) {
|
||||
switch(atc) {
|
||||
case(AWOS): return(os << "AWOS");
|
||||
case(ATIS): return(os << "ATIS");
|
||||
case(GROUND): return(os << "GROUND");
|
||||
case(TOWER): return(os << "TOWER");
|
||||
case(APPROACH): return(os << "APPROACH");
|
||||
case(DEPARTURE): return(os << "DEPARTURE");
|
||||
case(ENROUTE): return(os << "ENROUTE");
|
||||
case(INVALID): return(os << "INVALID");
|
||||
}
|
||||
return(os << "ERROR - Unknown switch in atc_type operator << ");
|
||||
}
|
||||
|
||||
std::istream& operator >> ( std::istream& fin, ATCData& a )
|
||||
{
|
||||
double f;
|
||||
char ch;
|
||||
char tp;
|
||||
|
||||
fin >> tp;
|
||||
|
||||
switch(tp) {
|
||||
case 'I':
|
||||
a.type = ATIS;
|
||||
break;
|
||||
case 'T':
|
||||
a.type = TOWER;
|
||||
break;
|
||||
case 'G':
|
||||
a.type = GROUND;
|
||||
break;
|
||||
case 'A':
|
||||
a.type = APPROACH;
|
||||
break;
|
||||
case '[':
|
||||
a.type = INVALID;
|
||||
return fin >> skipeol;
|
||||
default:
|
||||
SG_LOG(SG_ATC, SG_ALERT, "Warning - unknown type \'" << tp << "\' found whilst reading ATC frequency data!\n");
|
||||
a.type = INVALID;
|
||||
return fin >> skipeol;
|
||||
}
|
||||
|
||||
double lat, lon, elev;
|
||||
|
||||
fin >> lat >> lon >> elev >> f >> a.range >> a.ident;
|
||||
a.geod = SGGeod::fromDegM(lon, lat, elev);
|
||||
a.name = "";
|
||||
fin >> ch;
|
||||
if(ch != '"') a.name += ch;
|
||||
while(1) {
|
||||
//in >> noskipws
|
||||
fin.unsetf(std::ios::skipws);
|
||||
fin >> ch;
|
||||
if((ch == '"') || (ch == 0x0A)) {
|
||||
break;
|
||||
} // we shouldn't need the 0x0A but it makes a nice safely in case someone leaves off the "
|
||||
a.name += ch;
|
||||
}
|
||||
fin.setf(std::ios::skipws);
|
||||
//cout << "Comm name = " << a.name << '\n';
|
||||
|
||||
a.freq = (int)(f*100.0 + 0.5);
|
||||
|
||||
// cout << a.ident << endl;
|
||||
|
||||
// generate cartesian coordinates
|
||||
a.cart = SGVec3d::fromGeod(a.geod);
|
||||
return fin >> skipeol;
|
||||
}
|
||||
#endif
|
|
@ -1,226 +0,0 @@
|
|||
// FGATC - abstract base class for the various actual atc classes
|
||||
// such as FGATIS, FGTower etc.
|
||||
//
|
||||
// Written by David Luff, started Feburary 2002.
|
||||
//
|
||||
// Copyright (C) 2002 David C. Luff - david.luff@nottingham.ac.uk
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#ifndef _FG_ATC_HXX
|
||||
#define _FG_ATC_HXX
|
||||
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "ATCVoice.hxx"
|
||||
|
||||
class SGSampleGroup;
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
class CommStation;
|
||||
}
|
||||
|
||||
// Possible types of ATC type that the radios may be tuned to.
|
||||
// INVALID implies not tuned in to anything.
|
||||
enum atc_type {
|
||||
AWOS,
|
||||
ATIS,
|
||||
GROUND,
|
||||
TOWER,
|
||||
APPROACH,
|
||||
DEPARTURE,
|
||||
ENROUTE,
|
||||
INVALID /* must be last element; see ATC_NUM_TYPES */
|
||||
};
|
||||
|
||||
#ifdef OLD_ATC_MGR
|
||||
const int ATC_NUM_TYPES = 1 + INVALID;
|
||||
|
||||
// DCL - new experimental ATC data store
|
||||
struct ATCData {
|
||||
ATCData() : type(INVALID), cart(0, 0, 0), freq(0), range(0) {}
|
||||
atc_type type;
|
||||
SGGeod geod;
|
||||
SGVec3d cart;
|
||||
unsigned short int freq;
|
||||
unsigned short int range;
|
||||
std::string ident;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
// perhaps we could use an FGRunway instead of this.
|
||||
// That wouldn't cache the orthopos though.
|
||||
struct RunwayDetails {
|
||||
RunwayDetails() : end1ortho(0, 0, 0), end2ortho(0, 0, 0), hdg(0), length(-1), width(-1) {}
|
||||
SGGeod threshold_pos;
|
||||
SGVec3d end1ortho; // ortho projection end1 (the threshold ATM)
|
||||
SGVec3d end2ortho; // ortho projection end2 (the take off end in the current hardwired scheme)
|
||||
double hdg; // true runway heading
|
||||
double length; // In *METERS*
|
||||
double width; // ditto
|
||||
std::string rwyID;
|
||||
int patternDirection; // -1 for left, 1 for right
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, atc_type atc);
|
||||
#endif
|
||||
|
||||
class FGATC {
|
||||
friend class FGATISMgr;
|
||||
public:
|
||||
|
||||
FGATC();
|
||||
virtual ~FGATC();
|
||||
|
||||
virtual void init()=0;
|
||||
|
||||
// Run the internal calculations
|
||||
// Derived classes should call this method from their own Update methods if they
|
||||
// wish to use the response timer functionality.
|
||||
virtual void update(double dt);
|
||||
|
||||
// Indicate that this instance should output to the display if appropriate
|
||||
inline void SetDisplay() { _display = true; }
|
||||
|
||||
// Indicate that this instance should not output to the display
|
||||
inline void SetNoDisplay() { _display = false; }
|
||||
|
||||
#ifdef OLD_ATC_MGR
|
||||
// Receive a coded callback from the ATC menu system based on the user's selection
|
||||
virtual void ReceiveUserCallback(int code);
|
||||
|
||||
// Generate the text of a message from its parameters and the current context.
|
||||
virtual std::string GenText(const std::string& m, int c);
|
||||
|
||||
// Returns true if OK to transmit on this frequency
|
||||
inline bool GetFreqClear() { return freqClear; }
|
||||
// Indicate that the frequency is in use
|
||||
inline void SetFreqInUse() { freqClear = false; receiving = true; }
|
||||
// Transmission to the ATC is finished and a response is required
|
||||
void SetResponseReqd(const std::string& rid);
|
||||
// Transmission finished - let ATC decide if a response is reqd and clear freq if necessary
|
||||
void NotifyTransmissionFinished(const std::string& rid);
|
||||
// Transmission finished and no response required
|
||||
inline void ReleaseFreq() { freqClear = true; receiving = false; } // TODO - check that the plane releasing the freq is the right one etc.
|
||||
// The above 3 funcs under development!!
|
||||
// The idea is that AI traffic or the user ATC dialog box calls FreqInUse() when they begin transmitting,
|
||||
// and that the tower control sets freqClear back to true following a reply.
|
||||
// AI traffic should check FreqClear() is true prior to transmitting.
|
||||
// The user will just have to wait for a gap in dialog as in real life.
|
||||
|
||||
|
||||
|
||||
inline int get_freq() const { return freq; }
|
||||
inline void set_freq(const int fq) {freq = fq;}
|
||||
inline int get_range() const { return range; }
|
||||
inline void set_range(const int rg) {range = rg;}
|
||||
#endif
|
||||
// Return the type of ATC station that the class represents
|
||||
inline atc_type GetType() { return _type; }
|
||||
|
||||
// Set the core ATC data
|
||||
void SetStation(flightgear::CommStation* sta);
|
||||
|
||||
inline const std::string& get_ident() { return ident; }
|
||||
inline void set_ident(const std::string& id) { ident = id; }
|
||||
inline const std::string& get_name() { return name; }
|
||||
inline void set_name(const std::string& nm) { name = nm; }
|
||||
|
||||
protected:
|
||||
|
||||
// Render a transmission
|
||||
// Outputs the transmission either on screen or as audio depending on user preference
|
||||
// The refname is a string to identify this sample to the sound manager
|
||||
// The repeating flag indicates whether the message should be repeated continuously or played once.
|
||||
void Render(std::string& msg, const float volume = 1.0,
|
||||
const std::string& refname = "", bool repeating = false);
|
||||
|
||||
// Cease rendering all transmission from this station.
|
||||
// Requires the sound manager refname if audio, else "".
|
||||
void NoRender(const std::string& refname);
|
||||
|
||||
virtual FGATCVoice* GetVoicePointer() = 0;
|
||||
|
||||
SGGeod _geod;
|
||||
SGVec3d _cart;
|
||||
int freq;
|
||||
flightgear::CommStation* _currentStation;
|
||||
|
||||
int range;
|
||||
std::string ident; // Code of the airport its at.
|
||||
std::string name; // Name transmitted in the broadcast.
|
||||
std::string _currentMsg; // Current message being transmitted
|
||||
|
||||
// Rendering related stuff
|
||||
bool _voice; // Flag - true if we are using voice
|
||||
bool _playing; // Indicates a message in progress
|
||||
|
||||
SGSharedPtr<SGSampleGroup> _sgr; // default sample group;
|
||||
|
||||
#ifdef OLD_ATC_MGR
|
||||
bool freqClear; // Flag to indicate if the frequency is clear of ongoing dialog
|
||||
bool receiving; // Flag to indicate we are receiving a transmission
|
||||
|
||||
|
||||
double responseTime; // Time to take from end of request transmission to beginning of response
|
||||
// The idea is that this will be slightly random.
|
||||
|
||||
bool respond; // Flag to indicate now is the time to respond - ie set following the count down of the response timer.
|
||||
std::string responseID; // ID of the plane to respond to
|
||||
bool runResponseCounter; // Flag to indicate the response counter should be run
|
||||
double responseCounter; // counter to implement the above
|
||||
// Derived classes only need monitor this flag, and use the response ID, as long as they call FGATC::Update(...)
|
||||
bool _runReleaseCounter; // A timer for releasing the frequency after giving the message enough time to display
|
||||
bool responseReqd; // Flag to indicate we should be responding to a request/report
|
||||
double _releaseTime;
|
||||
double _releaseCounter;
|
||||
std::string pending_transmission; // derived classes set this string before calling Transmit(...)
|
||||
#endif
|
||||
atc_type _type;
|
||||
bool _display; // Flag to indicate whether we should be outputting to the ATC display.
|
||||
|
||||
private:
|
||||
|
||||
#ifdef OLD_ATC_MGR
|
||||
// Transmission timing stuff.
|
||||
double _timeout;
|
||||
bool _pending;
|
||||
bool _transmit; // we are to transmit
|
||||
bool _transmitting; // we are transmitting
|
||||
double _counter;
|
||||
double _max_count;
|
||||
#endif
|
||||
|
||||
SGPropertyNode_ptr _masterVolume;
|
||||
SGPropertyNode_ptr _enabled;
|
||||
SGPropertyNode_ptr _atc_external;
|
||||
SGPropertyNode_ptr _internal;
|
||||
};
|
||||
|
||||
#ifdef OLD_ATC_MGR
|
||||
std::istream& operator>> ( std::istream& fin, ATCData& a );
|
||||
#endif
|
||||
|
||||
#endif // _FG_ATC_HXX
|
|
@ -1,79 +0,0 @@
|
|||
// ATCProjection.cxx - A convenience projection class for the ATC/AI system.
|
||||
//
|
||||
// Written by David Luff, started 2002.
|
||||
//
|
||||
// Copyright (C) 2002 David C Luff - david.luff@nottingham.ac.uk
|
||||
//
|
||||
// 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 "ATCProjection.hxx"
|
||||
#include <math.h>
|
||||
#include <simgear/constants.h>
|
||||
|
||||
FGATCAlignedProjection::FGATCAlignedProjection() {
|
||||
_origin.setLatitudeRad(0);
|
||||
_origin.setLongitudeRad(0);
|
||||
_origin.setElevationM(0);
|
||||
_correction_factor = cos(_origin.getLatitudeRad());
|
||||
}
|
||||
|
||||
FGATCAlignedProjection::FGATCAlignedProjection(const SGGeod& centre, double heading) {
|
||||
_origin = centre;
|
||||
_theta = heading * SG_DEGREES_TO_RADIANS;
|
||||
_correction_factor = cos(_origin.getLatitudeRad());
|
||||
}
|
||||
|
||||
FGATCAlignedProjection::~FGATCAlignedProjection() {
|
||||
}
|
||||
|
||||
void FGATCAlignedProjection::Init(const SGGeod& centre, double heading) {
|
||||
_origin = centre;
|
||||
_theta = heading * SG_DEGREES_TO_RADIANS;
|
||||
_correction_factor = cos(_origin.getLatitudeRad());
|
||||
}
|
||||
|
||||
SGVec3d FGATCAlignedProjection::ConvertToLocal(const SGGeod& pt) {
|
||||
// convert from lat/lon to orthogonal
|
||||
double delta_lat = pt.getLatitudeRad() - _origin.getLatitudeRad();
|
||||
double delta_lon = pt.getLongitudeRad() - _origin.getLongitudeRad();
|
||||
double y = sin(delta_lat) * SG_EQUATORIAL_RADIUS_M;
|
||||
double x = sin(delta_lon) * SG_EQUATORIAL_RADIUS_M * _correction_factor;
|
||||
|
||||
// Align
|
||||
if(_theta != 0.0) {
|
||||
double xbar = x;
|
||||
x = x*cos(_theta) - y*sin(_theta);
|
||||
y = (xbar*sin(_theta)) + (y*cos(_theta));
|
||||
}
|
||||
|
||||
return SGVec3d(x, y, pt.getElevationM());
|
||||
}
|
||||
|
||||
SGGeod FGATCAlignedProjection::ConvertFromLocal(const SGVec3d& pt) {
|
||||
// de-align
|
||||
double thi = _theta * -1.0;
|
||||
double x = pt.x()*cos(thi) - pt.y()*sin(thi);
|
||||
double y = (pt.x()*sin(thi)) + (pt.y()*cos(thi));
|
||||
|
||||
// convert from orthogonal to lat/lon
|
||||
double delta_lat = asin(y / SG_EQUATORIAL_RADIUS_M);
|
||||
double delta_lon = asin(x / SG_EQUATORIAL_RADIUS_M) / _correction_factor;
|
||||
|
||||
return SGGeod::fromRadM(_origin.getLongitudeRad()+delta_lon, _origin.getLatitudeRad()+delta_lat, pt.z());
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
// ATCProjection.hxx - A convenience projection class for the ATC/AI system.
|
||||
//
|
||||
// Written by David Luff, started 2002.
|
||||
//
|
||||
// Copyright (C) 2002 David C Luff - david.luff@nottingham.ac.uk
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#ifndef _FG_ATC_PROJECTION_HXX
|
||||
#define _FG_ATC_PROJECTION_HXX
|
||||
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
// FGATCAlignedProjection - a class to project an area local to a runway onto an orthogonal co-ordinate system
|
||||
// with the origin at the threshold and the runway aligned with the y axis.
|
||||
class FGATCAlignedProjection {
|
||||
|
||||
public:
|
||||
FGATCAlignedProjection();
|
||||
FGATCAlignedProjection(const SGGeod& centre, double heading);
|
||||
~FGATCAlignedProjection();
|
||||
|
||||
void Init(const SGGeod& centre, double heading);
|
||||
|
||||
// Convert a lat/lon co-ordinate (degrees) to the local projection (meters)
|
||||
SGVec3d ConvertToLocal(const SGGeod& pt);
|
||||
|
||||
// Convert a local projection co-ordinate (meters) to lat/lon (degrees)
|
||||
SGGeod ConvertFromLocal(const SGVec3d& pt);
|
||||
|
||||
private:
|
||||
SGGeod _origin; // lat/lon of local area origin (the threshold)
|
||||
double _theta; // the rotation angle for alignment in radians
|
||||
double _correction_factor; // Reduction in surface distance per degree of longitude due to latitude. Saves having to do a cos() every call.
|
||||
|
||||
};
|
||||
|
||||
#endif // _FG_ATC_PROJECTION_HXX
|
|
@ -1,297 +0,0 @@
|
|||
// FGATCVoice.cxx - a class to encapsulate an ATC voice
|
||||
//
|
||||
// Written by David Luff, started November 2002.
|
||||
//
|
||||
// Copyright (C) 2002 David C Luff - david.luff@nottingham.ac.uk
|
||||
//
|
||||
// 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 "ATCVoice.hxx"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <simgear/sound/soundmgr_openal.hxx>
|
||||
#include <simgear/sound/sample_openal.hxx>
|
||||
#include <simgear/misc/sg_dir.hxx>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
#include <simgear/math/sg_random.h>
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
|
||||
using namespace std;
|
||||
|
||||
FGATCVoice::FGATCVoice() :
|
||||
rawSoundData(0),
|
||||
rawDataSize(0),
|
||||
SoundData(0)
|
||||
{
|
||||
}
|
||||
|
||||
FGATCVoice::~FGATCVoice() {
|
||||
if (rawSoundData)
|
||||
free( rawSoundData );
|
||||
delete SoundData;
|
||||
}
|
||||
|
||||
// Load all data for the requested voice.
|
||||
// Return true if successful.
|
||||
bool FGATCVoice::LoadVoice(const string& voicename)
|
||||
{
|
||||
rawDataSize = 0;
|
||||
if (rawSoundData)
|
||||
free(rawSoundData);
|
||||
rawSoundData = NULL;
|
||||
|
||||
// determine voice directory
|
||||
SGPath voicepath = globals->get_fg_root();
|
||||
voicepath.append( "ATC" );
|
||||
voicepath.append( "voices" );
|
||||
voicepath.append( voicename );
|
||||
|
||||
simgear::Dir d(voicepath);
|
||||
if (!d.exists())
|
||||
{
|
||||
SG_LOG(SG_ATC, SG_ALERT, "Unable to load ATIS voice. No such directory: " << voicepath.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// load all files from the voice's directory
|
||||
simgear::PathList paths = d.children(simgear::Dir::TYPE_FILE);
|
||||
bool Ok = false;
|
||||
for (unsigned int i=0; i<paths.size(); ++i)
|
||||
{
|
||||
if (paths[i].lower_extension() == "vce")
|
||||
Ok |= AppendVoiceFile(voicepath, paths[i].file_base());
|
||||
}
|
||||
|
||||
if (!Ok)
|
||||
{
|
||||
SG_LOG(SG_ATC, SG_ALERT, "Unable to load ATIS voice. Files are invalid or no files in directory: " << voicepath.str());
|
||||
}
|
||||
|
||||
// ok when at least some files loaded fine
|
||||
return Ok;
|
||||
}
|
||||
|
||||
// load a voice file and append it to the current word database
|
||||
bool FGATCVoice::AppendVoiceFile(const SGPath& basepath, const string& file)
|
||||
{
|
||||
size_t offset = 0;
|
||||
|
||||
SG_LOG(SG_ATC, SG_INFO, "Loading ATIS voice file: " << file);
|
||||
|
||||
// path to compressed voice file
|
||||
SGPath path(basepath);
|
||||
path.append(file + ".wav.gz");
|
||||
|
||||
// load wave data
|
||||
SGSoundMgr *smgr = globals->get_soundmgr();
|
||||
int format, freq;
|
||||
void *data;
|
||||
size_t size;
|
||||
if (!smgr->load(path.str(), &data, &format, &size, &freq))
|
||||
return false;
|
||||
|
||||
// append to existing data
|
||||
if (!rawSoundData)
|
||||
rawSoundData = (char*)data;
|
||||
else
|
||||
{
|
||||
rawSoundData = (char*) realloc(rawSoundData, rawDataSize + size);
|
||||
// new data starts behind existing sound data
|
||||
offset = rawDataSize;
|
||||
if (!rawSoundData)
|
||||
{
|
||||
SG_LOG(SG_ATC, SG_ALERT, "Out of memory. Cannot load file " << path.str());
|
||||
rawDataSize = 0;
|
||||
return false;
|
||||
}
|
||||
// append to existing sound data
|
||||
memcpy(rawSoundData+offset, data, size);
|
||||
free(data);
|
||||
data = NULL;
|
||||
}
|
||||
rawDataSize += size;
|
||||
|
||||
#ifdef VOICE_TEST
|
||||
cout << "ATCVoice: format: " << format
|
||||
<< " size: " << rawDataSize << endl;
|
||||
#endif
|
||||
|
||||
// load and parse index file (.vce)
|
||||
return ParseVoiceIndex(basepath, file, offset);
|
||||
}
|
||||
|
||||
// Load and parse a voice index file (.vce)
|
||||
bool FGATCVoice::ParseVoiceIndex(const SGPath& basepath, const string& file, size_t globaloffset)
|
||||
{
|
||||
// path to voice index file
|
||||
SGPath path(basepath);
|
||||
path.append(file + ".vce");
|
||||
|
||||
// Now load the word data
|
||||
std::ifstream fin;
|
||||
fin.open(path.c_str(), ios::in);
|
||||
if(!fin) {
|
||||
SG_LOG(SG_ATC, SG_ALERT, "Unable to open input file " << path.c_str());
|
||||
return(false);
|
||||
}
|
||||
SG_LOG(SG_ATC, SG_INFO, "Opened word data file " << path.c_str() << " OK...");
|
||||
|
||||
char numwds[10];
|
||||
char wrd[100];
|
||||
string wrdstr;
|
||||
char wrdOffsetStr[20];
|
||||
char wrdLengthStr[20];
|
||||
unsigned int wrdOffset; // Offset into the raw sound data that the word sample begins
|
||||
unsigned int wrdLength; // Length of the word sample in bytes
|
||||
WordData wd;
|
||||
|
||||
// first entry: number of words in the index
|
||||
fin >> numwds;
|
||||
unsigned int numwords = atoi(numwds);
|
||||
//cout << numwords << '\n';
|
||||
|
||||
// now load each word, its file offset and length
|
||||
for(unsigned int i=0; i < numwords; ++i) {
|
||||
// read data
|
||||
fin >> wrd;
|
||||
fin >> wrdOffsetStr;
|
||||
fin >> wrdLengthStr;
|
||||
|
||||
wrdstr = wrd;
|
||||
wrdOffset = atoi(wrdOffsetStr);
|
||||
wrdLength = atoi(wrdLengthStr);
|
||||
|
||||
// store word in map
|
||||
wd.offset = wrdOffset + globaloffset;
|
||||
wd.length = wrdLength;
|
||||
wordMap[wrdstr] = wd;
|
||||
|
||||
// post-process words
|
||||
string ws2 = wrdstr;
|
||||
for(string::iterator p = ws2.begin(); p != ws2.end(); p++){
|
||||
*p = tolower(*p);
|
||||
if (*p == '-')
|
||||
*p = '_';
|
||||
}
|
||||
|
||||
// store alternative version of word (lowercase/no hyphen)
|
||||
if (wrdstr != ws2)
|
||||
wordMap[ws2] = wd;
|
||||
|
||||
//cout << wrd << "\t\t" << wrdOffset << "\t\t" << wrdLength << '\n';
|
||||
//cout << i << '\n';
|
||||
}
|
||||
|
||||
fin.close();
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
// Given a desired message, return a string containing the
|
||||
// sound-sample data
|
||||
void* FGATCVoice::WriteMessage(const string& message, size_t* len) {
|
||||
|
||||
// What should we do here?
|
||||
// First - parse the message into a list of tokens.
|
||||
// Sort the tokens into those we understand and those we don't.
|
||||
// Add all the raw lengths of the token sound data, allocate enough space, and fill it with the rqd data.
|
||||
|
||||
vector<char> sound;
|
||||
const char delimiters[] = " \t.,;:\"\n";
|
||||
string::size_type token_start = message.find_first_not_of(delimiters);
|
||||
while(token_start != string::npos) {
|
||||
string::size_type token_end = message.find_first_of(delimiters, token_start);
|
||||
string token;
|
||||
if (token_end == string::npos) {
|
||||
token = message.substr(token_start);
|
||||
token_start = string::npos;
|
||||
} else {
|
||||
token = message.substr(token_start, token_end - token_start);
|
||||
token_start = message.find_first_not_of(delimiters, token_end);
|
||||
}
|
||||
|
||||
if (token == "/_") continue;
|
||||
|
||||
for(string::iterator t = token.begin(); t != token.end(); t++) {
|
||||
// canonicalize the token, to match what's in the index
|
||||
*t = (*t == '-') ? '_' : tolower(*t);
|
||||
}
|
||||
SG_LOG(SG_ATC, SG_DEBUG, "voice synth: token: '"
|
||||
<< token << "'");
|
||||
|
||||
atc_word_map_const_iterator wordIt = wordMap.find(token);
|
||||
if(wordIt == wordMap.end()) {
|
||||
// Oh dear - the token isn't in the sound file
|
||||
SG_LOG(SG_ATC, SG_ALERT, "voice synth: word '"
|
||||
<< token << "' not found");
|
||||
} else {
|
||||
const WordData& word = wordIt->second;
|
||||
/*
|
||||
* Sanity check for corrupt/mismatched sound data input - avoids a seg fault
|
||||
* (As long as the calling function checks the return value!!)
|
||||
* This check should be left in even when the default Flightgear files are known
|
||||
* to be OK since it checks for mis-indexing of voice files by 3rd party developers.
|
||||
*/
|
||||
if((word.offset + word.length) > rawDataSize) {
|
||||
SG_LOG(SG_ATC, SG_ALERT, "ERROR - mismatch between ATC .wav and .vce file in ATCVoice.cxx\n");
|
||||
SG_LOG(SG_ATC, SG_ALERT, "Offset + length: " << word.offset + word.length
|
||||
<< " exceeds rawdata size: " << rawDataSize << endl);
|
||||
|
||||
*len = 0;
|
||||
return 0;
|
||||
}
|
||||
sound.insert(sound.end(), rawSoundData + word.offset, rawSoundData + word.offset + word.length);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for no tokens found else slScheduler can be crashed
|
||||
*len = sound.size();
|
||||
if (*len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* data = (char*)malloc(*len);
|
||||
if (data == 0) {
|
||||
SG_LOG(SG_ATC, SG_ALERT, "ERROR - could not allocate " << *len << " bytes of memory for ATIS sound\n");
|
||||
*len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// randomize start position
|
||||
unsigned int offsetIn = (unsigned int)(*len * sg_random());
|
||||
if (offsetIn > 0 && offsetIn < *len) {
|
||||
copy(sound.begin() + offsetIn, sound.end(), data);
|
||||
copy(sound.begin(), sound.begin() + offsetIn, data + *len - offsetIn);
|
||||
} else {
|
||||
copy(sound.begin(), sound.end(), data);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
// FGATCVoice.hxx - a class to encapsulate an ATC voice
|
||||
//
|
||||
// Written by David Luff, started November 2002.
|
||||
//
|
||||
// Copyright (C) 2002 David C Luff - david.luff@nottingham.ac.uk
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#ifndef _FG_ATC_VOICE
|
||||
#define _FG_ATC_VOICE
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class SGSoundSample;
|
||||
class SGPath;
|
||||
|
||||
struct WordData {
|
||||
unsigned int offset; // Offset of beginning of word sample into raw sound sample
|
||||
unsigned int length; // Byte length of word sample
|
||||
};
|
||||
|
||||
typedef std::map < std::string, WordData > atc_word_map_type;
|
||||
typedef atc_word_map_type::iterator atc_word_map_iterator;
|
||||
typedef atc_word_map_type::const_iterator atc_word_map_const_iterator;
|
||||
|
||||
class FGATCVoice {
|
||||
|
||||
public:
|
||||
|
||||
FGATCVoice();
|
||||
~FGATCVoice();
|
||||
|
||||
// Load the two voice files - one containing the raw sound data (.wav) and one containing the word positions (.vce).
|
||||
// Return true if successful.
|
||||
bool LoadVoice(const std::string& voicename);
|
||||
|
||||
// Given a desired message, return a pointer to the data buffer and write the buffer length into len.
|
||||
// Sets len to something other than 0 if the returned buffer is valid.
|
||||
void* WriteMessage(const std::string& message, size_t *len);
|
||||
|
||||
private:
|
||||
bool AppendVoiceFile(const SGPath& basepath, const std::string& file);
|
||||
bool ParseVoiceIndex(const SGPath& basepath, const std::string& file, size_t globaloffset);
|
||||
|
||||
// the sound and word position data
|
||||
char* rawSoundData;
|
||||
size_t rawDataSize;
|
||||
SGSharedPtr<SGSoundSample> SoundData;
|
||||
|
||||
// A map of words vs. byte position and length in rawSoundData
|
||||
atc_word_map_type wordMap;
|
||||
|
||||
};
|
||||
|
||||
#endif // _FG_ATC_VOICE
|
|
@ -1,271 +0,0 @@
|
|||
// ATCutils.cxx - Utility functions for the ATC / AI system
|
||||
//
|
||||
// Written by David Luff, started March 2002.
|
||||
//
|
||||
// Copyright (C) 2002 David C Luff - david.luff@nottingham.ac.uk
|
||||
//
|
||||
// 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 <sstream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <Airports/runways.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
|
||||
#include "ATCutils.hxx"
|
||||
#include "ATCProjection.hxx"
|
||||
|
||||
static const string nums[10] = {"zero", "one", "two", "three", "four",
|
||||
"five", "six", "seven", "eight", "niner"};
|
||||
|
||||
static const string letters[LTRS] = {
|
||||
"alpha", "bravo", "charlie", "delta", "echo",
|
||||
"foxtrot", "golf", "hotel", "india", "juliet",
|
||||
"kilo", "lima", "mike", "november", "oscar",
|
||||
"papa", "quebec", "romeo", "sierra", "tango",
|
||||
"uniform", "victor", "whiskey", "xray", "yankee", "zulu"
|
||||
};
|
||||
|
||||
// Convert any number to spoken digits
|
||||
string ConvertNumToSpokenDigits(const string &n) {
|
||||
//cout << "n = " << n << endl;
|
||||
static const string pt = "decimal";
|
||||
string str = "";
|
||||
|
||||
for(unsigned int i=0; i<n.length(); ++i) {
|
||||
//cout << "n.substr(" << i << ",1 = " << n.substr(i,1) << endl;
|
||||
if(n.substr(i,1) == " ") {
|
||||
// do nothing
|
||||
} else if(n.substr(i,1) == ".") {
|
||||
str += pt;
|
||||
} else {
|
||||
str += nums[atoi((n.substr(i,1)).c_str())];
|
||||
}
|
||||
if(i != (n.length()-1)) { // ie. don't add a space at the end.
|
||||
str += " ";
|
||||
}
|
||||
}
|
||||
return(str);
|
||||
}
|
||||
|
||||
// Convert an integer to a decimal numeral string
|
||||
string decimalNumeral(const int& n) {
|
||||
std::ostringstream buf;
|
||||
buf << n;
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// Convert an integer to spoken digits
|
||||
string ConvertNumToSpokenDigits(const int& n) {
|
||||
return ConvertNumToSpokenDigits(decimalNumeral(n));
|
||||
}
|
||||
|
||||
|
||||
// Assumes we get a string of digits optionally appended with L, R or C
|
||||
// eg 1 7L 29R 36
|
||||
// Anything else is not guaranteed to be handled correctly!
|
||||
string ConvertRwyNumToSpokenString(const string &rwy) {
|
||||
string rslt;
|
||||
for (size_t ii = 0; ii < rwy.length(); ii++){
|
||||
if (rslt.length()) rslt += " ";
|
||||
string ch = rwy.substr(ii,1);
|
||||
if (isdigit(ch[0])) rslt += ConvertNumToSpokenDigits(atoi(ch.c_str()));
|
||||
else if (ch == "R") rslt += "right";
|
||||
else if (ch == "C") rslt += "center";
|
||||
else if (ch == "L") rslt += "left";
|
||||
else {
|
||||
rslt += GetPhoneticLetter(ch[0]);
|
||||
SG_LOG(SG_ATC, SG_WARN, "WARNING: Unknown suffix '" << ch
|
||||
<< "' in runway " << rwy << " in ConvertRwyNumToSpokenString(...)");
|
||||
}
|
||||
}
|
||||
return rslt;
|
||||
}
|
||||
|
||||
|
||||
// Return the phonetic letter of a letter represented as an integer 1->26
|
||||
string GetPhoneticLetter(const int i) {
|
||||
return(letters[i % LTRS]);
|
||||
}
|
||||
|
||||
// Return the phonetic letter of a character in the range a-z or A-Z.
|
||||
// Currently always returns prefixed by lowercase.
|
||||
string GetPhoneticLetter(const char c) {
|
||||
return GetPhoneticLetter(int(tolower(c) - 'a'));
|
||||
}
|
||||
|
||||
// Get the compass direction associated with a heading in degrees
|
||||
// Currently returns 8 direction resolution (N, NE, E etc...)
|
||||
// Might be modified in future to return 4, 8 or 16 resolution but defaulting to 8.
|
||||
string GetCompassDirection(double h) {
|
||||
while(h < 0.0) h += 360.0;
|
||||
while(h > 360.0) h -= 360.0;
|
||||
if(h < 22.5 || h > 337.5) {
|
||||
return("North");
|
||||
} else if(h < 67.5) {
|
||||
return("North-East");
|
||||
} else if(h < 112.5) {
|
||||
return("East");
|
||||
} else if(h < 157.5) {
|
||||
return("South-East");
|
||||
} else if(h < 202.5) {
|
||||
return("South");
|
||||
} else if(h < 247.5) {
|
||||
return("South-West");
|
||||
} else if(h < 292.5) {
|
||||
return("West");
|
||||
} else {
|
||||
return("North-West");
|
||||
}
|
||||
}
|
||||
|
||||
//================================================================================================================
|
||||
|
||||
// Given two positions (lat & lon in degrees), get the HORIZONTAL separation (in meters)
|
||||
double dclGetHorizontalSeparation(const SGGeod& pos1, const SGGeod& pos2) {
|
||||
double x; //East-West separation
|
||||
double y; //North-South separation
|
||||
double z; //Horizontal separation - z = sqrt(x^2 + y^2)
|
||||
|
||||
double lat1 = pos1.getLatitudeRad();
|
||||
double lon1 = pos1.getLongitudeRad();
|
||||
double lat2 = pos2.getLatitudeRad();
|
||||
double lon2 = pos2.getLongitudeRad();
|
||||
|
||||
y = sin(fabs(lat1 - lat2)) * SG_EQUATORIAL_RADIUS_M;
|
||||
x = sin(fabs(lon1 - lon2)) * SG_EQUATORIAL_RADIUS_M * (cos((lat1 + lat2) / 2.0));
|
||||
z = sqrt(x*x + y*y);
|
||||
|
||||
return(z);
|
||||
}
|
||||
|
||||
// Given a point and a line, get the HORIZONTAL shortest distance from the point to a point on the line.
|
||||
// Expects to be fed orthogonal co-ordinates, NOT lat & lon !
|
||||
// The units of the separation will be those of the input.
|
||||
double dclGetLinePointSeparation(double px, double py, double x1, double y1, double x2, double y2) {
|
||||
double vecx = x2-x1;
|
||||
double vecy = y2-y1;
|
||||
double magline = sqrt(vecx*vecx + vecy*vecy);
|
||||
double u = ((px-x1)*(x2-x1) + (py-y1)*(y2-y1)) / (magline * magline);
|
||||
double x0 = x1 + u*(x2-x1);
|
||||
double y0 = y1 + u*(y2-y1);
|
||||
vecx = px - x0;
|
||||
vecy = py - y0;
|
||||
double d = sqrt(vecx*vecx + vecy*vecy);
|
||||
if(d < 0) {
|
||||
d *= -1;
|
||||
}
|
||||
return(d);
|
||||
}
|
||||
|
||||
// Given a position (lat/lon/elev), heading and vertical angle (degrees), and distance (meters), calculate the new position.
|
||||
// This function assumes the world is spherical. If geodetic accuracy is required use the functions is sg_geodesy instead!
|
||||
// Assumes that the ground is not hit!!! Expects heading and angle in degrees, distance in meters.
|
||||
SGGeod dclUpdatePosition(const SGGeod& pos, double heading, double angle, double distance) {
|
||||
// FIXME: use SGGeodesy instead ...
|
||||
|
||||
//cout << setprecision(10) << pos.lon() << ' ' << pos.lat() << '\n';
|
||||
heading *= DCL_DEGREES_TO_RADIANS;
|
||||
angle *= DCL_DEGREES_TO_RADIANS;
|
||||
double lat = pos.getLatitudeRad();
|
||||
double lon = pos.getLongitudeRad();
|
||||
double elev = pos.getElevationM();
|
||||
//cout << setprecision(10) << lon*DCL_RADIANS_TO_DEGREES << ' ' << lat*DCL_RADIANS_TO_DEGREES << '\n';
|
||||
|
||||
double horiz_dist = distance * cos(angle);
|
||||
double vert_dist = distance * sin(angle);
|
||||
|
||||
double north_dist = horiz_dist * cos(heading);
|
||||
double east_dist = horiz_dist * sin(heading);
|
||||
|
||||
//cout << distance << ' ' << horiz_dist << ' ' << vert_dist << ' ' << north_dist << ' ' << east_dist << '\n';
|
||||
|
||||
double delta_lat = asin(north_dist / (double)SG_EQUATORIAL_RADIUS_M);
|
||||
double delta_lon = asin(east_dist / (double)SG_EQUATORIAL_RADIUS_M) * (1.0 / cos(lat)); // I suppose really we should use the average of the original and new lat but we'll assume that this will be good enough.
|
||||
//cout << delta_lon*DCL_RADIANS_TO_DEGREES << ' ' << delta_lat*DCL_RADIANS_TO_DEGREES << '\n';
|
||||
lat += delta_lat;
|
||||
lon += delta_lon;
|
||||
elev += vert_dist;
|
||||
//cout << setprecision(10) << lon*DCL_RADIANS_TO_DEGREES << ' ' << lat*DCL_RADIANS_TO_DEGREES << '\n';
|
||||
|
||||
//cout << setprecision(15) << DCL_DEGREES_TO_RADIANS * DCL_RADIANS_TO_DEGREES << '\n';
|
||||
|
||||
return SGGeod::fromRadM(lon, lat, elev);
|
||||
}
|
||||
|
||||
// Get a heading in degrees from one lat/lon to another.
|
||||
// This function assumes the world is spherical. If geodetic accuracy is required use the functions is sg_geodesy instead!
|
||||
// Warning - at the moment we are not checking for identical points - currently it returns 0 in this instance.
|
||||
double GetHeadingFromTo(const SGGeod& A, const SGGeod& B) {
|
||||
double latA = A.getLatitudeRad();
|
||||
double lonA = A.getLongitudeRad();
|
||||
double latB = B.getLatitudeRad();
|
||||
double lonB = B.getLongitudeRad();
|
||||
double xdist = sin(lonB - lonA) * (double)SG_EQUATORIAL_RADIUS_M * cos((latA+latB)/2.0);
|
||||
double ydist = sin(latB - latA) * (double)SG_EQUATORIAL_RADIUS_M;
|
||||
double heading = atan2(xdist, ydist) * DCL_RADIANS_TO_DEGREES;
|
||||
return heading < 0.0 ? heading + 360 : heading;
|
||||
}
|
||||
|
||||
// Given a heading (in degrees), bound it from 0 -> 360
|
||||
void dclBoundHeading(double &hdg) {
|
||||
while(hdg < 0.0) {
|
||||
hdg += 360.0;
|
||||
}
|
||||
while(hdg > 360.0) {
|
||||
hdg -= 360.0;
|
||||
}
|
||||
}
|
||||
|
||||
// smallest difference between two angles in degrees
|
||||
// difference is negative if a1 > a2 and positive if a2 > a1
|
||||
double GetAngleDiff_deg( const double &a1, const double &a2) {
|
||||
|
||||
double a3 = a2 - a1;
|
||||
while (a3 < 180.0) a3 += 360.0;
|
||||
while (a3 > 180.0) a3 -= 360.0;
|
||||
|
||||
return a3;
|
||||
}
|
||||
|
||||
// Runway stuff
|
||||
// Given (lon/lat/elev) and an FGRunway struct, determine if the point lies on the runway
|
||||
bool OnRunway(const SGGeod& pt, const FGRunwayBase* rwy) {
|
||||
FGATCAlignedProjection ortho;
|
||||
SGGeod centre = SGGeod::fromDegM(rwy->longitude(), rwy->latitude(), 0); // We don't need the elev
|
||||
ortho.Init(centre, rwy->headingDeg());
|
||||
|
||||
SGVec3d xyc = ortho.ConvertToLocal(centre);
|
||||
SGVec3d xyp = ortho.ConvertToLocal(pt);
|
||||
|
||||
//cout << "Length offset = " << fabs(xyp.y() - xyc.y()) << '\n';
|
||||
//cout << "Width offset = " << fabs(xyp.x() - xyc.x()) << '\n';
|
||||
|
||||
if((fabs(xyp.y() - xyc.y()) < ((rwy->lengthFt()/2.0) + 5.0))
|
||||
&& (fabs(xyp.x() - xyc.x()) < (rwy->widthFt()/2.0))) {
|
||||
return(true);
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
// ATCutils.hxx - Utility functions for the ATC / AI subsytem
|
||||
//
|
||||
// Written by David Luff, started March 2002.
|
||||
//
|
||||
// Copyright (C) 2002 David C Luff - david.luff@nottingham.ac.uk
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#include <Airports/airport.hxx>
|
||||
#include <Airports/runways.hxx>
|
||||
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
using std::string;
|
||||
|
||||
// These are defined here because I had a problem with SG_DEGREES_TO_RADIANS
|
||||
#define DCL_PI 3.1415926535f
|
||||
#define DCL_DEGREES_TO_RADIANS (DCL_PI/180.0)
|
||||
#define DCL_RADIANS_TO_DEGREES (180.0/DCL_PI)
|
||||
|
||||
/*******************************
|
||||
*
|
||||
* Communication functions
|
||||
*
|
||||
********************************/
|
||||
|
||||
// Convert any number to spoken digits
|
||||
string ConvertNumToSpokenDigits(const string &n);
|
||||
|
||||
// Convert an integer to spoken digits
|
||||
string ConvertNumToSpokenDigits(const int& n);
|
||||
string decimalNumeral(const int& n);
|
||||
|
||||
// Convert rwy number string to a spoken-style string
|
||||
// eg "15L" to "one five left"
|
||||
// Assumes we get a string of digits optionally appended with R, L, or C
|
||||
// eg 1 7L 29R 36
|
||||
string ConvertRwyNumToSpokenString(const string &s);
|
||||
|
||||
const int LTRS(26);
|
||||
// Return the phonetic letter of a letter represented as an integer 0..25
|
||||
string GetPhoneticLetter(const int i);
|
||||
|
||||
// Return the phonetic letter of a character in the range a-z or A-Z.
|
||||
// Currently always returns prefixed by lowercase.
|
||||
string GetPhoneticLetter(char c);
|
||||
|
||||
// Get the compass direction associated with a heading in degrees
|
||||
// Currently returns 8 direction resolution (N, NE, E etc...)
|
||||
// Might be modified in future to return 4, 8 or 16 resolution but defaulting to 8.
|
||||
string GetCompassDirection(double h);
|
||||
|
||||
/*******************************
|
||||
*
|
||||
* Positional functions
|
||||
*
|
||||
********************************/
|
||||
|
||||
// Given two positions (lat & lon in degrees), get the HORIZONTAL separation (in meters)
|
||||
double dclGetHorizontalSeparation(const SGGeod& pos1, const SGGeod& pos2);
|
||||
|
||||
// Given a point and a line, get the HORIZONTAL shortest distance from the point to a point on the line.
|
||||
// Expects to be fed orthogonal co-ordinates, NOT lat & lon !
|
||||
double dclGetLinePointSeparation(double px, double py, double x1, double y1, double x2, double y2);
|
||||
|
||||
// Given a position (lat/lon/elev), heading, vertical angle, and distance, calculate the new position.
|
||||
// Assumes that the ground is not hit!!! Expects heading and angle in degrees, distance in meters.
|
||||
SGGeod dclUpdatePosition(const SGGeod& pos, double heading, double angle, double distance);
|
||||
|
||||
// Get a heading from one lat/lon to another (in degrees)
|
||||
double GetHeadingFromTo(const SGGeod& A, const SGGeod& B);
|
||||
|
||||
// Given a heading (in degrees), bound it from 0 -> 360
|
||||
void dclBoundHeading(double &hdg);
|
||||
|
||||
// smallest difference between two angles in degrees
|
||||
// difference is negative if a1 > a2 and positive if a2 > a1
|
||||
double GetAngleDiff_deg( const double &a1, const double &a2);
|
||||
|
||||
/****************
|
||||
*
|
||||
* Runways
|
||||
*
|
||||
****************/
|
||||
|
||||
// Given (lon/lat/elev) and an FGRunway struct, determine if the point lies on the runway
|
||||
bool OnRunway(const SGGeod& pt, const FGRunwayBase* rwy);
|
||||
|
|
@ -1,147 +0,0 @@
|
|||
// ATISmgr.cxx - Implementation of FGATISMgr - a global Flightgear ATIS manager.
|
||||
//
|
||||
// Written by David Luff, started February 2002.
|
||||
//
|
||||
// Copyright (C) 2002 David C Luff - david.luff@nottingham.ac.uk
|
||||
// Copyright (C) 2012 Thorsten Brehm
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#include "ATISmgr.hxx"
|
||||
#include "atis.hxx"
|
||||
|
||||
FGATISMgr::FGATISMgr() :
|
||||
_currentUnit(0),
|
||||
_maxCommRadios(4)
|
||||
#ifdef ENABLE_AUDIO_SUPPORT
|
||||
,useVoice(true),
|
||||
voice(0)
|
||||
#endif
|
||||
{
|
||||
globals->set_ATIS_mgr(this);
|
||||
}
|
||||
|
||||
FGATISMgr::~FGATISMgr()
|
||||
{
|
||||
globals->set_ATIS_mgr(NULL);
|
||||
|
||||
for (unsigned int unit = 0;unit < radios.size(); ++unit) {
|
||||
delete radios[unit];
|
||||
}
|
||||
|
||||
#ifdef ENABLE_AUDIO_SUPPORT
|
||||
delete voice;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FGATISMgr::init()
|
||||
{
|
||||
for (unsigned int unit = 0;unit < _maxCommRadios; ++unit)
|
||||
{
|
||||
if (unit < _maxCommRadios/2)
|
||||
radios.push_back(new FGATIS("comm", unit));
|
||||
else
|
||||
radios.push_back(new FGATIS("nav", unit - _maxCommRadios/2));
|
||||
}
|
||||
}
|
||||
|
||||
void FGATISMgr::reinit()
|
||||
{
|
||||
#ifdef ENABLE_AUDIO_SUPPORT
|
||||
if ((voiceName != "")&&
|
||||
(voiceName != fgGetString("/sim/atis/voice", "default")))
|
||||
{
|
||||
voiceName = fgGetString("/sim/atis/voice", "default");
|
||||
delete voice;
|
||||
voice = NULL;
|
||||
useVoice = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FGATISMgr::update(double dt)
|
||||
{
|
||||
// update only runs every now and then (1-2 per second)
|
||||
if (++_currentUnit >= _maxCommRadios)
|
||||
_currentUnit = 0;
|
||||
|
||||
FGATC* commRadio = radios[_currentUnit];
|
||||
if (commRadio)
|
||||
commRadio->update(dt * _maxCommRadios);
|
||||
}
|
||||
|
||||
// Return a pointer to an appropriate voice for a given type of ATC
|
||||
// creating the voice if necessary - i.e. make sure exactly one copy
|
||||
// of every voice in use exists in memory.
|
||||
//
|
||||
// TODO - in the future this will get more complex and dole out country/airport
|
||||
// specific voices, and possible make sure that the same voice doesn't get used
|
||||
// at different airports in quick succession if a large enough selection are available.
|
||||
FGATCVoice* FGATISMgr::GetVoicePointer(const atc_type& type)
|
||||
{
|
||||
#ifdef ENABLE_AUDIO_SUPPORT
|
||||
// TODO - implement me better - maintain a list of loaded voices and other voices!!
|
||||
if(useVoice)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case ATIS: case AWOS:
|
||||
// Delayed loading for all available voices, needed because the
|
||||
// sound manager might not be initialized (at all) at this point.
|
||||
// For now we'll do one hard-wired one
|
||||
|
||||
/* I've loaded the voice even if /sim/sound/pause is true
|
||||
* since I know no way of forcing load of the voice if the user
|
||||
* subsequently switches /sim/sound/audible to true.
|
||||
* (which is the right thing to do -- CLO) :-)
|
||||
*/
|
||||
if (!voice && fgGetBool("/sim/sound/working")) {
|
||||
voice = new FGATCVoice;
|
||||
voiceName = fgGetString("/sim/atis/voice", "default");
|
||||
try {
|
||||
useVoice = voice->LoadVoice(voiceName);
|
||||
} catch ( sg_io_exception & e) {
|
||||
SG_LOG(SG_ATC, SG_ALERT, "Unable to load voice '" << voiceName << "': "
|
||||
<< e.getFormattedMessage().c_str());
|
||||
useVoice = false;
|
||||
delete voice;
|
||||
voice = 0;
|
||||
}
|
||||
}
|
||||
return voice;
|
||||
case TOWER:
|
||||
return NULL;
|
||||
case APPROACH:
|
||||
return NULL;
|
||||
case GROUND:
|
||||
return NULL;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
// ATISmgr.hxx - definition of FGATISMgr
|
||||
// - a global management class for FlightGear generated ATIS
|
||||
//
|
||||
// Written by David Luff, started February 2002.
|
||||
//
|
||||
// Copyright (C) 2002 David C Luff - david.luff@nottingham.ac.uk
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#ifndef _FG_ATISMGR_HXX
|
||||
#define _FG_ATISMGR_HXX
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
#include "ATC.hxx"
|
||||
|
||||
class FGATISMgr : public SGSubsystem
|
||||
{
|
||||
private:
|
||||
// A vector containing all comm radios
|
||||
std::vector<FGATC*> radios;
|
||||
|
||||
unsigned int _currentUnit;
|
||||
unsigned int _maxCommRadios;
|
||||
|
||||
#ifdef ENABLE_AUDIO_SUPPORT
|
||||
bool useVoice; // Flag - true if we are using voice
|
||||
FGATCVoice* voice;
|
||||
std::string voiceName; // currently loaded voice name
|
||||
#endif
|
||||
|
||||
public:
|
||||
FGATISMgr();
|
||||
~FGATISMgr();
|
||||
|
||||
void init();
|
||||
void reinit();
|
||||
void update(double dt);
|
||||
|
||||
// Return a pointer to an appropriate voice for a given type of ATC
|
||||
// creating the voice if necessary - i.e. make sure exactly one copy
|
||||
// of every voice in use exists in memory.
|
||||
//
|
||||
// TODO - in the future this will get more complex and dole out country/airport
|
||||
// specific voices, and possible make sure that the same voice doesn't get used
|
||||
// at different airports in quick succession if a large enough selection are available.
|
||||
FGATCVoice* GetVoicePointer(const atc_type& type);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif // _FG_ATISMGR_HXX
|
|
@ -1,11 +0,0 @@
|
|||
include(FlightGearComponent)
|
||||
|
||||
set(SOURCES
|
||||
ATCProjection.cxx
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
ATCProjection.hxx
|
||||
)
|
||||
|
||||
flightgear_component(ATCDCL "${SOURCES}" "${HEADERS}")
|
1030
src/ATCDCL/atis.cxx
1030
src/ATCDCL/atis.cxx
File diff suppressed because it is too large
Load diff
|
@ -1,153 +0,0 @@
|
|||
// atis.hxx -- ATIS class
|
||||
//
|
||||
// Written by David Luff, started October 2001.
|
||||
// Based on nav.hxx by Curtis Olson, started April 2000.
|
||||
//
|
||||
// Copyright (C) 2001 David C. Luff - david.luff@nottingham.ac.uk
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#ifndef _FG_ATIS_HXX
|
||||
#define _FG_ATIS_HXX
|
||||
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/timing/sg_time.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
#include "ATC.hxx"
|
||||
|
||||
class FGAirport;
|
||||
|
||||
typedef std::map<std::string,std::string> MSS;
|
||||
|
||||
class FGATIS : public FGATC {
|
||||
|
||||
std::string _name;
|
||||
int _num;
|
||||
|
||||
SGPropertyNode_ptr _root;
|
||||
SGPropertyNode_ptr _volume;
|
||||
SGPropertyNode_ptr _serviceable;
|
||||
SGPropertyNode_ptr _operable;
|
||||
SGPropertyNode_ptr _electrical;
|
||||
SGPropertyNode_ptr _freq;
|
||||
SGPropertyNode_ptr _atis;
|
||||
|
||||
// Pointers to current users position
|
||||
SGPropertyNode_ptr _lon_node;
|
||||
SGPropertyNode_ptr _lat_node;
|
||||
SGPropertyNode_ptr _elev_node;
|
||||
|
||||
SGPropertyChangeCallback<FGATIS> _cb_attention;
|
||||
|
||||
// The actual ATIS transmission
|
||||
// This is generated from the prevailing conditions when required.
|
||||
// This is the version with markup, suitable for voice synthesis:
|
||||
std::string transmission;
|
||||
|
||||
// Same as above, but in a form more readable as text.
|
||||
std::string transmission_readable;
|
||||
|
||||
// for failure modeling
|
||||
std::string trans_ident; // transmitted ident
|
||||
double old_volume;
|
||||
bool atis_failed; // atis failed?
|
||||
time_t msg_time; // for moderating error messages
|
||||
time_t cur_time;
|
||||
int msg_OK;
|
||||
bool _attention;
|
||||
bool _check_transmission;
|
||||
|
||||
bool _prev_display; // Previous value of _display flag
|
||||
MSS _remap; // abbreviations to be expanded
|
||||
|
||||
// internal periodic station search timer
|
||||
double _time_before_search_sec;
|
||||
int _last_frequency;
|
||||
|
||||
// temporary buffer for string conversions
|
||||
char buf[100];
|
||||
|
||||
// data for the current ATIS report
|
||||
struct
|
||||
{
|
||||
std::string phonetic_seq_string;
|
||||
bool US_CA;
|
||||
bool cavok;
|
||||
bool concise;
|
||||
bool ils;
|
||||
int temp;
|
||||
int dewpoint;
|
||||
double psl;
|
||||
double qnh;
|
||||
double rain_norm, snow_norm;
|
||||
int notam;
|
||||
std::string hours,mins;
|
||||
} _report;
|
||||
|
||||
public:
|
||||
|
||||
FGATIS(const std::string& name, int num);
|
||||
|
||||
void init();
|
||||
void reinit();
|
||||
|
||||
void attend(SGPropertyNode* node);
|
||||
|
||||
//run the ATIS instance
|
||||
void update(double dt);
|
||||
|
||||
//inline void set_type(const atc_type tp) {type = tp;}
|
||||
inline const std::string& get_trans_ident() { return trans_ident; }
|
||||
|
||||
protected:
|
||||
virtual FGATCVoice* GetVoicePointer();
|
||||
|
||||
private:
|
||||
|
||||
void createReport (const FGAirport* apt);
|
||||
|
||||
/** generate the ATIS transmission text */
|
||||
bool genTransmission (const int regen, bool forceUpdate);
|
||||
void genTimeInfo (void);
|
||||
void genFacilityInfo (void);
|
||||
void genPrecipitationInfo(void);
|
||||
bool genVisibilityInfo (std::string& vis_info);
|
||||
bool genCloudInfo (std::string& cloud_info);
|
||||
void genWindInfo (void);
|
||||
void genTemperatureInfo (void);
|
||||
void genTransitionLevel (const FGAirport* apt);
|
||||
void genPressureInfo (void);
|
||||
void genRunwayInfo (const FGAirport* apt);
|
||||
void genWarnings (int position);
|
||||
|
||||
void addTemperature (int Temp);
|
||||
|
||||
// Put the text into the property tree
|
||||
// (and in debug mode, print it on the console):
|
||||
void treeOut(int msgOK);
|
||||
|
||||
// Search the specified radio for stations on the same frequency and in range.
|
||||
bool search(double dt);
|
||||
|
||||
friend std::istream& operator>> ( std::istream&, FGATIS& );
|
||||
};
|
||||
|
||||
typedef int (FGATIS::*int_getter)() const;
|
||||
|
||||
#endif // _FG_ATIS_HXX
|
|
@ -1,123 +0,0 @@
|
|||
#ifndef _FG_ATIS_LEXICON_HXX
|
||||
#define _FG_ATIS_LEXICON_HXX
|
||||
|
||||
#include <string>
|
||||
|
||||
// NOTE: This file serves as a database.
|
||||
// It is read by some utility programs that synthesize
|
||||
// the library of spoken words.
|
||||
|
||||
#define Q(word) const std::string word(#word);
|
||||
|
||||
namespace lex {
|
||||
Q(Airport)
|
||||
Q(Airfield)
|
||||
Q(Airbase)
|
||||
Q(Junior)
|
||||
Q(Celsius)
|
||||
Q(Wind)
|
||||
Q(zulu)
|
||||
Q(zulu_weather)
|
||||
Q(Automated_weather_observation)
|
||||
Q(Weather)
|
||||
Q(airport_information)
|
||||
Q(International)
|
||||
Q(Regional)
|
||||
Q(County)
|
||||
Q(Municipal)
|
||||
Q(Memorial)
|
||||
Q(Field)
|
||||
Q(Air_Force_Base)
|
||||
Q(Army_Air_Field)
|
||||
Q(Marine_Corps_Air_Station)
|
||||
Q(light_and_variable)
|
||||
Q(at)
|
||||
Q(thousand)
|
||||
Q(hundred)
|
||||
Q(zero)
|
||||
Q(Temperature)
|
||||
Q(clear)
|
||||
Q(isolated)
|
||||
Q(few)
|
||||
Q(scattered)
|
||||
Q(broken)
|
||||
Q(overcast)
|
||||
Q(thin)
|
||||
Q(Sky_condition)
|
||||
Q(Sky)
|
||||
Q(Clouds)
|
||||
Q(Ceiling)
|
||||
Q(minus)
|
||||
Q(Dewpoint)
|
||||
Q(Visibility)
|
||||
Q(less_than_one_quarter)
|
||||
Q(one_quarter)
|
||||
Q(one_half)
|
||||
Q(three_quarters)
|
||||
Q(one_and_one_half)
|
||||
Q(Altimeter)
|
||||
Q(QNH)
|
||||
Q(Landing_and_departing_runway)
|
||||
Q(Advise_on_initial_contact_you_have_information)
|
||||
Q(This_is)
|
||||
Q(information)
|
||||
Q(millibars)
|
||||
Q(hectopascal)
|
||||
Q(inches)
|
||||
Q(I_L_S)
|
||||
Q(visual)
|
||||
Q(cav_ok)
|
||||
Q(clouds_and_visibility_OK)
|
||||
Q(out)
|
||||
Q(equals)
|
||||
Q(Expect_I_L_S_approach)
|
||||
Q(Expect_visual_approach)
|
||||
Q(Transition_level)
|
||||
Q(No_sig)
|
||||
Q(Time)
|
||||
Q(kelometers)
|
||||
Q(Attention)
|
||||
Q(flock_of_birds)
|
||||
Q(bird_activity)
|
||||
Q(in_the_vicinity_of_the_airport)
|
||||
Q(short_time__I_LS_interference_possible_by_taxiing_aircraft)
|
||||
Q(reed_back_all_runway_hold_instructions)
|
||||
Q(glider_operation_in_sector)
|
||||
Q(airport)
|
||||
Q(runway_wet)
|
||||
Q(runway_in_use)
|
||||
Q(arrivals)
|
||||
Q(runway)
|
||||
Q(runways)
|
||||
Q(expect)
|
||||
Q(approach)
|
||||
Q(departures)
|
||||
Q(wet)
|
||||
Q(ice)
|
||||
Q(closed)
|
||||
Q(light)
|
||||
Q(moderate)
|
||||
Q(heavy)
|
||||
Q(rain)
|
||||
Q(drizzle)
|
||||
Q(snow)
|
||||
Q(fog)
|
||||
Q(plus)
|
||||
Q(hours)
|
||||
Q(variable)
|
||||
Q(from)
|
||||
Q(Or)
|
||||
Q(And)
|
||||
Q(to)
|
||||
Q(maximum)
|
||||
Q(between)
|
||||
Q(degrees)
|
||||
Q(or_more)
|
||||
Q(left)
|
||||
Q(right)
|
||||
Q(center)
|
||||
Q(knots)
|
||||
}
|
||||
|
||||
#undef Q
|
||||
#endif // _FG_ATIS_LEXICON_HXX
|
|
@ -1,20 +0,0 @@
|
|||
// NOTE: This file serves as a database.
|
||||
// It is read by some utility programs that synthesize
|
||||
// the library of spoken words.
|
||||
|
||||
REMAP(Intl, International)
|
||||
REMAP(Rgnl, Regional)
|
||||
REMAP(Co, County)
|
||||
REMAP(Muni, Municipal)
|
||||
REMAP(Mem, Memorial)
|
||||
REMAP(Meml, Memorial)
|
||||
REMAP(Apt, Airport)
|
||||
REMAP(Arpt, Airport)
|
||||
REMAP(Fld, Field)
|
||||
REMAP(AFLD, Airfield)
|
||||
REMAP(AFB, Air_Force_Base)
|
||||
REMAP(AB, Airbase)
|
||||
REMAP(AAF, Army_Air_Field)
|
||||
REMAP(MCAS, Marine_Corps_Air_Station)
|
||||
REMAP(JR, Junior)
|
||||
REMAP(GKI, NIL)
|
|
@ -7,7 +7,6 @@ foreach( mylibfolder
|
|||
Airports
|
||||
Aircraft
|
||||
ATC
|
||||
ATCDCL
|
||||
Canvas
|
||||
Radio
|
||||
Autopilot
|
||||
|
|
|
@ -44,8 +44,6 @@
|
|||
#include "kln89_symbols.hxx"
|
||||
#include <iostream>
|
||||
|
||||
#include <ATCDCL/ATCProjection.hxx>
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <simgear/structure/commands.hxx>
|
||||
#include <Airports/airport.hxx>
|
||||
|
@ -763,7 +761,7 @@ void KLN89::DrawMap(bool draw_avs) {
|
|||
double mapScaleMeters = _mapScale * (_mapScaleUnits == 0 ? SG_NM_TO_METER : 1000);
|
||||
|
||||
// TODO - use an aligned projection when either DTK or TK up!
|
||||
FGATCAlignedProjection mapProj(SGGeod::fromRad(_gpsLon, _gpsLat), _mapHeading);
|
||||
AlignedProjection mapProj(SGGeod::fromRad(_gpsLon, _gpsLat), _mapHeading);
|
||||
double meter_per_pix = (_mapOrientation == 0 ? mapScaleMeters / 20.0f : mapScaleMeters / 29.0f);
|
||||
// SGGeod bottomLeft = mapProj.ConvertFromLocal(SGVec3d(gps_max(-57.0 * meter_per_pix, -50000), gps_max((_mapOrientation == 0 ? -20.0 * meter_per_pix : -11.0 * meter_per_pix), -25000), 0.0));
|
||||
// SGGeod topRight = mapProj.ConvertFromLocal(SGVec3d(gps_min(54.0 * meter_per_pix, 50000), gps_min((_mapOrientation == 0 ? 20.0 * meter_per_pix : 29.0 * meter_per_pix), 25000), 0.0));
|
||||
|
|
|
@ -1564,3 +1564,54 @@ double DCLGPS::CalcCrossTrackDeviation(const GPSWaypoint& wp1, const GPSWaypoint
|
|||
* sin(GetGreatCircleCourse(wp1.lat, wp1.lon, _gpsLat, _gpsLon) - GetGreatCircleCourse(wp1.lat, wp1.lon, wp2.lat, wp2.lon)));
|
||||
return(Rad2Nm(xtd));
|
||||
}
|
||||
|
||||
AlignedProjection::AlignedProjection()
|
||||
{
|
||||
SGGeod g; // ctor initializes to zero
|
||||
Init( g, 0.0 );
|
||||
}
|
||||
|
||||
AlignedProjection::AlignedProjection(const SGGeod& centre, double heading)
|
||||
{
|
||||
Init( centre, heading );
|
||||
}
|
||||
|
||||
AlignedProjection::~AlignedProjection() {
|
||||
}
|
||||
|
||||
void AlignedProjection::Init(const SGGeod& centre, double heading) {
|
||||
_origin = centre;
|
||||
_theta = heading * SG_DEGREES_TO_RADIANS;
|
||||
_correction_factor = cos(_origin.getLatitudeRad());
|
||||
}
|
||||
|
||||
SGVec3d AlignedProjection::ConvertToLocal(const SGGeod& pt) {
|
||||
// convert from lat/lon to orthogonal
|
||||
double delta_lat = pt.getLatitudeRad() - _origin.getLatitudeRad();
|
||||
double delta_lon = pt.getLongitudeRad() - _origin.getLongitudeRad();
|
||||
double y = sin(delta_lat) * SG_EQUATORIAL_RADIUS_M;
|
||||
double x = sin(delta_lon) * SG_EQUATORIAL_RADIUS_M * _correction_factor;
|
||||
|
||||
// Align
|
||||
if(_theta != 0.0) {
|
||||
double xbar = x;
|
||||
x = x*cos(_theta) - y*sin(_theta);
|
||||
y = (xbar*sin(_theta)) + (y*cos(_theta));
|
||||
}
|
||||
|
||||
return SGVec3d(x, y, pt.getElevationM());
|
||||
}
|
||||
|
||||
SGGeod AlignedProjection::ConvertFromLocal(const SGVec3d& pt) {
|
||||
// de-align
|
||||
double thi = _theta * -1.0;
|
||||
double x = pt.x()*cos(thi) - pt.y()*sin(thi);
|
||||
double y = (pt.x()*sin(thi)) + (pt.y()*cos(thi));
|
||||
|
||||
// convert from orthogonal to lat/lon
|
||||
double delta_lat = asin(y / SG_EQUATORIAL_RADIUS_M);
|
||||
double delta_lon = asin(x / SG_EQUATORIAL_RADIUS_M) / _correction_factor;
|
||||
|
||||
return SGGeod::fromRadM(_origin.getLongitudeRad()+delta_lon, _origin.getLatitudeRad()+delta_lat, pt.z());
|
||||
}
|
||||
|
||||
|
|
|
@ -166,6 +166,30 @@ private:
|
|||
int _min;
|
||||
};
|
||||
|
||||
// AlignedProjection - a class to project an area local to a runway onto an orthogonal co-ordinate system
|
||||
// with the origin at the threshold and the runway aligned with the y axis.
|
||||
class AlignedProjection {
|
||||
|
||||
public:
|
||||
AlignedProjection();
|
||||
AlignedProjection(const SGGeod& centre, double heading);
|
||||
~AlignedProjection();
|
||||
|
||||
void Init(const SGGeod& centre, double heading);
|
||||
|
||||
// Convert a lat/lon co-ordinate (degrees) to the local projection (meters)
|
||||
SGVec3d ConvertToLocal(const SGGeod& pt);
|
||||
|
||||
// Convert a local projection co-ordinate (meters) to lat/lon (degrees)
|
||||
SGGeod ConvertFromLocal(const SGVec3d& pt);
|
||||
|
||||
private:
|
||||
SGGeod _origin; // lat/lon of local area origin (the threshold)
|
||||
double _theta; // the rotation angle for alignment in radians
|
||||
double _correction_factor; // Reduction in surface distance per degree of longitude due to latitude. Saves having to do a cos() every call.
|
||||
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
// TODO - merge generic GPS functions instead and split out KLN specific stuff.
|
||||
|
|
Loading…
Add table
Reference in a new issue