]> git.mxchange.org Git - flightgear.git/blob - src/Navaids/navrecord.cxx
Use OSG polytope intersector to fill ground cache
[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,
41   double lat, double lon, double aElevFt,
42   int aFreq, int aRange, double aMultiuse) :
43   FGPositioned(aTy, aIdent, lat, lon, aElevFt),
44   freq(aFreq),
45   range(aRange),
46   multiuse(aMultiuse),
47   name(aName),
48   serviceable(true),
49   trans_ident(aIdent)
50
51   initAirportRelation();
52
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
55   // reason.
56   if (range < 0.1) {
57     SG_LOG(SG_GENERAL, SG_WARN, "navaid " << ident() << " has no range set, using defaults");
58     switch (type()) {
59     case NDB:
60     case VOR:
61       range = FG_NAV_DEFAULT_RANGE;
62       break;
63     
64     case LOC:
65     case ILS:
66     case GS:
67       range = FG_LOC_DEFAULT_RANGE;
68       break;
69       
70     case DME:
71       range = FG_DME_DEFAULT_RANGE;
72       break;
73     
74     default:
75       range = FG_LOC_DEFAULT_RANGE;
76     }
77   }
78   
79 }
80
81 SGVec3d FGNavRecord::get_cart() const
82 {
83   return SGVec3d::fromGeod(geod());
84 }
85
86
87 static FGPositioned::Type
88 mapRobinTypeToFGPType(int aTy)
89 {
90   switch (aTy) {
91  // case 1:
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;
100   case 12:
101   case 13: return FGPositioned::DME;
102   case 99: return FGPositioned::INVALID; // end-of-file code
103   default:
104     throw sg_range_exception("Got a nav.dat type we don't recgonize", "FGNavRecord::createFromStream");
105   }
106 }
107
108 FGNavRecord* FGNavRecord::createFromStream(std::istream& aStream)
109 {
110   int rawType;
111   aStream >> rawType;
112   if (aStream.eof()) {
113     return NULL; // happens with, eg, carrier_nav.dat
114   }
115   
116   Type type = mapRobinTypeToFGPType(rawType);
117   if (type == INVALID) return NULL;
118   
119   double lat, lon, elev_ft, multiuse;
120   int freq, range;
121   std::string apt_id, name, ident;
122   aStream >> lat >> lon >> elev_ft >> freq >> range >> multiuse >> ident;
123   getline(aStream, name);
124   
125   // silently multiply adf frequencies by 100 so that adf
126   // vs. nav/loc frequency lookups can use the same code.
127   if (type == NDB) {
128     freq *= 100;
129   }
130   
131   FGNavRecord* result = new FGNavRecord(type, ident,
132     simgear::strutils::strip(name), 
133     lat, lon, elev_ft, freq, range, multiuse);
134     
135   return result;
136 }
137
138 void FGNavRecord::initAirportRelation()
139 {
140   if (type() < ILS || type() > IM) {
141     return; // not airport-located
142   }
143   
144   vector<string> parts = simgear::strutils::split(name);
145   apt_id = parts[0];
146   const FGAirport* apt = fgFindAirportID(apt_id);
147   
148   if (!apt) {
149     SG_LOG(SG_GENERAL, SG_WARN, "navaid " << ident() << " associated with bogus airport ID:" << apt_id);
150     return;
151   }
152   
153   // fudge elevation to the field elevation if it's not specified
154   if (fabs(elevation()) < 0.01) {
155     mPosition.setElevationFt(apt->getElevation());
156   }
157   
158   // align localizers with their runway
159   if ((type() == ILS) || (type() == LOC)) {
160     if (!fgGetBool("/sim/navdb/localizers/auto-align", true)) {
161       return;
162     }
163     
164     if (parts.size() < 2) {
165       SG_LOG(SG_GENERAL, SG_ALERT, "can't parse navaid " << ident() 
166               << " name for airport/runway:" << name);
167       return;
168     }
169     
170      double threshold
171             = fgGetDouble( "/sim/navdb/localizers/auto-align-threshold-deg",
172                            5.0 );
173     FGRunway* runway = apt->getRunwayByIdent(parts[1]);
174     alignLocaliserWithRunway(runway, threshold);
175   }
176 }
177
178 void FGNavRecord::alignLocaliserWithRunway(FGRunway* aRunway, double aThreshold)
179 {
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);
184
185 // back project that distance along the runway center line
186   SGGeod newPos = aRunway->pointOnCenterline(dist);
187
188   double hdg_diff = get_multiuse() - aRunway->headingDeg();
189
190   // clamp to [-180.0 ... 180.0]
191   if ( hdg_diff < -180.0 ) {
192       hdg_diff += 360.0;
193   } else if ( hdg_diff > 180.0 ) {
194       hdg_diff -= 360.0;
195   }
196
197   if ( fabs(hdg_diff) <= aThreshold ) {
198     mPosition = newPos;
199     set_multiuse( aRunway->headingDeg() );
200   } else {
201     SG_LOG(SG_GENERAL, SG_WARN, "localizer:" << ident() << ", aligning with runway " 
202       << aRunway->_rwy_no << " exceeded heading threshold");
203   }
204 }
205
206 FGTACANRecord::FGTACANRecord(void) :
207     channel(""),
208     freq(0)
209     
210 {
211 }
212
213 std::istream&
214 operator >> ( std::istream& in, FGTACANRecord& n )
215 {
216     in >> n.channel >> n.freq ;
217     //getline( in, n.name );
218
219     return in;
220 }