From a4824656592279a6b22c754e0a01c28dea942253 Mon Sep 17 00:00:00 2001 From: "Curtis L. Olson" Date: Thu, 5 May 2011 14:13:18 -0500 Subject: [PATCH 1/6] Fix a problem with the YASim turbulence model. This change has been coordinated with and approved by Andy. The lattice(x,y) arguments were being "WRAP()'d" but the WRAP() function didn't make sense. Instead it was forcing the value to zero if it was greater than the wrap limit. This was creating large areas of constant values in the perlin noise maps which resulted in a "constant" turbulence vector over time -- which is just weird. Andy couldn't see any reason why the values should be wrapped and couldn't remember any reason why the WRAP() function was set up like it was. Andy wanted me to make sure and mention that he was INSANE when he wrote that code (but now he's sane ... err, mostly.) --- src/FDM/YASim/Turbulence.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/FDM/YASim/Turbulence.cpp b/src/FDM/YASim/Turbulence.cpp index 4a6183680..1b4048d1e 100644 --- a/src/FDM/YASim/Turbulence.cpp +++ b/src/FDM/YASim/Turbulence.cpp @@ -270,12 +270,10 @@ float Turbulence::iturb(unsigned int x, unsigned int y) xfrac = xfrac*xfrac*(3 - 2*xfrac); // ... as cubics yfrac = yfrac*yfrac*(3 - 2*yfrac); -#define WRAP(a) (a) >= wrapmax ? 0 : (a) - float p00 = lattice(WRAP(xl), WRAP(yl)); // lattice values - float p01 = lattice(WRAP(xl), WRAP(yl+1)); - float p10 = lattice(WRAP(xl+1), WRAP(yl)); - float p11 = lattice(WRAP(xl+1), WRAP(yl+1)); -#undef WRAP + float p00 = lattice(xl, yl); // lattice values + float p01 = lattice(xl, yl+1); + float p10 = lattice(xl+1, yl); + float p11 = lattice(xl+1, yl+1); float p0 = p00 * (1-yfrac) + p01 * yfrac; float p1 = p10 * (1-yfrac) + p11 * yfrac; From 3a11f8ae2843c1f3629f4168e5b10c3993c7bd3e Mon Sep 17 00:00:00 2001 From: Torsten Dreyer Date: Tue, 31 May 2011 20:39:32 +0200 Subject: [PATCH 2/6] remove inclusion of useless stdio.h --- src/Environment/gravity.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Environment/gravity.cxx b/src/Environment/gravity.cxx index cfeec7b04..cd32feeb4 100644 --- a/src/Environment/gravity.cxx +++ b/src/Environment/gravity.cxx @@ -42,7 +42,6 @@ Somigliana::Somigliana() Somigliana::~Somigliana() { } -#include double Somigliana::getGravity( const SGGeod & position ) const { From e61d37a7a39cf05ad19ca0cb5f16f41d5f8386bc Mon Sep 17 00:00:00 2001 From: Torsten Dreyer Date: Tue, 31 May 2011 20:58:22 +0200 Subject: [PATCH 3/6] Remove some unused code --- src/Environment/fgclouds.cxx | 2 +- src/Environment/metarproperties.cxx | 3 --- src/Environment/terrainsampler.cxx | 3 ++- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Environment/fgclouds.cxx b/src/Environment/fgclouds.cxx index 9b689d443..6cc4d49ef 100644 --- a/src/Environment/fgclouds.cxx +++ b/src/Environment/fgclouds.cxx @@ -161,7 +161,7 @@ double FGClouds::buildCloud(SGPropertyNode *cloud_def_root, SGPropertyNode *box_ y = w * (y - 0.5) + pos[1]; // E/W z = h * z + pos[2]; // Up/Down. pos[2] is the cloudbase - SGVec3f newpos = SGVec3f(x, y, z); + //SGVec3f newpos = SGVec3f(x, y, z); SGNewCloud cld = SGNewCloud(texture_root, cld_def); //layer->addCloud(newpos, cld.genCloud()); diff --git a/src/Environment/metarproperties.cxx b/src/Environment/metarproperties.cxx index 171d716af..11971f08c 100644 --- a/src/Environment/metarproperties.cxx +++ b/src/Environment/metarproperties.cxx @@ -301,9 +301,6 @@ void MetarProperties::set_metar( const char * metar ) } } - vector cv = m->getClouds(); - vector::const_iterator cloud, cloud_end = cv.end(); - { static const char * LAYER = "layer"; SGPropertyNode_ptr cloudsNode = _rootNode->getNode("clouds", true ); diff --git a/src/Environment/terrainsampler.cxx b/src/Environment/terrainsampler.cxx index 0d08af84e..293eb2c86 100644 --- a/src/Environment/terrainsampler.cxx +++ b/src/Environment/terrainsampler.cxx @@ -285,6 +285,7 @@ void AreaSampler::analyse() } } +/* double alt_low_min = 0.0; double n_max = 0.0; sum = 0.0; @@ -296,7 +297,7 @@ void AreaSampler::analyse() break; } } - +*/ _altLayered = 0.5 * (_altMin + _altOffset); #if 0 From 2bdaebb7d948de52b3e32b1d12224491c0361621 Mon Sep 17 00:00:00 2001 From: James Turner Date: Sun, 29 May 2011 23:43:40 +0100 Subject: [PATCH 4/6] Make basic route-manager commands be real SGCommands --- src/Autopilot/route_mgr.cxx | 183 +++++++++++++++++++++++++++++++++--- src/Autopilot/route_mgr.hxx | 27 +++--- 2 files changed, 183 insertions(+), 27 deletions(-) diff --git a/src/Autopilot/route_mgr.cxx b/src/Autopilot/route_mgr.cxx index 1b37fa256..044c624c8 100644 --- a/src/Autopilot/route_mgr.cxx +++ b/src/Autopilot/route_mgr.cxx @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -109,6 +110,151 @@ PropertyWatcher* createWatcher(T* obj, void (T::*m)()) return new MethodPropertyWatcher(obj, m); } +static bool commandLoadFlightPlan(const SGPropertyNode* arg) +{ + FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager"); + SGPath path(arg->getStringValue("path")); + return self->loadRoute(path); +} + +static bool commandSaveFlightPlan(const SGPropertyNode* arg) +{ + FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager"); + SGPath path(arg->getStringValue("path")); + return self->saveRoute(path); +} + +static bool commandActivateFlightPlan(const SGPropertyNode* arg) +{ + FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager"); + bool activate = arg->getBoolValue("activate", true); + if (activate) { + self->activate(); + } else { + + } + + return true; +} + +static bool commandClearFlightPlan(const SGPropertyNode*) +{ + FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager"); + self->clearRoute(); + return true; +} + +static bool commandSetActiveWaypt(const SGPropertyNode* arg) +{ + FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager"); + int index = arg->getIntValue("index"); + if ((index < 0) || (index >= self->numWaypts())) { + return false; + } + + self->jumpToIndex(index); + return true; +} + +static bool commandInsertWaypt(const SGPropertyNode* arg) +{ + FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager"); + int index = arg->getIntValue("index"); + std::string ident(arg->getStringValue("id")); + int alt = arg->getIntValue("altitude-ft", -999); + int ias = arg->getIntValue("speed-knots", -999); + + WayptRef wp; +// lat/lon may be supplied to narrow down navaid search, or to specify +// a raw waypoint + SGGeod pos; + if (arg->hasChild("longitude-deg")) { + pos = SGGeod::fromDeg(arg->getDoubleValue("longitude-deg"), + arg->getDoubleValue("latitude-deg")); + } + + if (arg->hasChild("navaid")) { + FGPositionedRef p = FGPositioned::findClosestWithIdent(arg->getStringValue("navaid"), pos); + + if (arg->hasChild("navaid", 1)) { + // intersection of two radials + FGPositionedRef p2 = FGPositioned::findClosestWithIdent(arg->getStringValue("navaid[1]"), pos); + if (!p2) { + SG_LOG( SG_AUTOPILOT, SG_INFO, "Unable to find FGPositioned with ident:" << arg->getStringValue("navaid[1]")); + return false; + } + + double r1 = arg->getDoubleValue("radial"), + r2 = arg->getDoubleValue("radial[1]"); + + SGGeod intersection; + bool ok = SGGeodesy::radialIntersection(p->geod(), r1, p2->geod(), r2, intersection); + if (!ok) { + SG_LOG(SG_AUTOPILOT, SG_INFO, "no valid intersection for:" << p->ident() + << "," << p2->ident()); + return false; + } + + std::string name = p->ident() + "-" + p2->ident(); + wp = new BasicWaypt(intersection, name, NULL); + } else if (arg->hasChild("offset-nm") && arg->hasChild("radial")) { + // offset radial from navaid + double radial = arg->getDoubleValue("radial"); + double distanceNm = arg->getDoubleValue("offset-nm"); + //radial += magvar->getDoubleValue(); // convert to true bearing + wp = new OffsetNavaidWaypoint(p, NULL, radial, distanceNm); + } else { + wp = new NavaidWaypoint(p, NULL); + } + } else if (arg->hasChild("airport")) { + const FGAirport* apt = fgFindAirportID(arg->getStringValue("airport")); + if (!apt) { + SG_LOG(SG_AUTOPILOT, SG_INFO, "no such airport" << arg->getStringValue("airport")); + return false; + } + + if (arg->hasChild("runway")) { + if (!apt->hasRunwayWithIdent(arg->getStringValue("runway"))) { + SG_LOG(SG_AUTOPILOT, SG_INFO, "No runway: " << arg->getStringValue("runway") << " at " << apt->ident()); + return false; + } + + FGRunway* runway = apt->getRunwayByIdent(arg->getStringValue("runway")); + wp = new RunwayWaypt(runway, NULL); + } else { + wp = new NavaidWaypoint((FGAirport*) apt, NULL); + } + } else if (arg->hasChild("text")) { + wp = self->waypointFromString(arg->getStringValue("text")); + } else if (!(pos == SGGeod())) { + // just a raw lat/lon + wp = new BasicWaypt(pos, ident, NULL); + } else { + return false; // failed to build waypoint + } + + if (alt >= 0) { + wp->setAltitude(alt, flightgear::RESTRICT_AT); + } + + if (ias > 0) { + wp->setSpeed(ias, flightgear::RESTRICT_AT); + } + + self->insertWayptAtIndex(wp, index); + return true; +} + +static bool commandDeleteWaypt(const SGPropertyNode* arg) +{ + FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager"); + int index = arg->getIntValue("index"); + self->removeWayptAtIndex(index); + return true; +} + +///////////////////////////////////////////////////////////////////////////// + FGRouteMgr::FGRouteMgr() : _currentIndex(0), input(fgGetNode( RM "input", true )), @@ -117,6 +263,14 @@ FGRouteMgr::FGRouteMgr() : listener = new InputListener(this); input->setStringValue(""); input->addChangeListener(listener); + + SGCommandMgr::instance()->addCommand("load-flightplan", commandLoadFlightPlan); + SGCommandMgr::instance()->addCommand("save-flightplan", commandSaveFlightPlan); + SGCommandMgr::instance()->addCommand("activate-flightplan", commandActivateFlightPlan); + SGCommandMgr::instance()->addCommand("clear-flightplan", commandClearFlightPlan); + SGCommandMgr::instance()->addCommand("set-active-waypt", commandSetActiveWaypt); + SGCommandMgr::instance()->addCommand("insert-waypt", commandInsertWaypt); + SGCommandMgr::instance()->addCommand("delete-waypt", commandDeleteWaypt); } @@ -227,7 +381,7 @@ void FGRouteMgr::postinit() SGPath path(_pathNode->getStringValue()); if (path.exists()) { SG_LOG(SG_AUTOPILOT, SG_INFO, "loading flight-plan from:" << path.str()); - loadRoute(); + loadRoute(path); } // this code only matters for the --wp option now - perhaps the option @@ -897,11 +1051,11 @@ void FGRouteMgr::InputListener::valueChanged(SGPropertyNode *prop) else if (!strcmp(s, "@ACTIVATE")) mgr->activate(); else if (!strcmp(s, "@LOAD")) { - mgr->loadRoute(); + SGPath path(mgr->_pathNode->getStringValue()); + mgr->loadRoute(path); } else if (!strcmp(s, "@SAVE")) { - mgr->saveRoute(); - } else if (!strcmp(s, "@POP")) { - SG_LOG(SG_AUTOPILOT, SG_WARN, "route-manager @POP command is deprecated"); + SGPath path(mgr->_pathNode->getStringValue()); + mgr->saveRoute(path); } else if (!strcmp(s, "@NEXT")) { mgr->jumpToIndex(mgr->_currentIndex + 1); } else if (!strcmp(s, "@PREVIOUS")) { @@ -1119,9 +1273,8 @@ Waypt* FGRouteMgr::wayptAtIndex(int index) const return _route[index]; } -void FGRouteMgr::saveRoute() +bool FGRouteMgr::saveRoute(const SGPath& path) { - SGPath path(_pathNode->getStringValue()); SG_LOG(SG_IO, SG_INFO, "Saving route to " << path.str()); try { SGPropertyNode_ptr d(new SGPropertyNode); @@ -1148,18 +1301,19 @@ void FGRouteMgr::saveRoute() wpt->saveAsNode(routeNode->getChild("wp", i, true)); } // of waypoint iteration writeProperties(path.str(), d, true /* write-all */); + return true; } catch (sg_exception& e) { SG_LOG(SG_IO, SG_WARN, "failed to save flight-plan:" << e.getMessage()); + return false; } } -void FGRouteMgr::loadRoute() +bool FGRouteMgr::loadRoute(const SGPath& path) { // deactivate route first active->setBoolValue(false); SGPropertyNode_ptr routeData(new SGPropertyNode); - SGPath path(_pathNode->getStringValue()); SG_LOG(SG_IO, SG_INFO, "going to read flight-plan from:" << path.str()); @@ -1167,8 +1321,7 @@ void FGRouteMgr::loadRoute() readProperties(path.str(), routeData); } catch (sg_exception& ) { // if XML parsing fails, the file might be simple textual list of waypoints - loadPlainTextRoute(path); - return; + return loadPlainTextRoute(path); } try { @@ -1180,9 +1333,11 @@ void FGRouteMgr::loadRoute() } else { throw sg_io_exception("unsupported XML route version"); } + return true; } catch (sg_exception& e) { SG_LOG(SG_IO, SG_WARN, "failed to load flight-plan (from '" << e.getOrigin() << "'):" << e.getMessage()); + return false; } } @@ -1299,11 +1454,11 @@ WayptRef FGRouteMgr::parseVersion1XMLWaypt(SGPropertyNode* aWP) return w; } -void FGRouteMgr::loadPlainTextRoute(const SGPath& path) +bool FGRouteMgr::loadPlainTextRoute(const SGPath& path) { sg_gzifstream in(path.str().c_str()); if (!in.is_open()) { - return; + return false; } try { @@ -1330,8 +1485,10 @@ void FGRouteMgr::loadPlainTextRoute(const SGPath& path) } // of line iteration _route = wpts; + return true; } catch (sg_exception& e) { SG_LOG(SG_IO, SG_WARN, "failed to load route from:" << path.str() << ":" << e.getMessage()); + return false; } } diff --git a/src/Autopilot/route_mgr.hxx b/src/Autopilot/route_mgr.hxx index 16b4adc4b..31336f96a 100644 --- a/src/Autopilot/route_mgr.hxx +++ b/src/Autopilot/route_mgr.hxx @@ -118,13 +118,22 @@ public: */ void jumpToIndex(int index); - void saveRoute(); - void loadRoute(); + bool saveRoute(const SGPath& p); + bool loadRoute(const SGPath& p); /** * Helper command to setup current airport/runway if necessary */ void initAtPosition(); + + /** + * Create a WayPoint from a string in the following format: + * - simple identifier + * - decimal-lon,decimal-lat + * - airport-id/runway-id + * - navaid/radial-deg/offset-nm + */ + flightgear::WayptRef waypointFromString(const std::string& target); private: flightgear::WayptVec _route; int _currentIndex; @@ -188,17 +197,7 @@ private: SGPropertyNode_ptr weightOnWheels; InputListener *listener; - SGPropertyNode_ptr mirror; - - /** - * Create a SGWayPoint from a string in the following format: - * - simple identifier - * - decimal-lon,decimal-lat - * - airport-id/runway-id - * - navaid/radial-deg/offset-nm - */ - flightgear::WayptRef waypointFromString(const std::string& target); - + SGPropertyNode_ptr mirror; void departureChanged(); void buildDeparture(flightgear::WayptRef enroute, flightgear::WayptVec& wps); @@ -229,7 +228,7 @@ private: bool checkFinished(); - void loadPlainTextRoute(const SGPath& path); + bool loadPlainTextRoute(const SGPath& path); void loadVersion1XMLRoute(SGPropertyNode_ptr routeData); void loadVersion2XMLRoute(SGPropertyNode_ptr routeData); From 2b967608a0029e6f373133124affd815b3a853e7 Mon Sep 17 00:00:00 2001 From: James Turner Date: Wed, 25 May 2011 07:50:15 +0100 Subject: [PATCH 5/6] Expose FGPositioned data via property tree, and make comm-stations a real FGPositioned subclass. --- src/ATC/CMakeLists.txt | 2 +- src/ATC/CommStation.cxx | 67 ++++ src/ATC/CommStation.hxx | 39 +++ src/ATC/Makefile.am | 2 +- src/ATC/atis_mgr.cxx | 46 --- src/ATC/atis_mgr.hxx | 39 --- src/ATCDCL/ATC.cxx | 26 +- src/ATCDCL/ATC.hxx | 7 +- src/ATCDCL/ATCDialog.cxx | 127 +++----- src/ATCDCL/ATCmgr.cxx | 138 +++------ src/ATCDCL/ATCmgr.hxx | 47 +-- src/ATCDCL/CMakeLists.txt | 1 - src/ATCDCL/Makefile.am | 1 - src/ATCDCL/atis.cxx | 51 +++- src/ATCDCL/atis.hxx | 3 + src/ATCDCL/commlist.cxx | 302 ------------------- src/ATCDCL/commlist.hxx | 136 --------- src/Airports/apt_loader.cxx | 84 +++--- src/Airports/apt_loader.hxx | 5 +- src/Airports/runwaybase.cxx | 1 + src/Airports/runwaybase.hxx | 1 + src/Airports/runways.cxx | 7 + src/Airports/runways.hxx | 3 + src/Airports/simple.cxx | 57 ++++ src/Airports/simple.hxx | 16 +- src/Instrumentation/KLN89/kln89_page_apt.cxx | 107 ++----- src/Main/fg_init.cxx | 21 +- src/Navaids/CMakeLists.txt | 1 + src/Navaids/PositionedBinding.cxx | 169 +++++++++++ src/Navaids/PositionedBinding.hxx | 63 ++++ src/Navaids/navrecord.cxx | 8 + src/Navaids/navrecord.hxx | 5 + src/Navaids/positioned.cxx | 170 ++++++++++- src/Navaids/positioned.hxx | 28 +- 34 files changed, 864 insertions(+), 916 deletions(-) create mode 100644 src/ATC/CommStation.cxx create mode 100644 src/ATC/CommStation.hxx delete mode 100644 src/ATC/atis_mgr.cxx delete mode 100644 src/ATC/atis_mgr.hxx delete mode 100644 src/ATCDCL/commlist.cxx delete mode 100644 src/ATCDCL/commlist.hxx create mode 100644 src/Navaids/PositionedBinding.cxx create mode 100644 src/Navaids/PositionedBinding.hxx diff --git a/src/ATC/CMakeLists.txt b/src/ATC/CMakeLists.txt index 60c18e996..98b6a0d25 100644 --- a/src/ATC/CMakeLists.txt +++ b/src/ATC/CMakeLists.txt @@ -1,8 +1,8 @@ include(FlightGearComponent) set(SOURCES - atis_mgr.cxx trafficcontrol.cxx + CommStation.cxx ) flightgear_component(ATC "${SOURCES}") diff --git a/src/ATC/CommStation.cxx b/src/ATC/CommStation.cxx new file mode 100644 index 000000000..45bc2cc08 --- /dev/null +++ b/src/ATC/CommStation.cxx @@ -0,0 +1,67 @@ +#include "CommStation.hxx" + +#include + +#include + +namespace { + +typedef std::multimap FrequencyMap; +static FrequencyMap static_frequencies; + +typedef std::pair FrequencyMapRange; + +} // of anonymous namespace + +namespace flightgear { + +CommStation::CommStation(const std::string& name, FGPositioned::Type t, const SGGeod& pos, int range, int freq) : + FGPositioned(t, name, pos), + mRangeNM(range), + mFreqKhz(freq), + mAirport(NULL) +{ + static_frequencies.insert(std::make_pair(freq, this)); + + init(true); +} + +void CommStation::setAirport(FGAirport* apt) +{ + mAirport = apt; +} + +double CommStation::freqMHz() const +{ + return mFreqKhz / 100.0; +} + +PositionedBinding* +CommStation::createBinding(SGPropertyNode* nd) const +{ + return new CommStationBinding(this, nd); +} + +CommStation* +CommStation::findByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt) +{ + FrequencyMapRange range = static_frequencies.equal_range(freqKhz); + FGPositioned::List results; + for (; range.first != range.second; ++range.first) { + CommStation* sta = range.first->second; + if (filt && !filt->pass(sta)) { + continue; // filtered out + } + + results.push_back(sta); + } + + if (results.empty()) { + return NULL; + } + + FGPositioned::sortByRange(results, pos); + return (CommStation*) results.front().ptr(); +} + +} // of namespace flightgear diff --git a/src/ATC/CommStation.hxx b/src/ATC/CommStation.hxx new file mode 100644 index 000000000..89c0d1f43 --- /dev/null +++ b/src/ATC/CommStation.hxx @@ -0,0 +1,39 @@ +#ifndef FG_ATC_COMM_STATION_HXX +#define FG_ATC_COMM_STATION_HXX + +#include + +class FGAirport; + +namespace flightgear +{ + +class CommStation : public FGPositioned +{ +public: + CommStation(const std::string& name, FGPositioned::Type t, const SGGeod& pos, int range, int freq); + + void setAirport(FGAirport* apt); + FGAirport* airport() const { return mAirport; } + + virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const; + + int rangeNm() const + { return mRangeNM; } + + int freqKHz() const + { return mFreqKhz; } + + double freqMHz() const; + + static CommStation* findByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt = NULL); +private: + int mRangeNM; + int mFreqKhz; + FGAirport* mAirport; +}; + +} // of namespace flightgear + +#endif // of FG_ATC_COMM_STATION_HXX + diff --git a/src/ATC/Makefile.am b/src/ATC/Makefile.am index e3e522737..046428e83 100644 --- a/src/ATC/Makefile.am +++ b/src/ATC/Makefile.am @@ -1,7 +1,7 @@ noinst_LIBRARIES = libATC.a libATC_a_SOURCES = \ - atis_mgr.cxx atis_mgr.hxx \ + CommStation.cxx CommStation.hxx \ trafficcontrol.cxx trafficcontrol.hxx INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src diff --git a/src/ATC/atis_mgr.cxx b/src/ATC/atis_mgr.cxx deleted file mode 100644 index 034a8358a..000000000 --- a/src/ATC/atis_mgr.cxx +++ /dev/null @@ -1,46 +0,0 @@ -/****************************************************************************** - * atis.cxx - * Written by Durk Talsma, started August 1, 2010. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * - **************************************************************************/ - - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include -#include "atis_mgr.hxx" - -FGAtisManager::FGAtisManager() { - -} - -FGAtisManager::~FGAtisManager() { - -} - -void FGAtisManager::init() { - SGSubsystem::init(); -} - -void FGAtisManager::update ( double time ) { - //cerr << "ATIS code is running at time: " << time << endl; -} diff --git a/src/ATC/atis_mgr.hxx b/src/ATC/atis_mgr.hxx deleted file mode 100644 index 12fc4fd07..000000000 --- a/src/ATC/atis_mgr.hxx +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C++ -*- ***************************************************** - * atic.hxx - * Written by Durk Talsma. Started August 1, 2010; based on earlier work - * by David C. Luff - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * - **************************************************************************/ - -#ifndef _ATIS_HXX_ -#define _ATIS_HXX_ - -#include - -class FGAtisManager : public SGSubsystem -{ -private: - -public: - FGAtisManager(); - ~FGAtisManager(); - void init(); - void update(double time); -}; - -#endif // _ATIS_HXX_ \ No newline at end of file diff --git a/src/ATCDCL/ATC.cxx b/src/ATCDCL/ATC.cxx index 30d3d23e8..4701a67ee 100644 --- a/src/ATCDCL/ATC.cxx +++ b/src/ATCDCL/ATC.cxx @@ -31,8 +31,8 @@ #include
#include
- - +#include +#include FGATC::FGATC() : _playing(false), @@ -181,14 +181,20 @@ void FGATC::NotifyTransmissionFinished(const string& rid) { } } -void FGATC::SetData(ATCData* d) { - _type = d->type; - _geod = d->geod; - _cart = d->cart; - range = d->range; - ident = d->ident; - name = d->name; - freq = d->freq; +void FGATC::SetStation(flightgear::CommStation* sta) { + switch (sta->type()) { + case FGPositioned::FREQ_ATIS: _type = ATIS; break; + case FGPositioned::FREQ_AWOS: _type = AWOS; break; + default: + throw sg_exception("unsupported comm station type"); + } + + _geod = sta->geod(); + _cart = sta->cart(); + range = sta->rangeNm(); + ident = sta->airport()->ident(); + name = sta->airport()->name(); + freq = sta->freqKHz(); } // Render a transmission diff --git a/src/ATCDCL/ATC.hxx b/src/ATCDCL/ATC.hxx index 2109b697b..17f743cd7 100644 --- a/src/ATCDCL/ATC.hxx +++ b/src/ATCDCL/ATC.hxx @@ -37,6 +37,11 @@ class SGSampleGroup; +namespace flightgear +{ + class CommStation; +} + // Convert a frequency in MHz to tens of kHz // so we can use it e.g. as an index into commlist_freq // @@ -140,7 +145,7 @@ public: inline atc_type GetType() { return _type; } // Set the core ATC data - void SetData(ATCData* d); + void SetStation(flightgear::CommStation* sta); inline int get_freq() const { return freq; } inline void set_freq(const int fq) {freq = fq;} diff --git a/src/ATCDCL/ATCDialog.cxx b/src/ATCDCL/ATCDialog.cxx index f5f5ec935..ad6e02763 100644 --- a/src/ATCDCL/ATCDialog.cxx +++ b/src/ATCDCL/ATCDialog.cxx @@ -34,9 +34,9 @@ #include "ATCDialog.hxx" #include "ATC.hxx" #include "ATCmgr.hxx" -#include "commlist.hxx" #include "ATCutils.hxx" #include +#include #include @@ -286,21 +286,17 @@ void FGATCDialog::PopupCallback(int num) { } } -// map() key data type (removes duplicates and sorts by distance) -struct atcdata { - atcdata() {} - atcdata(const string i, const string n, const double d) { - id = i, name = n, distance = d; - } - bool operator<(const atcdata& a) const { - return id != a.id && distance < a.distance; - } - bool operator==(const atcdata& a) const { - return id == a.id && distance == a.distance; - } - string id; - string name; - double distance; +class AirportsWithATC : public FGAirport::AirportFilter +{ +public: + virtual FGPositioned::Type maxType() const { + return FGPositioned::SEAPORT; + } + + virtual bool passAirport(FGAirport* aApt) const + { + return (!aApt->commStations().empty()); + } }; void FGATCDialog::FreqDialog() { @@ -315,38 +311,25 @@ void FGATCDialog::FreqDialog() { // remove all dynamic airport/ATC buttons button_group->removeChildren("button", false); - // Find the ATC stations within a reasonable range - comm_list_type atc_stations; - comm_list_iterator atc_stat_itr; SGGeod geod(SGGeod::fromDegFt(fgGetDouble("/position/longitude-deg"), fgGetDouble("/position/latitude-deg"), fgGetDouble("/position/altitude-ft"))); - SGVec3d aircraft = SGVec3d::fromGeod(geod); - - // search stations in range - int num_stat = current_commlist->FindByPos(geod, 50.0, &atc_stations); - if (num_stat != 0) { - map uniq; - // fill map (sorts by distance and removes duplicates) - comm_list_iterator itr = atc_stations.begin(); - for (; itr != atc_stations.end(); ++itr) { - double distance = distSqr(aircraft, itr->cart); - uniq[atcdata(itr->ident, itr->name, distance)] = true; - } - // create button per map entry (modified copy of ) - map::iterator uit = uniq.begin(); - for (int n = 0; uit != uniq.end() && n < 6; ++uit, ++n) { // max 6 buttons - SGPropertyNode *entry = button_group->getNode("button", n, true); - copyProperties(button_group->getNode("button-template", true), entry); - entry->removeChildren("enabled", true); - entry->setStringValue("legend", uit->first.id.c_str()); - entry->setStringValue("binding[0]/value", uit->first.id.c_str()); - } - } + AirportsWithATC filt; + FGPositioned::List results = FGPositioned::findWithinRange(geod, 50.0, &filt); + FGPositioned::sortByRange(results, geod); + for (unsigned int r=0; (rgetNode("button", r, true); + copyProperties(button_group->getNode("button-template", true), entry); + entry->removeChildren("enabled", true); + entry->setStringValue("legend", results[r]->ident()); + entry->setStringValue("binding[0]/value", results[r]->ident()); + } + // (un)hide message saying no things in range SGPropertyNode_ptr range_error = getNamedNode(dlg, "no-atc-in-range"); - range_error->setBoolValue("enabled", !num_stat); + range_error->setBoolValue("enabled", !results.empty()); _gui->showDialog(dialog_name); } @@ -377,43 +360,33 @@ void FGATCDialog::FreqDisplay(string& ident) { label = ident + " Frequencies"; dlg->setStringValue("text/label", label.c_str()); - int n = 0; // Number of ATC frequencies at this airport - - comm_list_type stations; - int found = current_commlist->FindByPos(a->geod(), 20.0, &stations); - if(found) { - comm_list_iterator itr = stations.begin(); - for (n = 0; itr != stations.end(); ++itr) { - if(itr->ident != ident) - continue; - - if(itr->type == INVALID) - continue; - - // add frequency line (modified copy of ) - SGPropertyNode *entry = freq_group->getNode("group", n, true); - copyProperties(freq_group->getNode("group-template", true), entry); - entry->removeChildren("enabled", true); - - ostringstream ostr; - ostr << itr->type; - entry->setStringValue("text[0]/label", ostr.str()); - - char buf[8]; - snprintf(buf, 8, "%.2f", (itr->freq / 100.0)); // Convert from KHz to MHz - if(buf[5] == '3') buf[5] = '2'; - if(buf[5] == '8') buf[5] = '7'; - buf[7] = '\0'; - - entry->setStringValue("text[1]/label", buf); - n++; - } - } - if(n == 0) { - label = "No frequencies found for airport " + ident; + const flightgear::CommStationList& comms(a->commStations()); + if (comms.empty()) { + label = "No frequencies found for airport " + ident; mkDialog(label.c_str()); return; - } + } + + int n = 0; + for (unsigned int c=0; c < comms.size(); ++c) { + flightgear::CommStation* comm = comms[c]; + + // add frequency line (modified copy of ) + SGPropertyNode *entry = freq_group->getNode("group", n, true); + copyProperties(freq_group->getNode("group-template", true), entry); + entry->removeChildren("enabled", true); + + entry->setStringValue("text[0]/label", comm->ident()); + + char buf[8]; + snprintf(buf, 8, "%.2f", comm->freqMHz()); + if(buf[5] == '3') buf[5] = '2'; + if(buf[5] == '8') buf[5] = '7'; + buf[7] = '\0'; + + entry->setStringValue("text[1]/label", buf); + ++n; + } _gui->showDialog(dialog_name); } diff --git a/src/ATCDCL/ATCmgr.cxx b/src/ATCDCL/ATCmgr.cxx index 537bfddef..8d8a6fc58 100644 --- a/src/ATCDCL/ATCmgr.cxx +++ b/src/ATCDCL/ATCmgr.cxx @@ -24,29 +24,18 @@ #include #include +#include #include +#include +#include
#include "ATCmgr.hxx" -#include "commlist.hxx" #include "ATCDialog.hxx" #include "ATCutils.hxx" +#include "atis.hxx" - -/* -// periodic radio station search wrapper -static void fgATCSearch( void ) { - globals->get_ATC_mgr()->Search(); -} -*/ //This wouldn't compile - including Time/event.hxx breaks it :-( - // Is this still true?? -EMH- - -AirportATC::AirportATC() : - atis_freq(0.0), - atis_active(false) - //airport_atc_map.clear(); -{ -} +using flightgear::CommStation; FGATCMgr::FGATCMgr() : initDone(false), @@ -148,44 +137,6 @@ void FGATCMgr::update(double dt) { //cout << "Leaving update..." << endl; } - -// Returns frequency in KHz - should I alter this to return in MHz? -unsigned short int FGATCMgr::GetFrequency(const string& ident, const atc_type& tp) { - ATCData test; - bool ok = current_commlist->FindByCode(ident, test, tp); - return(ok ? test.freq : 0); -} - -// Register the fact that the comm radio is tuned to an airport -// Channel is zero based -bool FGATCMgr::CommRegisterAirport(const string& ident, int chan, const atc_type& tp) { - SG_LOG(SG_ATC, SG_BULK, "Comm channel " << chan << " registered airport " << ident); - //cout << "Comm channel " << chan << " registered airport " << ident << ' ' << tp << '\n'; - if(airport_atc_map.find(ident) != airport_atc_map.end()) { - if(tp == ATIS || tp == AWOS) { - airport_atc_map[ident]->atis_active = true; - } - return(true); - } else { - //cout << "NOT IN MAP - creating new..." << endl; - const FGAirport *ap = fgFindAirportID(ident); - if (ap) { - AirportATC *a = new AirportATC; - // I'm not entirely sure that this AirportATC structure business is actually needed - it just duplicates what we can find out anyway! - a->geod = ap->geod(); - a->atis_freq = GetFrequency(ident, ATIS) - || GetFrequency(ident, AWOS); - a->atis_active = false; - if(tp == ATIS || tp == AWOS) { - a->atis_active = true; - } - airport_atc_map[ident] = a; - return(true); - } - } - return(false); -} - typedef map MSI; void FGATCMgr::ZapOtherService(const string ncunit, const string svc_name){ @@ -224,16 +175,6 @@ FGATC* FGATCMgr::FindInList(const string& id, const atc_type& tp) { return (*atc_list)[ndx]; } -// Returns true if the airport is found in the map -bool FGATCMgr::GetAirportATCDetails(const string& icao, AirportATC* a) { - if(airport_atc_map.find(icao) != airport_atc_map.end()) { - *a = *airport_atc_map[icao]; - return(true); - } else { - return(false); - } -} - // Return a pointer to an appropriate voice for a given type of ATC // creating the voice if necessary - ie. make sure exactly one copy // of every voice in use exists in memory. @@ -303,49 +244,44 @@ void FGATCMgr::FreqSearch(const string navcomm, const int unit) { if (!comm_node) return; // no such radio unit ATCData data; - double freq = comm_node->getDoubleValue(); + // Note: 122.375 must be rounded DOWN to 12237 + // in order to be consistent with apt.dat et cetera. + int freqKhz = static_cast(comm_node->getDoubleValue() * 100.0 + 0.25); + _aircraftPos = SGGeod::fromDegFt(lon_node->getDoubleValue(), lat_node->getDoubleValue(), elev_node->getDoubleValue()); - // Query the data store and get the closest match if any - //cout << "Will FindByFreq: " << lat << " " << lon << " " << elev - // << " freq: " << freq << endl; - if(current_commlist->FindByFreq(_aircraftPos, freq, &data)) { - //cout << "FoundByFreq: " << freq - // << " ident: " << data.ident - // << " type: " << data.type << " ***" << endl; - // We are in range of something. + CommStation* sta = CommStation::findByFreq(freqKhz, _aircraftPos); + if (!sta) { + ZapOtherService(ncunit, "x x x"); + return; + } + + // Get rid of any *other* service that was on this radio unit: + FGPositioned::Type ty = sta->type(); + string svc_name = sta->ident() + FGPositioned::nameForType(ty); + ZapOtherService(ncunit, svc_name); + // See if the service already exists, possibly connected to + // some other radio unit: + if (atc_list->count(svc_name)) { + // make sure the service knows it's tuned on this radio: + FGATC* svc = (*atc_list)[svc_name]; + svc->active_on[ncunit] = 1; + svc->SetDisplay(); + return; + } - - // Get rid of any *other* service that was on this radio unit: - string svc_name = data.ident+decimalNumeral(data.type); - ZapOtherService(ncunit, svc_name); - // See if the service already exists, possibly connected to - // some other radio unit: - if (atc_list->count(svc_name)) { - // make sure the service knows it's tuned on this radio: - FGATC* svc = (*atc_list)[svc_name]; + // This was a switch-case statement but the compiler didn't like + // the new variable creation with it. + if(ty == FGPositioned::FREQ_ATIS || ty == FGPositioned::FREQ_AWOS) { + (*atc_list)[svc_name] = new FGATIS; + FGATC* svc = (*atc_list)[svc_name]; + if(svc != NULL) { + svc->SetStation(sta); svc->active_on[ncunit] = 1; svc->SetDisplay(); - return; + svc->Init(); } + } - CommRegisterAirport(data.ident, unit, data.type); - - // This was a switch-case statement but the compiler didn't like - // the new variable creation with it. - if(data.type == ATIS || data.type == AWOS) { - (*atc_list)[svc_name] = new FGATIS; - FGATC* svc = (*atc_list)[svc_name]; - if(svc != NULL) { - svc->SetData(&data); - svc->active_on[ncunit] = 1; - svc->SetDisplay(); - svc->Init(); - } - } - } else { - // No services in range. Zap any service on this unit. - ZapOtherService(ncunit, "x x x"); - } } diff --git a/src/ATCDCL/ATCmgr.hxx b/src/ATCDCL/ATCmgr.hxx index 850fcc0a9..179f65fc3 100644 --- a/src/ATCDCL/ATCmgr.hxx +++ b/src/ATCDCL/ATCmgr.hxx @@ -24,31 +24,12 @@ #include -#include
-#include - #include #include #include #include "ATC.hxx" -using std::string; -using std::list; -using std::map; - -// Structure for holding details of the ATC frequencies at a given airport, and whether they are in the active list or not. -// These can then be cross referenced with the commlists which are stored by frequency or bucket. -// Non-available services are denoted by a frequency of zero. -// These structures are only intended to be created for in-use airports, and removed when no longer needed. -struct AirportATC { - AirportATC(); - - SGGeod geod; - float atis_freq; - bool atis_active; -}; - class FGATCMgr : public SGSubsystem { @@ -56,16 +37,8 @@ private: bool initDone; // Hack - guard against update getting called before init - // A map of airport ID vs frequencies and ATC provision - typedef map < string, AirportATC* > airport_atc_map_type; - typedef airport_atc_map_type::iterator airport_atc_map_iterator; - typedef airport_atc_map_type::const_iterator airport_atc_map_const_iterator; - - airport_atc_map_type airport_atc_map; - airport_atc_map_iterator airport_atc_map_itr; - // A list of pointers to all currently active ATC classes - typedef map atc_list_type; + typedef std::map atc_list_type; typedef atc_list_type::iterator atc_list_iterator; typedef atc_list_type::const_iterator atc_list_const_iterator; @@ -107,9 +80,7 @@ public: void update(double dt); - // Returns true if the airport is found in the map - bool GetAirportATCDetails(const string& icao, AirportATC* a); - + // Return a pointer to an appropriate voice for a given type of ATC // creating the voice if necessary - ie. make sure exactly one copy // of every voice in use exists in memory. @@ -124,26 +95,20 @@ public: atc_type GetComm2ATCType() { return(INVALID); } FGATC* GetComm2ATCPointer() { return(0/* kludge */); } - // Get the frequency of a given service at a given airport - // Returns zero if not found - unsigned short int GetFrequency(const string& ident, const atc_type& tp); - - // Register the fact that the comm radio is tuned to an airport - bool CommRegisterAirport(const string& ident, int chan, const atc_type& tp); - + private: // Remove a class from the atc_list and delete it from memory // *if* no other comm channel or AI plane is using it. - void ZapOtherService(const string ncunit, const string svc_name); + void ZapOtherService(const std::string ncunit, const std::string svc_name); // Return a pointer to a class in the list given ICAO code and type // Return NULL if the given service is not in the list // - *** THE CALLING FUNCTION MUST CHECK FOR THIS *** - FGATC* FindInList(const string& id, const atc_type& tp); + FGATC* FindInList(const std::string& id, const atc_type& tp); // Search the specified radio for stations on the same frequency and in range. - void FreqSearch(const string navcomm, const int unit); + void FreqSearch(const std::string navcomm, const int unit); }; #endif // _FG_ATCMGR_HXX diff --git a/src/ATCDCL/CMakeLists.txt b/src/ATCDCL/CMakeLists.txt index 72c1da6a9..d9e8db69b 100644 --- a/src/ATCDCL/CMakeLists.txt +++ b/src/ATCDCL/CMakeLists.txt @@ -3,7 +3,6 @@ include(FlightGearComponent) set(SOURCES ATC.cxx atis.cxx - commlist.cxx ATCDialog.cxx ATCVoice.cxx ATCmgr.cxx diff --git a/src/ATCDCL/Makefile.am b/src/ATCDCL/Makefile.am index d268da1e5..8c2a2b74b 100644 --- a/src/ATCDCL/Makefile.am +++ b/src/ATCDCL/Makefile.am @@ -3,7 +3,6 @@ noinst_LIBRARIES = libATCDCL.a libATCDCL_a_SOURCES = \ ATC.hxx ATC.cxx \ atis.hxx atis.cxx \ - commlist.hxx commlist.cxx \ ATCDialog.hxx ATCDialog.cxx \ ATCVoice.hxx ATCVoice.cxx \ ATCmgr.hxx ATCmgr.cxx \ diff --git a/src/ATCDCL/atis.cxx b/src/ATCDCL/atis.cxx index 53973a7a7..b2f358620 100644 --- a/src/ATCDCL/atis.cxx +++ b/src/ATCDCL/atis.cxx @@ -34,6 +34,8 @@ #include "atis_lexicon.hxx" #include +#include +#include #include // atoi() #include // sprintf @@ -44,9 +46,6 @@ #include #include - -#include - #include #include #include @@ -56,7 +55,6 @@ #include -#include "commlist.hxx" #include "ATCutils.hxx" #include "ATCmgr.hxx" @@ -230,6 +228,47 @@ int Apt_US_CA(const string id) { return 0; } +// Add structure and map for storing a log of atis transmissions +// made in this session of FlightGear. This allows the callsign +// to be allocated correctly wrt time. +typedef struct { + double tstamp; + int sequence; +} atis_transmission_type; + +typedef std::map < std::string, atis_transmission_type > atis_log_type; +typedef atis_log_type::iterator atis_log_iterator; +typedef atis_log_type::const_iterator atis_log_const_iterator; + +static atis_log_type atislog; + +int FGATIS::GetAtisSequence( const string& apt_id, + const double tstamp, const int interval, const int special) +{ + atis_transmission_type tran; + + if(atislog.find(apt_id) == atislog.end()) { // New station + tran.tstamp = tstamp - interval; +// Random number between 0 and 25 inclusive, i.e. 26 equiprobable outcomes: + tran.sequence = int(sg_random() * LTRS); + atislog[apt_id] = tran; + //cout << "New ATIS station: " << apt_id << " seq-1: " + // << tran.sequence << endl; + } + +// calculate the appropriate identifier and update the log + tran = atislog[apt_id]; + + int delta = int((tstamp - tran.tstamp) / interval); + tran.tstamp += delta * interval; + if (special && !delta) delta++; // a "special" ATIS update is required + tran.sequence = (tran.sequence + delta) % LTRS; + atislog[apt_id] = tran; + //if (delta) cout << "New ATIS sequence: " << tran.sequence + // << " Delta: " << delta << endl; + return(tran.sequence + (delta ? 0 : LTRS*1000)); +} + // Generate the actual broadcast ATIS transmission. // Regen means regenerate the /current/ transmission. // Special means generate a new transmission, with a new sequence. @@ -245,8 +284,8 @@ int FGATIS::GenTransmission(const int regen, const int special) { int interval = _type == ATIS ? ATIS_interval // ATIS updated hourly : 2*minute; // AWOS updated more frequently - int sequence = current_commlist->GetAtisSequence(ident, - tstamp, interval, special); + + int sequence = GetAtisSequence(ident, tstamp, interval, special); if (!regen && sequence > LTRS) { //xx if (msg_OK) cout << "ATIS: no change: " << sequence << endl; //xx msg_time = cur_time; diff --git a/src/ATCDCL/atis.hxx b/src/ATCDCL/atis.hxx index 76809eb09..189b11106 100644 --- a/src/ATCDCL/atis.hxx +++ b/src/ATCDCL/atis.hxx @@ -95,6 +95,9 @@ class FGATIS : public FGATC { void TreeOut(int msgOK); friend std::istream& operator>> ( std::istream&, FGATIS& ); + + int GetAtisSequence( const std::string& apt_id, + const double tstamp, const int interval, const int special); }; typedef int (FGATIS::*int_getter)() const; diff --git a/src/ATCDCL/commlist.cxx b/src/ATCDCL/commlist.cxx deleted file mode 100644 index ef5c8d7b8..000000000 --- a/src/ATCDCL/commlist.cxx +++ /dev/null @@ -1,302 +0,0 @@ -// commlist.cxx -- comm frequency lookup class -// -// Written by David Luff and Alexander Kappes, started Jan 2003. -// Based on navlist.cxx by Curtis Olson, started April 2000. -// -// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "commlist.hxx" - -#include -#include -#include -#include -#include -#include -#include - -#include "ATCutils.hxx" - - -FGCommList *current_commlist; - - -// Constructor -FGCommList::FGCommList( void ) { - sg_srandom_time(); -} - - -// Destructor -FGCommList::~FGCommList( void ) { -} - - -// load the navaids and build the map -bool FGCommList::init( const SGPath& path ) { - - SGPath temp = path; - commlist_freq.erase(commlist_freq.begin(), commlist_freq.end()); - commlist_bck.erase(commlist_bck.begin(), commlist_bck.end()); - temp.append( "ATC/default.atis" ); - LoadComms(temp); - temp = path; - temp.append( "ATC/default.tower" ); - LoadComms(temp); - temp = path; - temp.append( "ATC/default.ground" ); - LoadComms(temp); - temp = path; - temp.append( "ATC/default.approach" ); - LoadComms(temp); - return true; -} - - -bool FGCommList::LoadComms(const SGPath& path) { - - sg_gzifstream fin( path.str() ); - if ( !fin.is_open() ) { - SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() ); - exit(-1); - } - - // read in each line of the file - fin >> skipcomment; - - while ( !fin.eof() ) { - ATCData a; - fin >> a; - if(a.type == INVALID) { - SG_LOG(SG_GENERAL, SG_DEBUG, "WARNING - INVALID type found in " << path.str() << '\n'); - } else { - // Push all stations onto frequency map - commlist_freq[a.freq].push_back(a); - - // Push non-atis stations onto bucket map as well - // In fact, push all stations onto bucket map for now so FGATCMgr::GetFrequency() works. - //if(a.type != ATIS and/or AWOS?) { - // get bucket number - SGBucket bucket(a.geod); - int bucknum = bucket.gen_index(); - commlist_bck[bucknum].push_back(a); - //} - } - - fin >> skipcomment; - } - - fin.close(); - return true; -} - - -// query the database for the specified frequency, lon and lat are in -// degrees, elev is in meters -// If no atc_type is specified, it returns true if any non-invalid type is found -// If atc_type is specifed, returns true only if the specified type is found -bool FGCommList::FindByFreq(const SGGeod& aPos, double freq, - ATCData* ad, atc_type tp ) -{ - comm_list_type stations; - stations = commlist_freq[kHz10(freq)]; - comm_list_iterator current = stations.begin(); - comm_list_iterator last = stations.end(); - - // double az1, az2, s; - SGVec3d aircraft = SGVec3d::fromGeod(aPos); - const double orig_max_d = 1e100; - double max_d = orig_max_d; - double d; - // TODO - at the moment this loop returns the first match found in range - // We want to return the closest match in the event of a frequency conflict - for ( ; current != last ; ++current ) { - d = distSqr(aircraft, current->cart); - - //cout << " dist = " << sqrt(d) - // << " range = " << current->range * SG_NM_TO_METER << endl; - - // TODO - match up to twice the published range so we can model - // reduced signal strength - // NOTE The below is squared since we match to distance3Dsquared (above) to avoid a sqrt. - if ( d < (current->range * SG_NM_TO_METER - * current->range * SG_NM_TO_METER ) ) { - //cout << "matched = " << current->ident << endl; - if((tp == INVALID) || (tp == (*current).type)) { - if(d < max_d) { - max_d = d; - *ad = *current; - } - } - } - } - - if(max_d < orig_max_d) { - return true; - } else { - return false; - } -} - -int FGCommList::FindByPos(const SGGeod& aPos, double range, comm_list_type* stations, atc_type tp) -{ - // number of relevant stations found within range - int found = 0; - stations->erase(stations->begin(), stations->end()); - - // get bucket number for plane position - SGBucket buck(aPos); - - // get neigboring buckets - int bx = (int)( range*SG_NM_TO_METER / buck.get_width_m() / 2) + 1; - int by = (int)( range*SG_NM_TO_METER / buck.get_height_m() / 2 ) + 1; - - // loop over bucket range - for ( int i=-bx; i<=bx; i++) { - for ( int j=-by; j<=by; j++) { - buck = sgBucketOffset(aPos.getLongitudeDeg(), aPos.getLatitudeDeg(), i, j); - long int bucket = buck.gen_index(); - comm_map_const_iterator Fstations = commlist_bck.find(bucket); - if (Fstations == commlist_bck.end()) continue; - comm_list_const_iterator current = Fstations->second.begin(); - comm_list_const_iterator last = Fstations->second.end(); - - - // double az1, az2, s; - SGVec3d aircraft = SGVec3d::fromGeod(aPos); - double d; - for(; current != last; ++current) { - if((current->type == tp) || (tp == INVALID)) { - d = distSqr(aircraft, current->cart); - // NOTE The below is squared since we match to distance3Dsquared (above) to avoid a sqrt. - if ( d < (current->range * SG_NM_TO_METER - * current->range * SG_NM_TO_METER ) ) { - stations->push_back(*current); - ++found; - } - } - } - } - } - return found; -} - - -// Returns the distance in meters to the closest station of a given type, -// with the details written into ATCData& ad. If no type is specifed simply -// returns the distance to the closest station of any type. -// Returns -9999 if no stations found within max_range in nautical miles (default 100 miles). -// Note that the search algorithm starts at 10 miles and multiplies by 10 thereafter, so if -// say 300 miles is specifed 10, then 100, then 1000 will be searched, breaking at first result -// and giving up after 1000. -double FGCommList::FindClosest(const SGGeod& aPos, ATCData& ad, atc_type tp, double max_range) { - int num_stations = 0; - int range = 10; - comm_list_type stations; - comm_list_iterator itr; - double distance = -9999.0; - - while(num_stations == 0) { - num_stations = FindByPos(aPos, range, &stations, tp); - if(num_stations) { - double closest = max_range * SG_NM_TO_METER; - double tmp; - for(itr = stations.begin(); itr != stations.end(); ++itr) { - ATCData ad2 = *itr; - const FGAirport *a = fgFindAirportID(ad2.ident); - if (a) { - tmp = dclGetHorizontalSeparation(ad2.geod, aPos); - if(tmp <= closest) { - closest = tmp; - distance = tmp; - ad = *itr; - } - } - } - //cout << "Closest station is " << ad.ident << " at a range of " << distance << " meters\n"; - return(distance); - } - if(range > max_range) { - break; - } - range *= 10; - } - return(-9999.0); -} - - -// Find by Airport code. -// This is basically a wrapper for a call to the airport database to get the airport -// position followed by a call to FindByPos(...) -bool FGCommList::FindByCode( const string& ICAO, ATCData& ad, atc_type tp ) { - const FGAirport *a = fgFindAirportID( ICAO); - if ( a) { - comm_list_type stations; - int found = FindByPos(a->geod(), 10.0, &stations, tp); - if(found) { - comm_list_iterator itr = stations.begin(); - while(itr != stations.end()) { - if(((*itr).ident == ICAO) && ((*itr).type == tp)) { - ad = *itr; - //cout << "FindByCode returns " << ICAO - // << " type: " << tp - // << " freq: " << itr->freq - // << endl; - return true; - } - ++itr; - } - } - } - return false; -} - -// TODO - this function should move somewhere else eventually! -// Return an appropriate sequence number for an ATIS transmission. -// Return sequence number + 2600 if sequence is unchanged since -// last time. -int FGCommList::GetAtisSequence( const string& apt_id, - const double tstamp, const int interval, const int special) -{ - atis_transmission_type tran; - - if(atislog.find(apt_id) == atislog.end()) { // New station - tran.tstamp = tstamp - interval; -// Random number between 0 and 25 inclusive, i.e. 26 equiprobable outcomes: - tran.sequence = int(sg_random() * LTRS); - atislog[apt_id] = tran; - //cout << "New ATIS station: " << apt_id << " seq-1: " - // << tran.sequence << endl; - } - -// calculate the appropriate identifier and update the log - tran = atislog[apt_id]; - - int delta = int((tstamp - tran.tstamp) / interval); - tran.tstamp += delta * interval; - if (special && !delta) delta++; // a "special" ATIS update is required - tran.sequence = (tran.sequence + delta) % LTRS; - atislog[apt_id] = tran; - //if (delta) cout << "New ATIS sequence: " << tran.sequence - // << " Delta: " << delta << endl; - return(tran.sequence + (delta ? 0 : LTRS*1000)); -} diff --git a/src/ATCDCL/commlist.hxx b/src/ATCDCL/commlist.hxx deleted file mode 100644 index c5066f3e9..000000000 --- a/src/ATCDCL/commlist.hxx +++ /dev/null @@ -1,136 +0,0 @@ -// commlist.hxx -- comm frequency lookup class -// -// Written by David Luff and Alexander Kappes, started Jan 2003. -// Based on navlist.hxx by Curtis Olson, started April 2000. -// -// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -/***************************************************************** -* -* FGCommList is used to store communication frequency information -* for the ATC and AI subsystems. Two maps are maintained - one -* searchable by location and one searchable by frequency. The -* data structure returned from the search is the ATCData struct -* defined in ATC.hxx, containing location, frequency, name, range -* and type of the returned station. -* -******************************************************************/ - -#ifndef _FG_COMMLIST_HXX -#define _FG_COMMLIST_HXX - - -#include - -#include -#include -#include - -#include "ATC.hxx" -#include "atis.hxx" - -class SGPath; - -// A list of ATC stations -typedef std::list < ATCData > comm_list_type; -typedef comm_list_type::iterator comm_list_iterator; -typedef comm_list_type::const_iterator comm_list_const_iterator; - -// A map of ATC station lists -typedef std::map < int, comm_list_type > comm_map_type; -typedef comm_map_type::iterator comm_map_iterator; -typedef comm_map_type::const_iterator comm_map_const_iterator; - - -class FGCommList { - -public: - - FGCommList(); - ~FGCommList(); - - // load all comm frequencies and build the map - bool init( const SGPath& path ); - - // query the database for the specified frequency, lon and lat are - // If no atc_type is specified, it returns true if any non-invalid type is found. - // If atc_type is specifed, returns true only if the specified type is found. - // Returns the station closest to the supplied position. - // The data found is written into the passed-in ATCData structure. - bool FindByFreq(const SGGeod& aPos, double freq, ATCData* ad, atc_type tp = INVALID ); - - // query the database by location, lon and lat are in degrees, elev is in meters, range is in nautical miles. - // Returns the number of stations of the specified atc_type tp that are in range of the position defined by - // lon, lat and elev, and pushes them into stations. - // If no atc_type is specifed, returns the number of all stations in range, and pushes them into stations - // ** stations is erased before use ** - int FindByPos(const SGGeod& aPos, double range, comm_list_type* stations, atc_type tp = INVALID ); - - // Returns the distance in meters to the closest station of a given type, - // with the details written into ATCData& ad. If no type is specifed simply - // returns the distance to the closest station of any type. - // Returns -9999 if no stations found within max_range in nautical miles (default 100 miles). - // Note that the search algorithm starts at 10 miles and multiplies by 10 thereafter, so if - // say 300 miles is specifed 10, then 100, then 1000 will be searched, breaking at first result - // and giving up after 1000. - // !!!Be warned that searching anything over 100 miles will pause the sim unacceptably!!! - // (The ability to search longer ranges should be used during init only). - double FindClosest(const SGGeod& aPos, ATCData& ad, atc_type tp = INVALID, double max_range = 100.0 ); - - // Find by Airport code. - bool FindByCode( const std::string& ICAO, ATCData& ad, atc_type tp = INVALID ); - - // Return the sequence letter for an ATIS transmission given transmission time and airport id - // This maybe should get moved somewhere else!! - int GetAtisSequence( const std::string& apt_id, const double tstamp, - const int interval, const int flush=0); - - // Comm stations mapped by frequency - comm_map_type commlist_freq; - - // Comm stations mapped by bucket - comm_map_type commlist_bck; - - // Load comms from a specified path (which must include the filename) -private: - - bool LoadComms(const SGPath& path); - -//----------- This stuff is left over from atislist.[ch]xx and maybe should move somewhere else - // Add structure and map for storing a log of atis transmissions - // made in this session of FlightGear. This allows the callsign - // to be allocated correctly wrt time. - typedef struct { - double tstamp; - int sequence; - } atis_transmission_type; - - typedef std::map < std::string, atis_transmission_type > atis_log_type; - typedef atis_log_type::iterator atis_log_iterator; - typedef atis_log_type::const_iterator atis_log_const_iterator; - - atis_log_type atislog; -//----------------------------------------------------------------------------------------------- - -}; - - -extern FGCommList *current_commlist; - -#endif // _FG_COMMLIST_HXX - - diff --git a/src/Airports/apt_loader.cxx b/src/Airports/apt_loader.cxx index 8bb9924e6..5698eb16b 100644 --- a/src/Airports/apt_loader.cxx +++ b/src/Airports/apt_loader.cxx @@ -46,7 +46,8 @@ #include "simple.hxx" #include "runways.hxx" #include "pavement.hxx" -#include + +#include #include @@ -78,7 +79,7 @@ public: - void parseAPT(const string &aptdb_file, FGCommList *comm_list) + void parseAPT(const string &aptdb_file) { sg_gzifstream in( aptdb_file ); @@ -157,12 +158,8 @@ public: // custom startup locations (ignore) } else if ( line_id == 0 ) { // ?? - } else if ( line_id == 50 ) { - - parseATISLine(comm_list, simgear::strutils::split(line)); - - } else if ( line_id >= 51 && line_id <= 56 ) { - // other frequency entries (ignore) + } else if ( line_id >= 50 && line_id <= 56) { + parseCommLine(line_id, simgear::strutils::split(line)); } else if ( line_id == 110 ) { pavement = true; parsePavementLine850(simgear::strutils::split(line, 0, 4)); @@ -206,6 +203,7 @@ private: vector runways; vector taxiways; vector pavements; + vector commStations; void addAirport() { @@ -235,6 +233,7 @@ private: FGAirport* apt = new FGAirport(last_apt_id, pos, tower, last_apt_name, false, fptypeFromRobinType(atoi(last_apt_type.c_str()))); apt->setRunwaysAndTaxiways(runways, taxiways, pavements); + apt->setCommStations(commStations); } void parseAirportLine(const vector& token) @@ -466,48 +465,38 @@ private: } } - void parseATISLine(FGCommList *comm_list, const vector& token) + void parseCommLine(int lineId, const vector& token) { if ( rwy_count <= 0 ) { - SG_LOG( SG_GENERAL, SG_ALERT, - "No runways; skipping AWOS for " + last_apt_id); + SG_LOG( SG_GENERAL, SG_ALERT, "No runways; skipping comm for " + last_apt_id); } - -// This assumes/requires that any code-50 line (ATIS or AWOS) - // applies to the preceding code-1 line (airport ID and name) - // and that a full set of code-10 lines (runway descriptors) - // has come between the code-1 and code-50 lines. - // typical code-50 lines: - // 50 11770 ATIS - // 50 11770 AWOS 3 - // This code parallels code found in "operator>>" in ATC.hxx; - // FIXME: unify the code. - ATCData a; - a.geod = SGGeod::fromDegFt(rwy_lon_accum / (double)rwy_count, - rwy_lat_accum / (double)rwy_count, last_apt_elev); - a.range = 50; // give all ATISs small range - a.ident = last_apt_id; - a.name = last_apt_name; + + SGGeod pos = SGGeod::fromDegFt(rwy_lon_accum / (double)rwy_count, + rwy_lat_accum / (double)rwy_count, last_apt_elev); + // short int representing tens of kHz: - a.freq = atoi(token[1].c_str()); - if (token[2] == "ATIS") a.type = ATIS; - else a.type = AWOS; // ASOS same as AWOS + int freqKhz = atoi(token[1].c_str()); + int rangeNm = 50; + FGPositioned::Type ty; + switch (lineId) { + case 50: + ty = FGPositioned::FREQ_AWOS; + if (token[2] == "ATIS") { + ty = FGPositioned::FREQ_ATIS; + } + break; + + case 51: ty = FGPositioned::FREQ_UNICOM; break; + case 52: ty = FGPositioned::FREQ_CLEARANCE; break; + case 53: ty = FGPositioned::FREQ_GROUND; break; + case 54: ty = FGPositioned::FREQ_TOWER; break; + case 55: + case 56: ty = FGPositioned::FREQ_APP_DEP; break; + default: + throw sg_range_exception("unupported apt.dat comm station type"); + } - // generate cartesian coordinates - a.cart = SGVec3d::fromGeod(a.geod); - comm_list->commlist_freq[a.freq].push_back(a); - - SGBucket bucket(a.geod); - int bucknum = bucket.gen_index(); - comm_list->commlist_bck[bucknum].push_back(a); -#if 0 - SG_LOG( SG_GENERAL, SG_ALERT, - "Loaded ATIS/AWOS for airport: " << a.ident - << " lat: " << a.geod.getLatitudeDeg() - << " lon: " << a.geod.getLongitudeDeg() - << " freq: " << a.freq - << " type: " << a.type ); -#endif + commStations.push_back(new flightgear::CommStation(token[2], ty, pos, rangeNm, freqKhz)); } }; @@ -516,12 +505,11 @@ private: // Load the airport data base from the specified aptdb file. The // metar file is used to mark the airports as having metar available // or not. -bool fgAirportDBLoad( const string &aptdb_file, - FGCommList *comm_list, const std::string &metar_file ) +bool fgAirportDBLoad( const string &aptdb_file, const std::string &metar_file ) { APTLoader ld; - ld.parseAPT(aptdb_file, comm_list); + ld.parseAPT(aptdb_file); // // Load the metar.dat file and update apt db with stations that // have metar data. diff --git a/src/Airports/apt_loader.hxx b/src/Airports/apt_loader.hxx index 7e2405638..106268f54 100644 --- a/src/Airports/apt_loader.hxx +++ b/src/Airports/apt_loader.hxx @@ -29,14 +29,11 @@ #include -// forward decls -class FGCommList; - // Load the airport data base from the specified aptdb file. The // metar file is used to mark the airports as having metar available // or not. bool fgAirportDBLoad( const std::string &aptdb_file, - FGCommList *comm_list, const std::string &metar_file ); + const std::string &metar_file ); #endif // _FG_APT_LOADER_HXX diff --git a/src/Airports/runwaybase.cxx b/src/Airports/runwaybase.cxx index 01855347c..951f860e1 100644 --- a/src/Airports/runwaybase.cxx +++ b/src/Airports/runwaybase.cxx @@ -26,6 +26,7 @@ #endif #include +#include #include "runwaybase.hxx" diff --git a/src/Airports/runwaybase.hxx b/src/Airports/runwaybase.hxx index 745d4cb86..ca0a9fb6a 100644 --- a/src/Airports/runwaybase.hxx +++ b/src/Airports/runwaybase.hxx @@ -85,6 +85,7 @@ public: { return _surface_code; } protected: + double _heading; double _length; double _width; diff --git a/src/Airports/runways.cxx b/src/Airports/runways.cxx index c3e48ecbb..bd2df3038 100644 --- a/src/Airports/runways.cxx +++ b/src/Airports/runways.cxx @@ -39,6 +39,8 @@ #include #include +#include +#include using std::string; @@ -197,4 +199,9 @@ std::vector FGRunway::getSTARs() return result; } +flightgear::PositionedBinding* +FGRunway::createBinding(SGPropertyNode* nd) const +{ + return new flightgear::RunwayBinding(this, nd); +} diff --git a/src/Airports/runways.hxx b/src/Airports/runways.hxx index 1c5ab85b1..2cdc2e495 100644 --- a/src/Airports/runways.hxx +++ b/src/Airports/runways.hxx @@ -116,6 +116,8 @@ public: { return _reciprocal; } void setReciprocalRunway(FGRunway* other); + virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const; + /** * Helper to process property data loaded from an ICAO.threshold.xml file */ @@ -130,6 +132,7 @@ public: * Get STARs associared with this runway */ std::vector getSTARs(); + }; #endif // _FG_RUNWAYS_HXX diff --git a/src/Airports/simple.cxx b/src/Airports/simple.cxx index a085fab57..f4f3d1adb 100644 --- a/src/Airports/simple.cxx +++ b/src/Airports/simple.cxx @@ -47,6 +47,8 @@ #include #include #include +#include +#include using std::vector; using namespace flightgear; @@ -662,6 +664,61 @@ Approach* FGAirport::getApproachByIndex(unsigned int aIndex) const return mApproaches[aIndex]; } +class AirportNodeListener : public SGPropertyChangeListener +{ +public: + AirportNodeListener() + { + SGPropertyNode* airports = fgGetNode("/sim/airport"); + airports->addChangeListener(this, false); + } + + virtual void valueChanged(SGPropertyNode*) + { + } + + virtual void childAdded(SGPropertyNode* pr, SGPropertyNode* child) + { + FGAirport* apt = FGAirport::findByIdent(child->getName()); + if (!apt) { + return; + } + + flightgear::PositionedBinding::bind(apt, child); + } +}; + +void FGAirport::installPropertyListener() +{ + new AirportNodeListener; +} + +flightgear::PositionedBinding* +FGAirport::createBinding(SGPropertyNode* nd) const +{ + return new flightgear::AirportBinding(this, nd); +} + +void FGAirport::setCommStations(CommStationList& comms) +{ + mCommStations.swap(comms); + for (unsigned int c=0; csetAirport(this); + } +} + +CommStationList +FGAirport::commStationsOfType(FGPositioned::Type aTy) const +{ + CommStationList result; + for (unsigned int c=0; ctype() == aTy) { + result.push_back(mCommStations[c]); + } + } + return result; +} + // get airport elevation double fgGetAirportElev( const string& id ) { diff --git a/src/Airports/simple.hxx b/src/Airports/simple.hxx index db5c738a4..03d66a190 100644 --- a/src/Airports/simple.hxx +++ b/src/Airports/simple.hxx @@ -50,10 +50,12 @@ namespace flightgear { class STAR; class Approach; class Waypt; - + class CommStation; typedef SGSharedPtr WayptRef; typedef std::vector WayptVec; + + typedef std::vector CommStationList; } @@ -185,6 +187,8 @@ public: unsigned int numApproaches() const; flightgear::Approach* getApproachByIndex(unsigned int aIndex) const; + static void installPropertyListener(); + /** * Syntactic wrapper around FGPositioned::findClosest - find the closest * match for filter, and return it cast to FGAirport. The default filter @@ -228,6 +232,14 @@ public: */ std::pair selectSTAR(const SGGeod& aOrigin, FGRunway* aRwy); + virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const; + + void setCommStations(flightgear::CommStationList& comms); + + flightgear::CommStationList commStationsOfType(FGPositioned::Type aTy) const; + + const flightgear::CommStationList& commStations() const + { return mCommStations; } private: typedef std::vector::const_iterator Runway_iterator; /** @@ -275,6 +287,8 @@ private: std::vector mSIDs; std::vector mSTARs; std::vector mApproaches; + + flightgear::CommStationList mCommStations; }; // find basic airport location info from airport database diff --git a/src/Instrumentation/KLN89/kln89_page_apt.cxx b/src/Instrumentation/KLN89/kln89_page_apt.cxx index be9a4d721..95b34cfe6 100644 --- a/src/Instrumentation/KLN89/kln89_page_apt.cxx +++ b/src/Instrumentation/KLN89/kln89_page_apt.cxx @@ -27,58 +27,14 @@ #include "kln89_page_apt.hxx" +#include #include -#include +#include #include
#include #include -// This function is copied from Airports/runways.cxx -// TODO - Make the original properly available and remove this instance!!!! -// Return reverse rwy number -// eg 01 -> 19 -// 03L -> 21R -static string GetReverseRunwayNo(string rwyno) { - // cout << "Original rwyno = " << rwyNo << '\n'; - - // standardize input number - string tmp = rwyno.substr(1, 1); - if (( tmp == "L" || tmp == "R" || tmp == "C" ) || (rwyno.size() == 1)) { - tmp = rwyno; - rwyno = "0" + tmp; - SG_LOG( SG_GENERAL, SG_INFO, - "Standardising rwy number from " << tmp << " to " << rwyno ); - } - - char buf[4]; - int rn = atoi(rwyno.substr(0,2).c_str()); - rn += 18; - while(rn > 36) { - rn -= 36; - } - sprintf(buf, "%02i", rn); - if(rwyno.size() == 3) { - if(rwyno.substr(2,1) == "L") { - buf[2] = 'R'; - buf[3] = '\0'; - } else if (rwyno.substr(2,1) == "R") { - buf[2] = 'L'; - buf[3] = '\0'; - } else if (rwyno.substr(2,1) == "C") { - buf[2] = 'C'; - buf[3] = '\0'; - } else if (rwyno.substr(2,1) == "T") { - buf[2] = 'T'; - buf[3] = '\0'; - } else { - SG_LOG(SG_GENERAL, SG_ALERT, "Unknown runway code " - << rwyno << " passed to GetReverseRunwayNo(...)"); - } - } - return(buf); -} - KLN89AptPage::KLN89AptPage(KLN89* parent) : KLN89Page(parent) { _nSubPages = 8; @@ -230,7 +186,8 @@ void KLN89AptPage::Update(double dt) { string s = _aptRwys[i]->ident(); _kln89->DrawText(s, 2, 9, 3); _kln89->DrawText("/", 2, 12, 3); - _kln89->DrawText(GetReverseRunwayNo(s), 2, 13, 3); + string recipIdent = _aptRwys[i]->reciprocalRunway()->ident(); + _kln89->DrawText(recipIdent, 2, 13, 3); // Length s = GPSitoa(int(float(_aptRwys[i]->lengthFt()) * (_kln89->_altUnits == GPS_ALT_UNITS_FT ? 1.0 : SG_FEET_TO_METER) + 0.5)); _kln89->DrawText(s, 2, 5 - s.size(), 2); @@ -278,7 +235,8 @@ void KLN89AptPage::Update(double dt) { string s = _aptRwys[i]->ident(); _kln89->DrawText(s, 2, 9, 1); _kln89->DrawText("/", 2, 12, 1); - _kln89->DrawText(GetReverseRunwayNo(s), 2, 13, 1); + string recip = _aptRwys[i]->reciprocalRunway()->ident(); + _kln89->DrawText(recip, 2, 13, 1); // Length s = GPSitoa(int(float(_aptRwys[i]->lengthFt()) * (_kln89->_altUnits == GPS_ALT_UNITS_FT ? 1.0 : SG_FEET_TO_METER) + 0.5)); _kln89->DrawText(s, 2, 5 - s.size(), 0); @@ -499,38 +457,35 @@ void KLN89AptPage::SetId(const string& s) { // Update the cached airport details void KLN89AptPage::UpdateAirport(const string& id) { // Frequencies - _aptFreqs.clear(); - ATCData ad; - AptFreq aq; - //cout << "UpdateAirport called, id = " << id << '\n'; - // TODO - the logic below only returns one service per type per airport - they can be on more than one freq though. - if(current_commlist->FindByCode(id, ad, ATIS)) { - //cout << "Found ATIS\n"; - aq.service = "ATIS*"; - aq.freq = ad.freq; - _aptFreqs.push_back(aq); - } - if(current_commlist->FindByCode(id, ad, GROUND)) { - aq.service = "GRND*"; - aq.freq = ad.freq; - _aptFreqs.push_back(aq); - } - if(current_commlist->FindByCode(id, ad, TOWER)) { - aq.service = "TWR *"; - aq.freq = ad.freq; - _aptFreqs.push_back(aq); - } - if(current_commlist->FindByCode(id, ad, APPROACH)) { - aq.service = "APR"; - aq.freq = ad.freq; - _aptFreqs.push_back(aq); - } + _aptFreqs.clear(); + + const FGAirport* apt = fgFindAirportID(id); + if (!apt) { + throw sg_exception("UpdateAirport: unknown airport id " + id); + } + + for (unsigned int c=0; ccommStations().size(); ++c) { + flightgear::CommStation* comm = apt->commStations()[c]; + AptFreq aq; + aq.freq = comm->freqKHz(); + switch (comm->type()) { + case FGPositioned::FREQ_ATIS: + aq.service = "ATIS*"; break; + case FGPositioned::FREQ_GROUND: + aq.service = "GRND*"; break; + case FGPositioned::FREQ_TOWER: + aq.service = "TWR *"; break; + case FGPositioned::FREQ_APP_DEP: + aq.service = "APR *"; break; + default: + continue; + } + } + _nFreqPages = (unsigned int)ceil((float(_aptFreqs.size())) / 3.0f); // Runways _aptRwys.clear(); - const FGAirport* apt = fgFindAirportID(id); - assert(apt); // build local array, longest runway first for (unsigned int r=0; rnumRunways(); ++r) { diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index 50329b39f..9fd101b65 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -75,8 +75,6 @@ #include #include -#include -#include #include #include @@ -1084,15 +1082,10 @@ fgInitNav () SGPath p_metar( globals->get_fg_root() ); p_metar.append( "Airports/metar.dat" ); -// Initialise the frequency search map BEFORE reading -// the airport database: - - - - current_commlist = new FGCommList; - current_commlist->init( globals->get_fg_root() ); - fgAirportDBLoad( aptdb.str(), current_commlist, p_metar.str() ); - + fgAirportDBLoad( aptdb.str(), p_metar.str() ); + FGAirport::installPropertyListener(); + FGPositioned::installCommands(); + FGNavList *navlist = new FGNavList; FGNavList *loclist = new FGNavList; FGNavList *gslist = new FGNavList; @@ -1423,12 +1416,6 @@ bool fgInitSubsystems() { globals->set_ATC_mgr(new FGATCMgr); globals->get_ATC_mgr()->init(); - //////////////////////////////////////////////////////////////////// - // Initialise the ATIS Manager - //////////////////////////////////////////////////////////////////// - globals->add_subsystem("atis", new FGAtisManager, SGSubsystemMgr::POST_FDM); - - //////////////////////////////////////////////////////////////////// // Initialize multiplayer subsystem //////////////////////////////////////////////////////////////////// diff --git a/src/Navaids/CMakeLists.txt b/src/Navaids/CMakeLists.txt index cf8ce4ad7..8f2747270 100644 --- a/src/Navaids/CMakeLists.txt +++ b/src/Navaids/CMakeLists.txt @@ -13,6 +13,7 @@ set(SOURCES route.cxx routePath.cxx waypoint.cxx + PositionedBinding.cxx ) flightgear_component(Navaids "${SOURCES}") \ No newline at end of file diff --git a/src/Navaids/PositionedBinding.cxx b/src/Navaids/PositionedBinding.cxx new file mode 100644 index 000000000..758491cc5 --- /dev/null +++ b/src/Navaids/PositionedBinding.cxx @@ -0,0 +1,169 @@ +#include "PositionedBinding.hxx" + +#include + +#include +#include +#include + +#include
+#include +#include +#include +#include + +typedef std::map BindingMap; +static BindingMap static_bindings; + +namespace { + +class PropertyDeleteObserver : public SGPropertyChangeListener +{ +public: + virtual void childRemoved(SGPropertyNode*, SGPropertyNode* node) + { + BindingMap::iterator it = static_bindings.find(node); + if (it != static_bindings.end()) { + SG_LOG(SG_GENERAL, SG_INFO, "saw remove of:" << node->getPath() << ", deleting binding"); + delete it->second; + static_bindings.erase(it); + } + } +}; + +static PropertyDeleteObserver* static_deleteObserver = NULL; + +} // of anonymous namespace + +namespace flightgear +{ + +PositionedBinding::PositionedBinding(const FGPositioned* pos, SGPropertyNode* nd) : + p(const_cast(pos)), + tied(nd) +{ + if (!static_deleteObserver) { + static_deleteObserver = new PropertyDeleteObserver; + globals->get_props()->addChangeListener(static_deleteObserver, false); + } + + nd->setDoubleValue("latitude-deg", p->latitude()); + nd->setDoubleValue("longitude-deg", p->longitude()); + + if (p->elevation() > -1000) { + nd->setDoubleValue("elevation-ft", p->elevation()); + } + + nd->setStringValue("ident", p->ident()); + if (!p->name().empty()) { + nd->setStringValue("name", p->name()); + } + + nd->setStringValue("type", FGPositioned::nameForType(p->type())); +} + +PositionedBinding::~PositionedBinding() +{ + tied.Untie(); +} + +void PositionedBinding::bind(FGPositioned* pos, SGPropertyNode* node) +{ + BindingMap::iterator it = static_bindings.find(node); + if (it != static_bindings.end()) { + throw sg_exception("duplicate positioned binding", node->getPath()); + } + + PositionedBinding* binding = pos->createBinding(node); + static_bindings.insert(it, std::make_pair(node, binding)); +} + +NavaidBinding::NavaidBinding(const FGNavRecord* nav, SGPropertyNode* nd) : + PositionedBinding(nav, nd) +{ + FGPositioned::Type ty = nav->type(); + if (ty == FGPositioned::NDB) { + nd->setDoubleValue("frequency-khz", nav->get_freq() / 100.0); + } else { + nd->setDoubleValue("frequency-mhz", nav->get_freq() / 100.0); + } + + if ((ty == FGPositioned::LOC) || (ty == FGPositioned::ILS)) { + nd->setDoubleValue("loc-course-deg", nav->get_multiuse()); + } + + if (ty == FGPositioned::GS) { + nd->setDoubleValue("gs-angle-deg", nav->get_multiuse()); + } + + nd->setDoubleValue("range-nm", nav->get_range()); + + if (nav->runway()) { + // don't want to create a cycle in the graph, so we don't re-bind + // the airport/runway node here - just expose the IDs + nd->setStringValue("airport", nav->runway()->airport()->ident()); + nd->setStringValue("runway", nav->runway()->ident()); + } +}; + +RunwayBinding::RunwayBinding(const FGRunway* rwy, SGPropertyNode* nd) : + PositionedBinding(rwy, nd) +{ + nd->setDoubleValue("length-ft", rwy->lengthFt()); + nd->setDoubleValue("length-m", rwy->lengthM()); + nd->setDoubleValue("width-ft", rwy->widthFt()); + nd->setDoubleValue("width-m", rwy->widthM()); + nd->setDoubleValue("heading-deg", rwy->headingDeg()); + nd->setBoolValue("hard-surface", rwy->isHardSurface()); + + nd->setDoubleValue("threshold-displacement-m", rwy->displacedThresholdM()); + nd->setDoubleValue("stopway-m", rwy->stopwayM()); + + if (rwy->ILS()) { + SGPropertyNode* ilsNode = nd->getChild("ils", 0, true); + PositionedBinding::bind(rwy->ILS(), ilsNode); + } +} + +AirportBinding::AirportBinding(const FGAirport* apt, SGPropertyNode* nd) : + PositionedBinding(apt, nd) +{ + nd->setIntValue("num-runways", apt->numRunways()); + + SGGeod tower = apt->getTowerLocation(); + nd->setDoubleValue("tower/latitude-deg", tower.getLatitudeDeg()); + nd->setDoubleValue("tower/longitude-deg", tower.getLongitudeDeg()); + nd->setDoubleValue("tower/elevation-ft", tower.getElevationFt()); + + for (unsigned int r=0; rnumRunways(); ++r) { + SGPropertyNode* rn = nd->getChild("runway", r, true); + FGRunway* rwy = apt->getRunwayByIndex(r); + PositionedBinding::bind(rwy, rn); + } + + for (unsigned int c=0; ccommStations().size(); ++c) { + flightgear::CommStation* comm = apt->commStations()[c]; + std::string tynm = FGPositioned::nameForType(comm->type()); + int count = nd->getChildren(tynm).size(); + + SGPropertyNode* commNode = nd->getChild(tynm, count, true); + commNode->setStringValue("ident", comm->ident()); + commNode->setDoubleValue("frequency-mhz", comm->freqMHz()); + } +} + +CommStationBinding::CommStationBinding(const CommStation* sta, SGPropertyNode* node) : + PositionedBinding(sta, node) +{ + node->setIntValue("range-nm", sta->rangeNm()); + node->setDoubleValue("frequency-mhz", sta->freqMHz()); + + if (sta->airport()) { + // don't want to create a cycle in the graph, so we don't re-bind + // the airport/runway node here - just expose the IDs + node->setStringValue("airport", sta->airport()->ident()); + } +} + +} // of namespace flightgear + diff --git a/src/Navaids/PositionedBinding.hxx b/src/Navaids/PositionedBinding.hxx new file mode 100644 index 000000000..ee4df7d19 --- /dev/null +++ b/src/Navaids/PositionedBinding.hxx @@ -0,0 +1,63 @@ +#ifndef FG_POSITIONED_BINDING_HXX +#define FG_POSITIONED_BINDING_HXX + +#include + +#include "positioned.hxx" + +// forward decls +class FGNavRecord; +class FGRunway; +class FGAirport; + +namespace flightgear +{ + +// forward decls +class CommStation; + +class PositionedBinding +{ +public: + virtual ~PositionedBinding(); + + static void bind(FGPositioned* pos, SGPropertyNode* node); + + + PositionedBinding(const FGPositioned* pos, SGPropertyNode* node); + +protected: + FGPositionedRef p; // bindings own a reference to their positioned + simgear::TiedPropertyList tied; + +private: + +}; + +class NavaidBinding : public PositionedBinding +{ +public: + NavaidBinding(const FGNavRecord* nav, SGPropertyNode* node); +}; + +class RunwayBinding : public PositionedBinding +{ +public: + RunwayBinding(const FGRunway* rwy, SGPropertyNode* node); +}; + +class AirportBinding : public PositionedBinding +{ +public: + AirportBinding(const FGAirport* apt, SGPropertyNode* node); +}; + +class CommStationBinding : public PositionedBinding +{ +public: + CommStationBinding(const CommStation* sta, SGPropertyNode* node); +}; + +} // of namespace flightgear + +#endif // of FG_POSITIONED_BINDING_HXX diff --git a/src/Navaids/navrecord.cxx b/src/Navaids/navrecord.cxx index 03317a57d..5edc64ef1 100644 --- a/src/Navaids/navrecord.cxx +++ b/src/Navaids/navrecord.cxx @@ -41,6 +41,7 @@ #include #include
+#include FGNavRecord::FGNavRecord(Type aTy, const std::string& aIdent, const std::string& aName, const SGGeod& aPos, @@ -187,6 +188,13 @@ double FGNavRecord::localizerWidth() const } +flightgear::PositionedBinding* +FGNavRecord::createBinding(SGPropertyNode* nd) const +{ + return new flightgear::NavaidBinding(this, nd); +} + + FGTACANRecord::FGTACANRecord(void) : channel(""), freq(0) diff --git a/src/Navaids/navrecord.hxx b/src/Navaids/navrecord.hxx index 09abb6e97..f58d5a167 100644 --- a/src/Navaids/navrecord.hxx +++ b/src/Navaids/navrecord.hxx @@ -89,12 +89,17 @@ public: */ FGRunway* runway() const { return mRunway; } + virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const; + /** * return the localizer width, in degrees * computation is based up ICAO stdandard width at the runway threshold * see implementation for further details. */ double localizerWidth() const; + + void bindToNode(SGPropertyNode* nd) const; + void unbindFromNode(SGPropertyNode* nd) const; }; class FGTACANRecord : public SGReferenced { diff --git a/src/Navaids/positioned.cxx b/src/Navaids/positioned.cxx index b74e4e877..045839da3 100644 --- a/src/Navaids/positioned.cxx +++ b/src/Navaids/positioned.cxx @@ -35,11 +35,16 @@ #include // for osg::isNaN #include +#include #include #include #include +#include +#include - +#include "PositionedBinding.hxx" +#include "Airports/simple.hxx" +#include "Main/fg_props.hxx" typedef std::multimap NamedPositionedIndex; typedef std::pair NamedIndexRange; @@ -628,7 +633,15 @@ FGPositioned::Type FGPositioned::typeFromName(const std::string& aName) {"fix", FIX}, {"tacan", TACAN}, {"dme", DME}, + {"atis", FREQ_ATIS}, + {"awos", FREQ_AWOS}, + {"tower", FREQ_TOWER}, + {"ground", FREQ_GROUND}, + {"approach", FREQ_APP_DEP}, + {"departure", FREQ_APP_DEP}, // aliases + {"gnd", FREQ_GROUND}, + {"twr", FREQ_TOWER}, {"waypoint", WAYPOINT}, {"apt", AIRPORT}, {"arpt", AIRPORT}, @@ -672,11 +685,24 @@ const char* FGPositioned::nameForType(Type aTy) case WAYPOINT: return "waypoint"; case DME: return "dme"; case TACAN: return "tacan"; + case FREQ_TOWER: return "tower"; + case FREQ_ATIS: return "atis"; + case FREQ_AWOS: return "awos"; + case FREQ_GROUND: return "ground"; + case FREQ_CLEARANCE: return "clearance"; + case FREQ_UNICOM: return "unicom"; + case FREQ_APP_DEP: return "approach-departure"; default: return "unknown"; } } +flightgear::PositionedBinding* +FGPositioned::createBinding(SGPropertyNode* node) const +{ + return new flightgear::PositionedBinding(this, node); +} + /////////////////////////////////////////////////////////////////////////////// // search / query functions @@ -811,3 +837,145 @@ FGPositioned::sortByRange(List& aResult, const SGGeod& aPos) aResult[i] = r[i].get(); } } + +FGPositioned::Filter* createSearchFilter(const SGPropertyNode* arg) +{ + string sty(arg->getStringValue("type", 0)); + FGPositioned::Type ty = FGPositioned::typeFromName(sty); + double minRunwayLenFt = arg->getDoubleValue("min-runway-length-ft", -1.0); + + if ((ty == FGPositioned::AIRPORT) && (minRunwayLenFt > 0.0)) { + return new FGAirport::HardSurfaceFilter(minRunwayLenFt); + } else if (ty != FGPositioned::INVALID) { + FGPositioned::TypeFilter* tf = new FGPositioned::TypeFilter(ty); + + for (int t=1; arg->hasChild("type", t); ++t) { + sty = arg->getChild("type", t)->getStringValue(); + tf->addType(FGPositioned::typeFromName(sty)); + } + + return tf; + } + + return NULL; +} + +SGGeod commandSearchPos(const SGPropertyNode* arg) +{ + if (arg->hasChild("longitude-deg") && arg->hasChild("latitude-deg")) { + return SGGeod::fromDeg(arg->getDoubleValue("longitude-deg"), + arg->getDoubleValue("latitude-deg")); + } + + // use current viewer/aircraft position + return SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"), + fgGetDouble("/position/latitude-deg")); +} + +void commandClearExisting(const SGPropertyNode* arg) +{ + if (arg->getBoolValue("clear", true)) { + // delete all existing result children from their parent + string resultPath = arg->getStringValue("results"); + SGPropertyNode* n = fgGetNode(resultPath.c_str(), 0, true); + SGPropertyNode* pr = n->getParent(); + pr->removeChildren(n->getName(), false /* keep=false, i.e delete nodes */); + } +} + +bool commandFindClosest(const SGPropertyNode* arg) +{ + int n = arg->getIntValue("max-results", 1); + if ((n < 1) || (n > 100)) { + SG_LOG(SG_GENERAL, SG_WARN, "commandFindClosest: max-results invalid:" << n); + return false; + } + + string resultPath = arg->getStringValue("results"); + if (resultPath.empty()) { + SG_LOG(SG_GENERAL, SG_WARN, "commandFindClosest: no results path defined"); + return false; + } + + std::auto_ptr filt(createSearchFilter(arg)); +// cap search range, since huge ranges will overload everything + double cutoff = arg->getDoubleValue("cutoff-nm", 400.0); + SG_CLAMP_RANGE(cutoff, 0.0, 1000.0); + + SGGeod pos = commandSearchPos(arg); + commandClearExisting(arg); + + FGPositioned::List results = FGPositioned::findClosestN(pos, n, cutoff, filt.get()); + for (unsigned int i=0; igetStringValue("results"); + if (resultPath.empty()) { + SG_LOG(SG_GENERAL, SG_WARN, "commandFindByIdent: no results path defined"); + return false; + } + + std::auto_ptr filt(createSearchFilter(arg)); + SGGeod pos = commandSearchPos(arg); + commandClearExisting(arg); + + FGPositioned::List results; + bool exact = arg->getBoolValue("exact", true); + if (arg->hasChild("name")) { + results = FGPositioned::findAllWithName(arg->getStringValue("name"), filt.get(), exact); + } else if (arg->hasChild("ident")) { + results = FGPositioned::findAllWithName(arg->getStringValue("ident"), filt.get(), exact); + } else { + SG_LOG(SG_GENERAL, SG_WARN, "commandFindByIdent: no search term defined"); + return false; + } + + bool orderByRange = arg->getBoolValue("order-by-distance", true); + if (orderByRange) { + FGPositioned::sortByRange(results, pos); + } + + for (unsigned int i=0; iaddCommand("find-nearest", commandFindClosest); + SGCommandMgr::instance()->addCommand("find-by-ident", commandFindByIdent); +} + +FGPositioned::TypeFilter::TypeFilter(Type aTy) +{ + types.push_back(aTy); +} + +void FGPositioned::TypeFilter::addType(Type aTy) +{ + types.push_back(aTy); +} + +bool +FGPositioned::TypeFilter::pass(FGPositioned* aPos) const +{ + std::vector::const_iterator it = types.begin(), + end = types.end(); + for (; it != end; ++it) { + return aPos->type() == *it; + } + + return false; +} + diff --git a/src/Navaids/positioned.hxx b/src/Navaids/positioned.hxx index f6f61229a..de5a31322 100644 --- a/src/Navaids/positioned.hxx +++ b/src/Navaids/positioned.hxx @@ -27,9 +27,15 @@ #include class FGPositioned; +class SGPropertyNode; typedef SGSharedPtr FGPositionedRef; +namespace flightgear +{ + class PositionedBinding; +} + class FGPositioned : public SGReferenced { public: @@ -56,9 +62,14 @@ public: DME, TACAN, OBSTACLE, - FREQ_GND, - FREQ_TWR, + FREQ_GROUND, + FREQ_TOWER, FREQ_ATIS, + FREQ_AWOS, + FREQ_APP_DEP, + FREQ_ENROUTE, + FREQ_CLEARANCE, + FREQ_UNICOM, LAST_TYPE } Type; @@ -97,6 +108,9 @@ public: double elevation() const { return mPosition.getElevationFt(); } + + virtual flightgear::PositionedBinding* createBinding(SGPropertyNode* nd) const; + /** * Predicate class to support custom filtering of FGPositioned queries * Default implementation of this passes any FGPositioned instance. @@ -135,13 +149,15 @@ public: class TypeFilter : public Filter { public: - TypeFilter(Type aTy) : mType(aTy) { ; } - virtual bool pass(FGPositioned* aPos) const - { return (mType == aPos->type()); } + TypeFilter(Type aTy); + virtual bool pass(FGPositioned* aPos) const; + void addType(Type aTy); private: - const Type mType; + std::vector types; }; + static void installCommands(); + static List findWithinRange(const SGGeod& aPos, double aRangeNm, Filter* aFilter = NULL); static FGPositionedRef findClosestWithIdent(const std::string& aIdent, const SGGeod& aPos, Filter* aFilter = NULL); From f1a3cedb2fc0098514914275f4a4dcf5fbc966bf Mon Sep 17 00:00:00 2001 From: Frederic Bouvier Date: Wed, 1 Jun 2011 20:25:53 +0200 Subject: [PATCH 6/6] Fix win32 build --- projects/VC90/FlightGear/FlightGear.vcproj | 86 +++++++++++----------- src/Navaids/PositionedBinding.cxx | 4 + 2 files changed, 47 insertions(+), 43 deletions(-) diff --git a/projects/VC90/FlightGear/FlightGear.vcproj b/projects/VC90/FlightGear/FlightGear.vcproj index 98fde43d6..084a5531f 100644 --- a/projects/VC90/FlightGear/FlightGear.vcproj +++ b/projects/VC90/FlightGear/FlightGear.vcproj @@ -569,14 +569,6 @@ RelativePath="..\..\..\src\ATCDCL\atis.hxx" > - - - - - - - - @@ -2489,6 +2473,14 @@ RelativePath="..\..\..\src\FDM\NullFDM.hxx" > + + + + + + + + @@ -3220,7 +3220,7 @@ - + @@ -3381,6 +3381,14 @@ RelativePath="..\..\..\src\Environment\fgwind.hxx" > + + + + @@ -3405,6 +3413,14 @@ RelativePath="..\..\..\src\Environment\precipitation_mgr.hxx" > + + + + @@ -3429,22 +3445,6 @@ RelativePath="..\..\..\src\Environment\terrainsampler.hxx" > - - - - - - - - + + + + @@ -3800,14 +3808,6 @@ - - - -