From d2c000699f3d20d22fd4d6173b060a23554214a2 Mon Sep 17 00:00:00 2001 From: Torsten Dreyer Date: Wed, 30 Apr 2014 10:22:51 +0200 Subject: [PATCH] Cleanup of ATCDCL - move FGATCAlignedProjection class as AlignedProjection to dclgps, the only place where it's currently used - remove now obsolete files in ATCDCL --- src/ATCDCL/ATC.cxx | 413 ----------- src/ATCDCL/ATC.hxx | 226 ------ src/ATCDCL/ATCProjection.cxx | 79 -- src/ATCDCL/ATCProjection.hxx | 50 -- src/ATCDCL/ATCVoice.cxx | 297 -------- src/ATCDCL/ATCVoice.hxx | 71 -- src/ATCDCL/ATCutils.cxx | 271 ------- src/ATCDCL/ATCutils.hxx | 100 --- src/ATCDCL/ATISmgr.cxx | 147 ---- src/ATCDCL/ATISmgr.hxx | 66 -- src/ATCDCL/CMakeLists.txt | 11 - src/ATCDCL/atis.cxx | 1030 --------------------------- src/ATCDCL/atis.hxx | 153 ---- src/ATCDCL/atis_lexicon.hxx | 123 ---- src/ATCDCL/atis_remap.hxx | 20 - src/CMakeLists.txt | 1 - src/Instrumentation/KLN89/kln89.cxx | 4 +- src/Instrumentation/dclgps.cxx | 51 ++ src/Instrumentation/dclgps.hxx | 24 + 19 files changed, 76 insertions(+), 3061 deletions(-) delete mode 100644 src/ATCDCL/ATC.cxx delete mode 100644 src/ATCDCL/ATC.hxx delete mode 100644 src/ATCDCL/ATCProjection.cxx delete mode 100644 src/ATCDCL/ATCProjection.hxx delete mode 100644 src/ATCDCL/ATCVoice.cxx delete mode 100644 src/ATCDCL/ATCVoice.hxx delete mode 100644 src/ATCDCL/ATCutils.cxx delete mode 100644 src/ATCDCL/ATCutils.hxx delete mode 100644 src/ATCDCL/ATISmgr.cxx delete mode 100644 src/ATCDCL/ATISmgr.hxx delete mode 100644 src/ATCDCL/CMakeLists.txt delete mode 100644 src/ATCDCL/atis.cxx delete mode 100644 src/ATCDCL/atis.hxx delete mode 100644 src/ATCDCL/atis_lexicon.hxx delete mode 100644 src/ATCDCL/atis_remap.hxx diff --git a/src/ATCDCL/ATC.cxx b/src/ATCDCL/ATC.cxx deleted file mode 100644 index 223661974..000000000 --- a/src/ATCDCL/ATC.cxx +++ /dev/null @@ -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 -#endif - -#include "ATC.hxx" - -#include - -#include -#include -#include - -#include
-#include
-#include -#include - -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 diff --git a/src/ATCDCL/ATC.hxx b/src/ATCDCL/ATC.hxx deleted file mode 100644 index 6a0918a66..000000000 --- a/src/ATCDCL/ATC.hxx +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 _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 diff --git a/src/ATCDCL/ATCProjection.cxx b/src/ATCDCL/ATCProjection.cxx deleted file mode 100644 index ecc08cc80..000000000 --- a/src/ATCDCL/ATCProjection.cxx +++ /dev/null @@ -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 -#endif - -#include "ATCProjection.hxx" -#include -#include - -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()); -} diff --git a/src/ATCDCL/ATCProjection.hxx b/src/ATCDCL/ATCProjection.hxx deleted file mode 100644 index 94dfb92b9..000000000 --- a/src/ATCDCL/ATCProjection.hxx +++ /dev/null @@ -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 - -// 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 diff --git a/src/ATCDCL/ATCVoice.cxx b/src/ATCDCL/ATCVoice.cxx deleted file mode 100644 index 71f15e587..000000000 --- a/src/ATCDCL/ATCVoice.cxx +++ /dev/null @@ -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 -#endif - -#include "ATCVoice.hxx" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include
- -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; iget_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 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; -} diff --git a/src/ATCDCL/ATCVoice.hxx b/src/ATCDCL/ATCVoice.hxx deleted file mode 100644 index 55fe68a7c..000000000 --- a/src/ATCDCL/ATCVoice.hxx +++ /dev/null @@ -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 -#include - -#include -#include - -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 SoundData; - - // A map of words vs. byte position and length in rawSoundData - atc_word_map_type wordMap; - -}; - -#endif // _FG_ATC_VOICE diff --git a/src/ATCDCL/ATCutils.cxx b/src/ATCDCL/ATCutils.cxx deleted file mode 100644 index 296040172..000000000 --- a/src/ATCDCL/ATCutils.cxx +++ /dev/null @@ -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 -#endif - -#include -#include - -#include -#include -#include - -#include -#include
- -#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; i26 -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); -} - diff --git a/src/ATCDCL/ATCutils.hxx b/src/ATCDCL/ATCutils.hxx deleted file mode 100644 index 478ba7e9d..000000000 --- a/src/ATCDCL/ATCutils.hxx +++ /dev/null @@ -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 -#include - -#include -#include -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); - diff --git a/src/ATCDCL/ATISmgr.cxx b/src/ATCDCL/ATISmgr.cxx deleted file mode 100644 index abb7490a4..000000000 --- a/src/ATCDCL/ATISmgr.cxx +++ /dev/null @@ -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 -#endif - -#include -#include -#include - -#include
- -#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; -} diff --git a/src/ATCDCL/ATISmgr.hxx b/src/ATCDCL/ATISmgr.hxx deleted file mode 100644 index 29aaef472..000000000 --- a/src/ATCDCL/ATISmgr.hxx +++ /dev/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 - -#include - -#include "ATC.hxx" - -class FGATISMgr : public SGSubsystem -{ -private: - // A vector containing all comm radios - std::vector 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 diff --git a/src/ATCDCL/CMakeLists.txt b/src/ATCDCL/CMakeLists.txt deleted file mode 100644 index 98d253a97..000000000 --- a/src/ATCDCL/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -include(FlightGearComponent) - -set(SOURCES - ATCProjection.cxx - ) - -set(HEADERS - ATCProjection.hxx - ) - -flightgear_component(ATCDCL "${SOURCES}" "${HEADERS}") diff --git a/src/ATCDCL/atis.cxx b/src/ATCDCL/atis.cxx deleted file mode 100644 index 3cdfa806f..000000000 --- a/src/ATCDCL/atis.cxx +++ /dev/null @@ -1,1030 +0,0 @@ -// atis.cxx - routines to generate the ATIS info string -// This is the implementation of the FGATIS class -// -// Written by David Luff, started October 2001. -// Extended by Thorsten Brehm, October 2012. -// -// 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. - -///// -///// TODO: _Cumulative_ sky coverage. -///// TODO: wind _gust_ -///// TODO: more-sensible encoding of voice samples -///// u-law? outright synthesis? -///// - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "atis.hxx" -#include "atis_lexicon.hxx" - -#include -#include -#include -#include - -#include // atoi() -#include // sprintf -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include
-#include
-#include -#include - -#include -#include - -#include "ATCutils.hxx" -#include "ATISmgr.hxx" - -using std::string; -using std::map; -using std::cout; -using std::cout; -using boost::ref; -using boost::tie; -using flightgear::CommStation; - -FGATIS::FGATIS(const std::string& name, int num) : - _name(name), - _num(num), - _cb_attention(this, &FGATIS::attend, fgGetNode("/environment/attention", true)), - transmission(""), - trans_ident(""), - old_volume(0), - atis_failed(false), - msg_time(0), - cur_time(0), - msg_OK(0), - _attention(false), - _check_transmission(true), - _prev_display(0), - _time_before_search_sec(0), - _last_frequency(0) -{ - _root = fgGetNode("/instrumentation", true)->getNode(_name, num, true); - _volume = _root->getNode("volume",true); - _serviceable = _root->getNode("serviceable",true); - - if (name != "nav") - { - // only drive "operable" for non-nav instruments (nav radio drives this separately) - _operable = _root->getNode("operable",true); - _operable->setBoolValue(false); - } - - _electrical = fgGetNode("/systems/electrical/outputs",true)->getNode(_name,num, true); - _atis = _root->getNode("atis",true); - _freq = _root->getNode("frequencies/selected-mhz",true); - - // current position - _lon_node = fgGetNode("/position/longitude-deg", true); - _lat_node = fgGetNode("/position/latitude-deg", true); - _elev_node = fgGetNode("/position/altitude-ft", true); - - // backward compatibility: some properties may not exist (but default to "ON") - if (!_serviceable->hasValue()) - _serviceable->setBoolValue(true); - if (!_electrical->hasValue()) - _electrical->setDoubleValue(24.0); - -/////////////// -// FIXME: This would be more flexible and more extensible -// if the mappings were taken from an XML file, not hard-coded ... -// ... although having it in a .hxx file is better than nothing. -// -// Load the remap list from the .hxx file: - using namespace lex; - - # define NIL "" - # define REMAP(from,to) _remap[#from] = to; - # include "atis_remap.hxx" - # undef REMAP - # undef NIL - - #ifdef ATIS_TEST - SG_LOG(SG_ATC, SG_ALERT, "ATIS initialized"); - #endif - - _report.psl = 0; -} - -// Hint: -// http://localhost:5400/environment/attention?value=1&submit=update - -FGATCVoice* FGATIS::GetVoicePointer() -{ - FGATISMgr* pAtisMgr = globals->get_ATIS_mgr(); - if (!pAtisMgr) - { - SG_LOG(SG_ATC, SG_ALERT, "ERROR! No ATIS manager! Oops..."); - return NULL; - } - - return pAtisMgr->GetVoicePointer(ATIS); -} - -void FGATIS::init() -{ -// Nothing to see here. Move along. -} - -void FGATIS::reinit() -{ - _time_before_search_sec = 0; - _check_transmission = true; -} - -void -FGATIS::attend(SGPropertyNode* node) -{ - if (node->getBoolValue()) - _attention = true; -#ifdef ATMO_TEST - int flag = fgGetInt("/sim/logging/atmo"); - if (flag) { - FGAltimeter().check_model(); - FGAltimeter().dump_stack(); - } -#endif -} - - -// Main update function - checks whether we are displaying or not the correct message. -void FGATIS::update(double dt) { - cur_time = globals->get_time_params()->get_cur_time(); - msg_OK = (msg_time < cur_time); - -#ifdef ATIS_TEST - if (msg_OK || _display != _prev_display) { - cout << "ATIS Update: " << _display << " " << _prev_display - << " len: " << transmission.length() - << " oldvol: " << old_volume - << " dt: " << dt << endl; - msg_time = cur_time; - } -#endif - - double volume = 0; - if ((_electrical->getDoubleValue() > 8) && _serviceable->getBoolValue()) - { - // radio is switched on and OK - if (_operable.valid()) - _operable->setBoolValue(true); - - _check_transmission |= search(dt); - - if (_display) - { - volume = _volume->getDoubleValue(); - } - } - else - { - // radio is OFF - if (_operable.valid()) - _operable->setBoolValue(false); - _time_before_search_sec = 0; - } - - if (volume > 0.05) - { - bool changed = false; - if (_check_transmission) - { - _check_transmission = false; - // Check if we need to update the message - // - basically every hour and if the weather changes significantly at the station - // If !_prev_display, the radio had been detuned for a while and our - // "transmission" variable was lost when we were de-instantiated. - if (genTransmission(!_prev_display, _attention)) - { - // update output property - treeOut(msg_OK); - changed = true; - } - } - - if (changed || volume != old_volume) { - // audio output enabled - Render(transmission, volume, _name, true); - old_volume = volume; - } - _prev_display = _display; - } else { - // silence - NoRender(_name); - _prev_display = false; - } - _attention = false; - - FGATC::update(dt); -} - -// Replace all occurrences of a given word. -// Words in the original string must be separated by hyphens (not spaces). -// We check for the word as given, and for the all-caps version thereof. -string replace_word(const string _orig, const string _www, const string _nnn){ -// The following are so we can match words at the beginning -// and end of the string. - string orig = "-" + _orig + "-"; - string www = "-" + _www + "-"; - string nnn = "-" + _nnn + "-"; - - size_t where(0); - for ( ; (where = orig.find(www, where)) != string::npos ; ) { - orig.replace(where, www.length(), nnn); - where += nnn.length(); - } - - www = simgear::strutils::uppercase(www); - for ( ; (where = orig.find(www, where)) != string::npos ; ) { - orig.replace(where, www.length(), nnn); - where += nnn.length(); - } - where = orig.length(); - return orig.substr(1, where-2); -} - -// Normally the interval is 1 hour, -// but you can shorten it for testing. -const int minute(60); // measured in seconds -#ifdef ATIS_TEST - const int ATIS_interval(2*minute); -#else - const int ATIS_interval(60*minute); -#endif - -// FIXME: This is heuristic. It gets the right answer for -// more than 90% of the world's airports, which is a lot -// better than nothing ... but it's not 100%. -// We know "most" of the world uses millibars, -// but the US, Canada and *some* other places use inches of mercury, -// but (a) we have not implemented a reliable method of -// ascertaining which airports are in the US, let alone -// (b) ascertaining which other places use inches. -// -bool Apt_US_CA(const string id) -{ - // Assume all IDs have length 3 or 4. - // No counterexamples have been seen. - if (id.length() == 4) { - if (id.substr(0,1) == "K") return true; - if (id.substr(0,2) == "CY") return true; - } - for (string::const_iterator ptr = id.begin(); ptr != id.end(); ptr++) { - if (isdigit(*ptr)) return true; - } - return false; -} - -// voice spacers -static const string BRK = ".\n"; -static const string PAUSE = " / "; - -/** Generate the actual broadcast ATIS transmission. -* 'regen' triggers a regeneration of the /current/ transmission. -* 'forceUpdate' generates a new transmission, with a new sequence. -* Returns 1 if we actually generated something. -*/ -bool FGATIS::genTransmission(const int regen, bool forceUpdate) -{ - using namespace lex; - - // ATIS updated hourly, AWOS updated more frequently - int interval = _type == ATIS ? ATIS_interval : 2*minute; - - // check if pressure has changed significantly and we need to update ATIS - double Psl = fgGetDouble("/environment/pressure-sea-level-inhg"); - if (fabs(Psl-_report.psl) >= 0.15) - forceUpdate = true; - - FGAirport* apt = FGAirport::findByIdent(ident); - int sequence = apt->getDynamics()->updateAtisSequence(interval, forceUpdate); - if (!regen && sequence > LTRS) { - //xx if (msg_OK) cout << "ATIS: no change: " << sequence << endl; - //xx msg_time = cur_time; - return false; // no change since last time - } - - _report.psl = Psl; - transmission = ""; - - // collect data and create report - createReport(apt); - - // add facility name - genFacilityInfo(); - - if (_type == ATIS) { - // ATIS phraseology starts with "... airport information" - transmission += airport_information + " "; - } else { - // AWOS - transmission += Automated_weather_observation + " "; - } - - string phonetic_seq_string = GetPhoneticLetter(sequence); // Add the sequence letter - transmission += phonetic_seq_string + BRK; - - genTimeInfo(); - - // some warnings may appear at the beginning - genWarnings(-1); - - if (_type == ATIS) // as opposed to AWOS - genRunwayInfo(apt); - - // some warnings may appear after runway info - genWarnings(0); - - // transition level - genTransitionLevel(apt); - - // weather - if (!_report.concise) - transmission += Weather + BRK; - - genWindInfo(); - - // clouds and visibility - { - string vis_info, cloud_info; - bool v = genVisibilityInfo(vis_info); - bool c = genCloudInfo(cloud_info); - _report.cavok = !(v || c); - if (!_report.cavok) - { - // there is some visibility or cloud restriction - transmission += vis_info + cloud_info; - } - else - { - // Abbreviation CAVOK vs full "clouds and visibility..." does not really depend on - // US vs rest of the world, it really seems to depend on the airport. Just use - // it as a heuristic. - if ((_report.US_CA)||(_report.concise)) - transmission += cav_ok + BRK; - else - transmission += clouds_and_visibility_OK + BRK; - } - } - - // precipitation - genPrecipitationInfo(); - - // temperature - genTemperatureInfo(); - - // pressure - genPressureInfo(); - - // TODO check whether "no significant change" applies - somehow... - transmission += No_sig + BRK; // sounds better with festival than "nosig" - - // some warnings may appear at the very end - genWarnings(1); - - if ((!_report.concise)|| _report.US_CA) - transmission += Advise_on_initial_contact_you_have_information; - else - transmission += information; - transmission += " " + phonetic_seq_string + "."; - - if (!_report.US_CA) - { - // non-US ATIS ends with "out!" - transmission += " " + out; - } - - // Pause in between two messages must be 3-5 seconds - transmission += " / / / / / / / / "; - - ///////////////////////////////////////////////////////// - // post-processing - ///////////////////////////////////////////////////////// - transmission_readable = transmission; - - // Take the previous readable string and munge it to - // be relatively-more acceptable to the primitive tts system. - // Note that : ; and . are among the token-delimiters recognized - // by the tts system. - for (size_t where;;) { - where = transmission.find_first_of(":."); - if (where == string::npos) break; - transmission.replace(where, 1, PAUSE); - } - - return true; -} - -/** Collect (most of) the data and create report. - */ -void FGATIS::createReport(const FGAirport* apt) -{ - // check country - _report.US_CA = Apt_US_CA(ident); - - // switch to enable brief ATIS message (really depends on the airport) - _report.concise = fgGetBool("/sim/atis/concise-reports", false); - - _report.ils = false; - - // time information - string time_str = fgGetString("sim/time/gmt-string"); - // Warning - this is fragile if the time string format changes - _report.hours = time_str.substr(0,2).c_str(); - _report.mins = time_str.substr(3,2).c_str(); - - // pressure/temperature - { - double press, temp; - double Tsl = fgGetDouble("/environment/temperature-sea-level-degc"); - tie(press, temp) = PT_vs_hpt(_geod.getElevationM(), _report.psl*atmodel::inHg, Tsl + atmodel::freezing); - #if 0 - SG_LOG(SG_ATC, SG_ALERT, "Field P: " << press << " T: " << temp); - SG_LOG(SG_ATC, SG_ALERT, "based on elev " << elev - << " Psl: " << Psl - << " Tsl: " << Tsl); - #endif - _report.qnh = FGAtmo().QNH(_geod.getElevationM(), press); - _report.temp = int(SGMiscd::round(FGAtmo().fake_T_vs_a_us(_geod.getElevationFt(), Tsl))); - } - - // dew point - double dpsl = fgGetDouble("/environment/dewpoint-sea-level-degc"); - _report.dewpoint = int(SGMiscd::round(FGAtmo().fake_dp_vs_a_us(dpsl, _geod.getElevationFt()))); - - // precipitation - _report.rain_norm = fgGetDouble("environment/rain-norm"); - _report.snow_norm = fgGetDouble("environment/snow-norm"); - - // NOTAMs - _report.notam = 0; - if (fgGetBool("/sim/atis/random-notams", true)) - { - _report.notam = fgGetInt("/sim/atis/notam-id", 0); // fixed NOTAM for testing/debugging only - if (!_report.notam) - { - // select pseudo-random NOTAM (changes every hour, differs for each airport) - char cksum = 0; - string name = apt->getName(); - for(string::iterator p = name.begin(); p != name.end(); p++) - { - cksum += *p; - } - cksum ^= atoi(_report.hours.c_str()); - _report.notam = cksum % 12; // 12 intentionally higher than number of available NOTAMs, so they don't appear too often - // debugging - //fgSetInt("/sim/atis/selected-notam", _report.notam); - } - } -} - -void FGATIS::genPrecipitationInfo(void) -{ - using namespace lex; - - double rain_norm = _report.rain_norm; - double snow_norm = _report.snow_norm; - - // report rain or snow - which ever is worse - if (rain_norm > 0.7) - transmission += heavy + " " + rain + BRK; - else - if (snow_norm > 0.7) - transmission += heavy + " " + snow + BRK; - else - if (rain_norm > 0.4) - transmission += moderate + " " + rain + BRK; - else - if (snow_norm > 0.4) - transmission += moderate + " " + snow + BRK; - else - if (rain_norm > 0.2) - transmission += light + " " + rain + BRK; - else - if (snow_norm > 0.05) - transmission += light + " " + snow + BRK; - else - if (rain_norm > 0.05) - transmission += light + " " + drizzle + BRK; -} - -void FGATIS::genTimeInfo(void) -{ - using namespace lex; - - if (!_report.concise) - transmission += Time + " "; - - // speak each digit separately: - transmission += ConvertNumToSpokenDigits(_report.hours + _report.mins); - transmission += " " + zulu + BRK; -} - -bool FGATIS::genVisibilityInfo(string& vis_info) -{ - using namespace lex; - - double visibility = fgGetDouble("/environment/config/boundary/entry[0]/visibility-m"); - bool IsMax = false; - bool USE_KM = !_report.US_CA; - - vis_info += Visibility + ": "; - if (USE_KM) - { - visibility /= 1000.0; // convert to statute miles - // integer kilometers - if (visibility >= 9.5) - { - visibility = 10; - IsMax = true; - } - snprintf(buf, sizeof(buf), "%i", int(.5 + visibility)); - // "kelometers" instead of "kilometers" since the festival language generator doesn't get it right otherwise - vis_info += ConvertNumToSpokenDigits(buf) + " " + kelometers; - } - else - { - visibility /= atmodel::sm; // convert to statute miles - if (visibility < 0.25) { - vis_info += less_than_one_quarter; - } else if (visibility < 0.5) { - vis_info += one_quarter; - } else if (visibility < 0.75) { - vis_info += one_half; - } else if (visibility < 1.0) { - vis_info += three_quarters; - } else if (visibility >= 1.5 && visibility < 2.0) { - vis_info += one_and_one_half; - } else { - // integer miles - if (visibility > 9.5) - { - visibility = 10; - IsMax = true; - } - snprintf(buf, sizeof(buf), "%i", int(.5 + visibility)); - vis_info += ConvertNumToSpokenDigits(buf); - } - } - if (IsMax) - { - vis_info += " " + or_more; - } - vis_info += BRK; - return !IsMax; -} - -void FGATIS::addTemperature(int Temp) -{ - if (Temp < 0) - transmission += lex::minus + " "; - else - if (Temp > 0) - { - transmission += lex::plus + " "; - } - snprintf(buf, sizeof(buf), "%i", abs(Temp)); - transmission += ConvertNumToSpokenDigits(buf); - if (_report.US_CA) - transmission += " " + lex::Celsius; -} - -void FGATIS::genTemperatureInfo() -{ - // temperature - transmission += lex::Temperature + ": "; - addTemperature(_report.temp); - - // dewpoint - transmission += BRK + lex::Dewpoint + ": "; - addTemperature(_report.dewpoint); - - transmission += BRK; -} - -bool FGATIS::genCloudInfo(string& cloud_info) -{ - using namespace lex; - - bool did_some = false; - bool did_ceiling = false; - - for (int layer = 0; layer <= 4; layer++) { - snprintf(buf, sizeof(buf), "/environment/clouds/layer[%i]/coverage", layer); - string coverage = fgGetString(buf); - if (coverage == clear) - continue; - snprintf(buf, sizeof(buf), "/environment/clouds/layer[%i]/thickness-ft", layer); - if (fgGetDouble(buf) == 0) - continue; - snprintf(buf, sizeof(buf), "/environment/clouds/layer[%i]/elevation-ft", layer); - double ceiling = int(fgGetDouble(buf) - _geod.getElevationFt()); - if (ceiling > 12000) - continue; - - // BEWARE: At the present time, the environment system has no - // way (so far as I know) to represent a "thin broken" or - // "thin overcast" layer. If/when such things are implemented - // in the environment system, code will have to be written here - // to handle them. - - // First, do the prefix if any: - if (coverage == scattered || coverage == few) { - if (!did_some) { - if (_report.concise) - cloud_info += Clouds + ": "; - else - cloud_info += Sky_condition + ": "; - did_some = true; - } - } else /* must be a ceiling */ if (!did_ceiling) { - cloud_info += " " + Ceiling + ": "; - did_ceiling = true; - did_some = true; - } else { - cloud_info += " "; // no prefix required - } - int cig00 = int(SGMiscd::round(ceiling/100)); // hundreds of feet - if (cig00) { - int cig000 = cig00/10; - cig00 -= cig000*10; // just the hundreds digit - if (cig000) { - snprintf(buf, sizeof(buf), "%i", cig000); - cloud_info += ConvertNumToSpokenDigits(buf); - cloud_info += " " + thousand + " "; - } - if (cig00) { - snprintf(buf, sizeof(buf), "%i", cig00); - cloud_info += ConvertNumToSpokenDigits(buf); - cloud_info += " " + hundred + " "; - } - } else { - // Should this be "sky obscured?" - cloud_info += " " + zero + " "; // not "zero hundred" - } - cloud_info += coverage + BRK; - } - if (!did_some) - cloud_info += " " + Sky + " " + clear + BRK; - return did_some; -} - -void FGATIS::genFacilityInfo(void) -{ - if ((!_report.US_CA)&&(!_report.concise)) - { - // UK CAA radiotelephony manual indicates ATIS transmissions start - // with "This is ...", while US just starts with airport name. - transmission += lex::This_is + " "; - } - - // SG_LOG(SG_ATC, SG_ALERT, "ATIS: facility name: " << name); - - // Note that at this point, multi-word facility names - // will sometimes contain hyphens, not spaces. - std::vector name_words; - boost::split(name_words, name, boost::is_any_of(" -")); - - for( std::vector::const_iterator wordp = name_words.begin(); - wordp != name_words.end(); wordp++) { - string word(*wordp); - // Remap some abbreviations that occur in apt.dat, to - // make things nicer for the text-to-speech system: - for (MSS::const_iterator replace = _remap.begin(); - replace != _remap.end(); replace++) { - // Due to inconsistent capitalisation in the apt.dat file, we need - // to do a case-insensitive comparison here. - string tmp1 = word, tmp2 = replace->first; - boost::algorithm::to_lower(tmp1); - boost::algorithm::to_lower(tmp2); - if (tmp1 == tmp2) { - word = replace->second; - break; - } - } - transmission += word + " "; - } -} - -void FGATIS::genWindInfo(void) -{ - using namespace lex; - - transmission += Wind + ": "; - - double wind_speed = fgGetDouble("/environment/config/boundary/entry[0]/wind-speed-kt"); - double wind_dir = fgGetDouble("/environment/config/boundary/entry[0]/wind-from-heading-deg"); - while (wind_dir <= 0) wind_dir += 360; - // The following isn't as bad a kludge as it might seem. - // It combines the magvar at the /aircraft/ location with - // the wind direction in the environment/config array. - // But if the aircraft is close enough to the station to - // be receiving the ATIS signal, this should be a good-enough - // approximation. For more-distant aircraft, the wind_dir - // shouldn't be corrected anyway. - // The less-kludgy approach would be to use the magvar associated - // with the station, but that is not tabulated in the stationweather - // structure as it stands, and computing it would be expensive. - // Also note that as it stands, there is only one environment in - // the entire FG universe, so the aircraft environment is the same - // as the station environment anyway. - wind_dir -= fgGetDouble("/environment/magnetic-variation-deg"); // wind_dir now magnetic - if (wind_speed == 0) { - // Force west-facing rwys to be used in no-wind situations - // which is consistent with Flightgear's initial setup: - wind_dir = 270; - transmission += " " + light_and_variable; - } else { - // FIXME: get gust factor in somehow - snprintf(buf, sizeof(buf), "%03.0f", 5*SGMiscd::round(wind_dir/5)); - transmission += ConvertNumToSpokenDigits(buf); - if (!_report.concise) - transmission += " " + degrees; - transmission += " "; - snprintf(buf, sizeof(buf), "%1.0f", wind_speed); - transmission += at + " " + ConvertNumToSpokenDigits(buf); - if (!_report.concise) - transmission += " " + knots; - } - transmission += BRK; -} - -void FGATIS::genTransitionLevel(const FGAirport* apt) -{ - double hPa = _report.qnh/atmodel::mbar; - - /* Transition level is the flight level above which aircraft must use standard pressure and below - * which airport pressure settings must be used. - * Following definitions are taken from German ATIS: - * QNH <= 977 hPa: TRL 80 - * QNH <= 1013 hPa: TRL 70 - * QNH > 1013 hPa: TRL 60 - * (maybe differs slightly for other countries...) - */ - int tl = 60; - if (hPa <= 977) - tl = 80; - else - if (hPa <= 1013) - tl = 70; - - // add an offset to the transition level for high altitude airports (just guessing here, - // seems reasonable) - double elevationFt = apt->getElevation(); - int e = int(elevationFt / 1000.0); - if (e >= 3) - { - // TL steps in 10(00)ft - tl += (e-2)*10; - } - - snprintf(buf, sizeof(buf), "%02i", tl); - transmission += lex::Transition_level + ": " + ConvertNumToSpokenDigits(buf) + BRK; -} - -void FGATIS::genPressureInfo(void) -{ - using namespace lex; - - // hectopascal for most of the world (not US, not CA) - if(!_report.US_CA) { - double hPa = _report.qnh/atmodel::mbar; - transmission += QNH + ": "; - snprintf(buf, sizeof(buf), "%03.0f", _report.qnh / atmodel::mbar); - transmission += ConvertNumToSpokenDigits(buf); - // "hectopascal" replaced "millibars" in new ATIS standard since 2011 - if ((!_report.concise)||(hPa < 1000)) - transmission += " " + hectopascal; // "hectopascal" must be provided for values below 1000 (to avoid confusion with inHg) - - // Many (European) airports (with lots of US traffic?) provide both, hPa and inHg announcements. - // Europeans keep the "decimal" in inHg readings to make the distinction to hPa even more apparent. - // hPa/inHg separated by "equals" or "or" with some airports - if (_report.concise) - transmission += " " + equals + " "; - else - transmission += " " + Or + " "; - snprintf(buf, sizeof(buf), "%04.2f", _report.qnh / atmodel::inHg); - transmission += ConvertNumToSpokenDigits(buf); - if (!_report.concise) - transmission += " " + inches; - transmission += BRK; - } else { - // use inches of mercury for US/CA - transmission += Altimeter + ": "; - double asetting = _report.qnh / atmodel::inHg; - // shift two decimal places, US/CA airports omit the "decimal" in inHg settings - asetting *= 100.; - snprintf(buf, sizeof(buf), "%04.0f", asetting); - transmission += ConvertNumToSpokenDigits(buf); - } - - transmission += BRK; -} - -void FGATIS::genRunwayInfo(const FGAirport* apt) -{ - using namespace lex; - - if (!apt) - return; - - FGRunway* rwy = apt->getActiveRunwayForUsage(); - if (!rwy) - return; - - string rwy_no = rwy->ident(); - if(rwy_no != "NN") - { - FGNavRecord* ils = rwy->ILS(); - if (ils) - { - _report.ils = true; - transmission += Expect_I_L_S_approach + " "+ runway + " "+ConvertRwyNumToSpokenString(rwy_no) + BRK; - if (fgGetBool("/sim/atis/announce-ils-frequency", false)) - { - // this is handy - but really non-standard (so disabled by default) - snprintf(buf, sizeof(buf), "%5.2f", ils->get_freq()/100.0); - transmission += I_L_S + " " + ConvertNumToSpokenDigits(buf) + BRK; - } - } - else - { - transmission += Expect_visual_approach + " "+ runway + " "+ConvertRwyNumToSpokenString(rwy_no) + BRK; - } - - transmission += Landing_and_departing_runway + " "; - transmission += ConvertRwyNumToSpokenString(rwy_no) + BRK; - #ifdef ATIS_TEST - if (msg_OK) { - msg_time = cur_time; - cout << "In atis.cxx, r.rwy_no: " << rwy_no - << " wind_dir: " << wind_dir << endl; - } - #endif - } -} - -void FGATIS::genWarnings(int position) -{ - using namespace lex; - bool dayTime = (fgGetDouble("/sim/time/sun-angle-rad") < 1.57); - - if (position == -1) // warnings at beginning of ATIS - { - // bird related warnings at day-time only (birds are VFR-only! ;-) ) - if (dayTime) - { - if (_report.notam == 1) - transmission += Attention + ": " + flock_of_birds + " " + in_the_vicinity_of_the_airport + BRK; - else - if (_report.notam == 2) - transmission += Attention + ": " + bird_activity + " " + in_the_vicinity_of_the_airport + BRK; - } - } - else - if (position == 0) // warnings after runway messages - { - if ((_report.notam == 3)&&(_report.ils)) - { - // "__I_LS_" necessary to trick the language generator into pronouncing it properly - transmission += Attention + ": " + short_time__I_LS_interference_possible_by_taxiing_aircraft + BRK; - } - } - else - if (position == 1) // warnings at the end of the report - { - // "runway wet-wet-wet" warning in heavy rain - if (_report.rain_norm > 0.6) - { - // "wet" is repeated 3 times in ATIS warnings, since the word is difficult - // to understand over radio - but the message is important. - transmission += runway_wet + " " + wet + " " + wet + BRK; - } - - if (_report.notam == 4) - { - // intentional: "reed" instead of "read" since festival gets it wrong otherwise - transmission += reed_back_all_runway_hold_instructions + BRK; - } - else - if ((_report.notam == 5)&& _report.cavok && dayTime && - (_report.rain_norm == 0) && (_report.snow_norm == 0)) // ;-) - { - transmission += Attention + ": " + glider_operation_in_sector + BRK; - } - } -} - -// Put the transmission into the property tree. -// You can see it by pointing a web browser -// at the property tree. The second comm radio is: -// http://localhost:5400/instrumentation/comm[1] -// -// (Also, if in debug mode, dump it to the console.) -void FGATIS::treeOut(int msg_OK) -{ - _atis->setStringValue("
\n" + transmission_readable + "
\n"); - SG_LOG(SG_ATC, SG_DEBUG, "**** ATIS active on: " << _name << - "transmission: " << transmission_readable); -} - - -class RangeFilter : public CommStation::Filter -{ -public: - RangeFilter( const SGGeod & pos ) : - CommStation::Filter(), - _cart(SGVec3d::fromGeod(pos)), - _pos(pos) - { - } - - virtual bool pass(FGPositioned* aPos) const - { - flightgear::CommStation * stn = dynamic_cast(aPos); - if( NULL == stn ) - return false; - - // do the range check in cartesian space, since the distances are potentially - // large enough that the geodetic functions become unstable - // (eg, station on opposite side of the planet) - double rangeM = SGMiscd::max( stn->rangeNm(), 10.0 ) * SG_NM_TO_METER; - double d2 = distSqr( aPos->cart(), _cart); - - return d2 <= (rangeM * rangeM); - } - - virtual CommStation::Type minType() const - { - return CommStation::FREQ_ATIS; - } - - virtual CommStation::Type maxType() const - { - return CommStation::FREQ_AWOS; - } - -private: - SGVec3d _cart; - SGGeod _pos; -}; - -// Search for ATC stations by frequency -bool FGATIS::search(double dt) -{ - double frequency = _freq->getDoubleValue(); - - // Note: 122.375 must be rounded DOWN to 122370 - // in order to be consistent with apt.dat et cetera. - int freqKhz = 10 * static_cast(frequency * 100 + 0.25); - - // only search tuned frequencies when necessary - _time_before_search_sec -= dt; - - // throttle frequency searches - if ((freqKhz == _last_frequency)&&(_time_before_search_sec > 0)) - return false; - - _last_frequency = freqKhz; - _time_before_search_sec = 4.0; - - // Position of the Users Aircraft - SGGeod aircraftPos = SGGeod::fromDegFt(_lon_node->getDoubleValue(), - _lat_node->getDoubleValue(), - _elev_node->getDoubleValue()); - - RangeFilter rangeFilter(aircraftPos ); - CommStation* sta = CommStation::findByFreq(freqKhz, aircraftPos, &rangeFilter ); - SetStation(sta); - - return true; -} diff --git a/src/ATCDCL/atis.hxx b/src/ATCDCL/atis.hxx deleted file mode 100644 index 525001fa0..000000000 --- a/src/ATCDCL/atis.hxx +++ /dev/null @@ -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 -#include - -#include -#include -#include - -#include "ATC.hxx" - -class FGAirport; - -typedef std::map 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 _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 diff --git a/src/ATCDCL/atis_lexicon.hxx b/src/ATCDCL/atis_lexicon.hxx deleted file mode 100644 index ef6f02735..000000000 --- a/src/ATCDCL/atis_lexicon.hxx +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef _FG_ATIS_LEXICON_HXX -#define _FG_ATIS_LEXICON_HXX - -#include - -// 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 diff --git a/src/ATCDCL/atis_remap.hxx b/src/ATCDCL/atis_remap.hxx deleted file mode 100644 index 2497197b3..000000000 --- a/src/ATCDCL/atis_remap.hxx +++ /dev/null @@ -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) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b09b6a348..2c2d83e05 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,6 @@ foreach( mylibfolder Airports Aircraft ATC - ATCDCL Canvas Radio Autopilot diff --git a/src/Instrumentation/KLN89/kln89.cxx b/src/Instrumentation/KLN89/kln89.cxx index 858869fbd..c0c72773e 100644 --- a/src/Instrumentation/KLN89/kln89.cxx +++ b/src/Instrumentation/KLN89/kln89.cxx @@ -44,8 +44,6 @@ #include "kln89_symbols.hxx" #include -#include - #include
#include #include @@ -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)); diff --git a/src/Instrumentation/dclgps.cxx b/src/Instrumentation/dclgps.cxx index c0d8d3466..8444b5c51 100644 --- a/src/Instrumentation/dclgps.cxx +++ b/src/Instrumentation/dclgps.cxx @@ -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()); +} + diff --git a/src/Instrumentation/dclgps.hxx b/src/Instrumentation/dclgps.hxx index a49fafda8..4febcd64e 100644 --- a/src/Instrumentation/dclgps.hxx +++ b/src/Instrumentation/dclgps.hxx @@ -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.