]> git.mxchange.org Git - flightgear.git/blob - src/Navaids/navrecord.cxx
1e3800ae4aae01ff51ab840fed808085af0534bf
[flightgear.git] / src / Navaids / navrecord.cxx
1 // navrecord.cxx -- generic vor/dme/ndb class
2 //
3 // Written by Curtis Olson, started May 2004.
4 //
5 // Copyright (C) 2004  Curtis L. Olson - http://www.flightgear.org/~curt
6 //
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.
11 //
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.
16 //
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.
20 //
21 // $Id$
22
23 #ifdef HAVE_CONFIG_H
24   #include "config.h"
25 #endif
26
27 #include <istream>
28
29 #include <simgear/misc/sgstream.hxx>
30 #include <simgear/structure/exception.hxx>
31 #include <simgear/misc/strutils.hxx>
32 #include <simgear/debug/logstream.hxx>
33
34 #include "Navaids/navrecord.hxx"
35 #include "Airports/simple.hxx"
36 #include "Airports/runways.hxx"
37 #include "Main/fg_props.hxx"
38
39 FGNavRecord::FGNavRecord(Type aTy, const std::string& aIdent, 
40   const std::string& aName, const SGGeod& aPos,
41   int aFreq, int aRange, double aMultiuse) :
42   FGPositioned(aTy, aIdent, aPos),
43   freq(aFreq),
44   range(aRange),
45   multiuse(aMultiuse),
46   _name(aName),
47   serviceable(true),
48   trans_ident(aIdent)
49
50   initAirportRelation();
51
52   // Ranges are included with the latest data format, no need to
53   // assign our own defaults, unless the range is not set for some
54   // reason.
55   if (range < 0.1) {
56     SG_LOG(SG_GENERAL, SG_WARN, "navaid " << ident() << " has no range set, using defaults");
57     switch (type()) {
58     case NDB:
59     case VOR:
60       range = FG_NAV_DEFAULT_RANGE;
61       break;
62     
63     case LOC:
64     case ILS:
65     case GS:
66       range = FG_LOC_DEFAULT_RANGE;
67       break;
68       
69     case DME:
70       range = FG_DME_DEFAULT_RANGE;
71       break;
72     
73     default:
74       range = FG_LOC_DEFAULT_RANGE;
75     }
76   }
77   
78 }
79
80 static FGPositioned::Type
81 mapRobinTypeToFGPType(int aTy)
82 {
83   switch (aTy) {
84  // case 1:
85   case 2: return FGPositioned::NDB;
86   case 3: return FGPositioned::VOR;
87   case 4: return FGPositioned::LOC;
88   case 5: return FGPositioned::ILS;
89   case 6: return FGPositioned::GS;
90   case 7: return FGPositioned::OM;
91   case 8: return FGPositioned::MM;
92   case 9: return FGPositioned::IM;
93   case 12:
94   case 13: return FGPositioned::DME;
95   case 99: return FGPositioned::INVALID; // end-of-file code
96   default:
97     throw sg_range_exception("Got a nav.dat type we don't recognize", "FGNavRecord::createFromStream");
98   }
99 }
100
101 FGNavRecord* FGNavRecord::createFromStream(std::istream& aStream)
102 {
103   int rawType;
104   aStream >> rawType;
105   if (aStream.eof()) {
106     return NULL; // happens with, eg, carrier_nav.dat
107   }
108   
109   Type type = mapRobinTypeToFGPType(rawType);
110   if (type == INVALID) return NULL;
111   
112   double lat, lon, elev_ft, multiuse;
113   int freq, range;
114   std::string name, ident;
115   aStream >> lat >> lon >> elev_ft >> freq >> range >> multiuse >> ident;
116   getline(aStream, name);
117   
118   // silently multiply adf frequencies by 100 so that adf
119   // vs. nav/loc frequency lookups can use the same code.
120   if (type == NDB) {
121     freq *= 100;
122   }
123   
124   // ensure marker beacons are anonymous, so they don't get added to the
125   // name index
126   if ((type >= OM) && (type <= IM)) {
127     ident.clear();
128   }
129   
130   FGNavRecord* result = new FGNavRecord(type, ident,
131     simgear::strutils::strip(name), SGGeod::fromDegFt(lon, lat, elev_ft),
132     freq, range, multiuse);
133     
134   return result;
135 }
136
137 void FGNavRecord::initAirportRelation()
138 {
139   if ((type() < ILS) || (type() > IM)) {
140     return; // not airport-located
141   }
142   
143   vector<string> parts = simgear::strutils::split(_name);
144   if (parts.size() < 2) {
145     SG_LOG(SG_GENERAL, SG_WARN, "navaid has malformed name:" << _name);
146     return;
147   }
148   
149   const FGAirport* apt = fgFindAirportID(parts[0]);
150   
151   if (!apt) {
152     SG_LOG(SG_GENERAL, SG_WARN, "navaid " << _name << " associated with bogus airport ID:" << parts[0]);
153     return;
154   }
155   
156   runway = apt->getRunwayByIdent(parts[1]);
157   if (!runway) {
158     SG_LOG(SG_GENERAL, SG_WARN, "navaid " << _name << " associated with bogus runway ID:" << parts[1]);
159     return;
160   }
161     
162   // fudge elevation to the field elevation if it's not specified
163   if (fabs(elevation()) < 0.01) {
164     mPosition.setElevationFt(apt->getElevation());
165   }
166   
167   // align localizers with their runway
168   if ((type() == ILS) || (type() == LOC)) {
169     if (!fgGetBool("/sim/navdb/localizers/auto-align", true)) {
170       return;
171     }
172     
173    double threshold 
174      = fgGetDouble( "/sim/navdb/localizers/auto-align-threshold-deg", 5.0 );
175     alignLocaliserWithRunway(runway, threshold);
176   }
177 }
178
179 void FGNavRecord::alignLocaliserWithRunway(FGRunway* aRunway, double aThreshold)
180 {
181 // find the distance from the threshold to the localizer
182   SGGeod runwayThreshold(aRunway->threshold());
183   double dist, az1, az2;
184   SGGeodesy::inverse(mPosition, runwayThreshold, az1, az2, dist);
185
186 // back project that distance along the runway center line
187   SGGeod newPos = aRunway->pointOnCenterline(dist);
188
189   double hdg_diff = get_multiuse() - aRunway->headingDeg();
190
191   // clamp to [-180.0 ... 180.0]
192   if ( hdg_diff < -180.0 ) {
193       hdg_diff += 360.0;
194   } else if ( hdg_diff > 180.0 ) {
195       hdg_diff -= 360.0;
196   }
197
198   if ( fabs(hdg_diff) <= aThreshold ) {
199     mPosition = newPos;
200     set_multiuse( aRunway->headingDeg() );
201   } else {
202     SG_LOG(SG_GENERAL, SG_WARN, "localizer:" << ident() << ", aligning with runway " 
203       << aRunway->ident() << " exceeded heading threshold");
204   }
205 }
206
207 FGTACANRecord::FGTACANRecord(void) :
208     channel(""),
209     freq(0)
210     
211 {
212 }
213
214 std::istream&
215 operator >> ( std::istream& in, FGTACANRecord& n )
216 {
217     in >> n.channel >> n.freq ;
218     //getline( in, n.name );
219
220     return in;
221 }