1 // navrecord.cxx -- generic vor/dme/ndb class
3 // Written by Curtis Olson, started May 2004.
5 // Copyright (C) 2004 Curtis L. Olson - http://www.flightgear.org/~curt
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
29 #include <simgear/misc/sgstream.hxx>
30 #include <simgear/structure/exception.hxx>
31 #include <simgear/misc/strutils.hxx>
32 #include <simgear/debug/logstream.hxx>
34 #include "Navaids/navrecord.hxx"
35 #include "Airports/simple.hxx"
36 #include "Airports/runways.hxx"
37 #include "Main/fg_props.hxx"
39 FGNavRecord::FGNavRecord(Type aTy, const std::string& aIdent,
40 const std::string& aName,
41 double lat, double lon, double aElevFt,
42 int aFreq, int aRange, double aMultiuse) :
43 FGPositioned(aTy, aIdent, lat, lon, aElevFt),
51 initAirportRelation();
53 // Ranges are included with the latest data format, no need to
54 // assign our own defaults, unless the range is not set for some
57 SG_LOG(SG_GENERAL, SG_WARN, "navaid " << ident() << " has no range set, using defaults");
61 range = FG_NAV_DEFAULT_RANGE;
67 range = FG_LOC_DEFAULT_RANGE;
71 range = FG_DME_DEFAULT_RANGE;
75 range = FG_LOC_DEFAULT_RANGE;
81 SGVec3d FGNavRecord::get_cart() const
83 return SGVec3d::fromGeod(geod());
87 static FGPositioned::Type
88 mapRobinTypeToFGPType(int aTy)
92 case 2: return FGPositioned::NDB;
93 case 3: return FGPositioned::VOR;
94 case 4: return FGPositioned::LOC;
95 case 5: return FGPositioned::ILS;
96 case 6: return FGPositioned::GS;
97 case 7: return FGPositioned::OM;
98 case 8: return FGPositioned::MM;
99 case 9: return FGPositioned::IM;
101 case 13: return FGPositioned::DME;
102 case 99: return FGPositioned::INVALID; // end-of-file code
104 throw sg_range_exception("Got a nav.dat type we don't recgonize", "FGNavRecord::createFromStream");
108 FGNavRecord* FGNavRecord::createFromStream(std::istream& aStream)
113 return NULL; // happens with, eg, carrier_nav.dat
116 Type type = mapRobinTypeToFGPType(rawType);
117 if (type == INVALID) return NULL;
119 double lat, lon, elev_ft, multiuse;
121 std::string apt_id, name, ident;
122 aStream >> lat >> lon >> elev_ft >> freq >> range >> multiuse >> ident;
123 getline(aStream, name);
125 // silently multiply adf frequencies by 100 so that adf
126 // vs. nav/loc frequency lookups can use the same code.
131 FGNavRecord* result = new FGNavRecord(type, ident,
132 simgear::strutils::strip(name),
133 lat, lon, elev_ft, freq, range, multiuse);
138 void FGNavRecord::initAirportRelation()
140 if (type() < ILS || type() > IM) {
141 return; // not airport-located
144 vector<string> parts = simgear::strutils::split(name);
146 const FGAirport* apt = fgFindAirportID(apt_id);
149 SG_LOG(SG_GENERAL, SG_WARN, "navaid " << ident() << " associated with bogus airport ID:" << apt_id);
153 // fudge elevation to the field elevation if it's not specified
154 if (fabs(elevation()) < 0.01) {
155 mPosition.setElevationFt(apt->getElevation());
158 // align localizers with their runway
159 if ((type() == ILS) || (type() == LOC)) {
160 if (!fgGetBool("/sim/navdb/localizers/auto-align", true)) {
164 if (parts.size() < 2) {
165 SG_LOG(SG_GENERAL, SG_ALERT, "can't parse navaid " << ident()
166 << " name for airport/runway:" << name);
171 = fgGetDouble( "/sim/navdb/localizers/auto-align-threshold-deg",
173 FGRunway* runway = apt->getRunwayByIdent(parts[1]);
174 alignLocaliserWithRunway(runway, threshold);
178 void FGNavRecord::alignLocaliserWithRunway(FGRunway* aRunway, double aThreshold)
180 // find the distance from the threshold to the localizer
181 SGGeod runwayThreshold(aRunway->threshold());
182 double dist, az1, az2;
183 SGGeodesy::inverse(mPosition, runwayThreshold, az1, az2, dist);
185 // back project that distance along the runway center line
186 SGGeod newPos = aRunway->pointOnCenterline(dist);
188 double hdg_diff = get_multiuse() - aRunway->headingDeg();
190 // clamp to [-180.0 ... 180.0]
191 if ( hdg_diff < -180.0 ) {
193 } else if ( hdg_diff > 180.0 ) {
197 if ( fabs(hdg_diff) <= aThreshold ) {
199 set_multiuse( aRunway->headingDeg() );
201 SG_LOG(SG_GENERAL, SG_WARN, "localizer:" << ident() << ", aligning with runway "
202 << aRunway->_rwy_no << " exceeded heading threshold");
206 FGTACANRecord::FGTACANRecord(void) :
214 operator >> ( std::istream& in, FGTACANRecord& n )
216 in >> n.channel >> n.freq ;
217 //getline( in, n.name );