1 
2 #include <fstream>
3 
4 #include <simgear/misc/sg_path.hxx>
5 #include <simgear/io/iostreams/sgstream.hxx>
6 #include <simgear/structure/exception.hxx>
7 
8 #include <Main/fg_init.hxx>
9 #include <Main/fg_props.hxx>
10 
11 #include <Instrumentation/gps.hxx>
12 #include <Autopilot/route_mgr.hxx>
13 #include <Environment/environment_mgr.hxx>
14 #include <Navaids/airways.hxx>
15 #include <Navaids/waypoint.hxx>
16 #include <Navaids/procedure.hxx>
17 
18 #include "test_suite/helpers/globals.hxx"
19 #include "test_suite/helpers/NavDataCache.hxx"
20 
21 #include "testgps.hxx"
22 
23 
24 using std::string;
25 using namespace flightgear;
26 
27 char *homedir = ::getenv( "HOME" );
28 char *hostname = ::getenv( "HOSTNAME" );
29 bool free_hostname = false;
30 
testSetPosition(const SGGeod & aPos)31 void testSetPosition(const SGGeod& aPos)
32 {
33   fgSetDouble("/position/longitude-deg", aPos.getLongitudeDeg());
34   fgSetDouble("/position/latitude-deg", aPos.getLatitudeDeg());
35   fgSetDouble("/position/altitude-ft", aPos.getElevationFt());
36 }
37 
printScratch(SGPropertyNode * scratch)38 void printScratch(SGPropertyNode* scratch)
39 {
40   if (!scratch->getBoolValue("valid", false)) {
41     SG_LOG(SG_GENERAL, SG_ALERT, "Scratch is invalid.");
42     return;
43   }
44 
45   SG_LOG(SG_GENERAL, SG_ALERT, "Scratch:" <<
46     scratch->getStringValue("ident") << "/" << scratch->getStringValue("name"));
47 
48   SG_LOG(SG_GENERAL, SG_ALERT, "\t" << scratch->getDoubleValue("longitude-deg")
49     << " " << scratch->getDoubleValue("latitude-deg") << " @ " << scratch->getDoubleValue("altitude-ft"));
50 
51   SG_LOG(SG_GENERAL, SG_ALERT, "\t" << scratch->getDoubleValue("true-bearing-deg") <<
52     " (" << scratch->getDoubleValue("mag-bearing-deg") << " magnetic) " << scratch->getDoubleValue("distance-nm"));
53 
54   if (scratch->hasChild("result-index")) {
55     SG_LOG(SG_GENERAL, SG_ALERT, "\tresult-index:" << scratch->getIntValue("result-index"));
56   }
57 
58   if (scratch->hasChild("route-index")) {
59     SG_LOG(SG_GENERAL, SG_ALERT, "\troute-index:" << scratch->getIntValue("route-index"));
60   }
61 }
62 
printRoute(const WayptVec & aRoute)63 void printRoute(const WayptVec& aRoute)
64 {
65   SG_LOG(SG_GENERAL, SG_INFO, "route size=" << aRoute.size());
66   for (unsigned int r=0; r<aRoute.size();++r) {
67     Waypt* w = aRoute[r];
68     SG_LOG(SG_GENERAL, SG_ALERT, "\t" << r << ": " << w->ident() << " "
69       << w->owner()->ident());
70   }
71 }
72 
createDummyRoute(FGRouteMgr * rm)73 void createDummyRoute(FGRouteMgr* rm)
74 {
75   SGPropertyNode* rmInput = fgGetNode("/autopilot/route-manager/input", true);
76   rmInput->setStringValue("UW");
77   rmInput->setStringValue("TLA/347/13");
78   rmInput->setStringValue("TLA");
79   rmInput->setStringValue("HAVEN");
80   rmInput->setStringValue("NEW/305/29");
81   rmInput->setStringValue("NEW");
82   rmInput->setStringValue("OTR");
83 }
84 
85 
setUp()86 void GPSTests::setUp()
87 {
88     fgtest::initTestGlobals("GPS");
89     fgtest::initNavDataCache();
90 }
91 
92 
tearDown()93 void GPSTests::tearDown()
94 {
95     fgtest::shutdownTestGlobals();
96 }
97 
98 
testGPS()99 void GPSTests::testGPS()
100 {
101   fgSetDouble("/environment/magnetic-variation-deg", 0.0);
102 
103   Airway::load();
104 
105   SG_LOG(SG_GENERAL, SG_ALERT, "hello world!");
106 
107   const FGAirport* egph = fgFindAirportID("EGPH");
108   SG_LOG(SG_GENERAL, SG_ALERT, "egph: cart location:" << egph->cart());
109 
110   FGAirport::AirportFilter af;
111   FGPositionedList l = FGPositioned::findClosestN(egph->geod(), 20, 2000.0, &af);
112   for (unsigned int i=0; i<l.size(); ++i) {
113     SG_LOG(SG_GENERAL, SG_ALERT, "\t" << l[i]->ident() << "/" << l[i]->name());
114   }
115 
116   //l = FGPositioned::findWithinRange(egph->geod(), 500.0, &af);
117   //for (unsigned int i=0; i<l.size(); ++i) {
118   //  SG_LOG(SG_GENERAL, SG_ALERT, "\t" << l[i]->ident() << "/" << l[i]->name());
119   //}
120 
121 
122   FGRouteMgr* rm = new FGRouteMgr;
123   globals->add_subsystem( "route-manager", rm );
124 
125  // FGEnvironmentMgr* envMgr = new FGEnvironmentMgr;
126  // globals->add_subsystem("environment", envMgr);
127  // envMgr->init();
128 
129   fgSetBool("/sim/realism/simple-gps", true);
130 
131   // _realismSimpleGps
132 
133   SGPropertyNode* nd = fgGetNode("/instrumentation/gps", true);
134   GPS* gps = new GPS(nd);
135   globals->add_subsystem("gps", gps);
136 
137   const FGAirport* egph = fgFindAirportID("EGPH");
138   testSetPosition(egph->geod());
139 
140   // startup the route manager
141   rm->init();
142 
143   nd->setBoolValue("serviceable", true);
144   fgSetBool("/systems/electrical/outputs/gps", true);
145 
146   gps->init();
147   SGPropertyNode* scratch  = nd->getChild("scratch", 0, true);
148   SGPropertyNode* wp = nd->getChild("wp", 0, true);
149   SGPropertyNode* wp1 = wp->getChild("wp", 1, true);
150 
151   // update a few times
152   gps->update(0.05);
153   gps->update(0.05);
154   gps->update(0.05);
155 
156   scratch->setStringValue("query", "TL");
157   scratch->setStringValue("type", "Vor");
158   scratch->setBoolValue("exact", false);
159   nd->setStringValue("command", "search");
160   printScratch(scratch);
161 
162   nd->setStringValue("command", "next");
163   printScratch(scratch);
164 
165   nd->setStringValue("command", "next");
166   printScratch(scratch);
167 
168 // alphanumeric sort, partial matching
169   nd->setDoubleValue("config/min-runway-length-ft", 5000.0);
170   scratch->setBoolValue("exact", false);
171   scratch->setBoolValue("order-by-distance", false);
172   scratch->setStringValue("query", "KS");
173   scratch->setStringValue("type", "apt");
174 
175   nd->setStringValue("command", "search");
176   printScratch(scratch);
177 
178   nd->setStringValue("command", "next");
179   printScratch(scratch);
180 
181   nd->setStringValue("command", "next");
182   printScratch(scratch);
183 
184 // alphanumeric sort, explicit matching
185   scratch->setBoolValue("exact", true);
186   scratch->setBoolValue("order-by-distance", true);
187   scratch->setStringValue("type", "vor");
188   scratch->setStringValue("query", "DCS");
189 
190   nd->setStringValue("command", "search");
191   printScratch(scratch);
192 
193   nd->setStringValue("command", "next");
194   printScratch(scratch);
195 
196 // search on totally missing
197   scratch->setBoolValue("exact", true);
198   scratch->setBoolValue("order-by-distance", true);
199   scratch->setStringValue("query", "FOFOFOFOF");
200   nd->setStringValue("command", "search");
201   printScratch(scratch);
202 
203 // nearest
204   scratch->setStringValue("type", "apt");
205   scratch->setIntValue("max-results", 10);
206   nd->setStringValue("command", "nearest");
207   printScratch(scratch);
208 
209   nd->setStringValue("command", "next");
210   printScratch(scratch);
211 
212   nd->setStringValue("command", "next");
213   printScratch(scratch);
214 
215 // direct to
216   nd->setStringValue("command", "direct");
217   SG_LOG(SG_GENERAL, SG_ALERT, "mode:" << nd->getStringValue("mode") << "\n\t"
218     << wp1->getStringValue("ID") << " " << wp1->getDoubleValue("longitude-deg")
219     << " " << wp1->getDoubleValue("latitude-deg"));
220 
221 // OBS mode
222   scratch->setStringValue("query", "UW");
223   scratch->setBoolValue("order-by-distance", true);
224   nd->setStringValue("command", "search");
225   printScratch(scratch);
226 
227   nd->setStringValue("command", "obs");
228   SG_LOG(SG_GENERAL, SG_ALERT, "mode:" << nd->getStringValue("mode") << "\n\t"
229     << wp1->getStringValue("ID") << " " << wp1->getDoubleValue("longitude-deg")
230     << " " << wp1->getDoubleValue("latitude-deg"));
231 
232 // load route waypoints
233   createDummyRoute(rm);
234 
235   scratch->setIntValue("route-index", 5);
236   nd->setStringValue("command", "load-route-wpt");
237   printScratch(scratch);
238 
239   nd->setStringValue("command", "next");
240   printScratch(scratch);
241 
242   nd->setStringValue("command", "next");
243   printScratch(scratch);
244 
245   scratch->setIntValue("route-index", 2);
246   nd->setStringValue("command", "load-route-wpt");
247   nd->setStringValue("command", "direct");
248   SG_LOG(SG_GENERAL, SG_ALERT, "mode:" << nd->getStringValue("mode") << "\n\t"
249     << wp1->getStringValue("ID") << " " << wp1->getDoubleValue("longitude-deg")
250     << " " << wp1->getDoubleValue("latitude-deg"));
251 
252 // route editing
253   SGGeod pos = egph->geod();
254   scratch->setStringValue("ident", "FOOBAR");
255   scratch->setDoubleValue("longitude-deg", pos.getLongitudeDeg());
256   scratch->setDoubleValue("latitude-deg", pos.getLatitudeDeg());
257   nd->setStringValue("command", "define-user-wpt");
258   printScratch(scratch);
259 
260 // airways
261   FGPositioned::TypeFilter vorFilt(FGPositioned::VOR);
262   FGPositionedRef tla = FGPositioned::findClosestWithIdent("TLA", pos, &vorFilt);
263   FGPositionedRef big = FGPositioned::findClosestWithIdent("BIG", pos, &vorFilt);
264   FGPositionedRef pol = FGPositioned::findClosestWithIdent("POL", pos, &vorFilt);
265 
266   const FGAirport* eddm = fgFindAirportID("EDDM");
267   FGPositionedRef mun = FGPositioned::findClosestWithIdent("MUN",
268     eddm->geod(), &vorFilt);
269 
270   const FGAirport* ksfo = fgFindAirportID("KSFO");
271   FGPositionedRef sfo = FGPositioned::findClosestWithIdent("SFO",
272     ksfo->geod(), &vorFilt);
273 
274 
275   WayptRef awy1 = new NavaidWaypoint(tla, NULL);
276   WayptRef awy2 = new NavaidWaypoint(big, NULL);
277   WayptRef awy3 = new NavaidWaypoint(pol, NULL);
278   WayptRef awy4 = new NavaidWaypoint(mun, NULL);
279   WayptRef awy5 = new NavaidWaypoint(sfo, NULL);
280 
281   WayptRef awy6 = new NavaidWaypoint(
282     (FGPositioned*) fgFindAirportID("KJFK"), NULL);
283 
284   SGPath p("/Users/jmt/Desktop/airways.kml");
285   sg_ofstream f;
286   f.open(p, fstream::out | fstream::trunc);
287 
288 // pre-amble
289   f << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
290       "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"
291     "<Document>\n";
292 
293   WayptVec route;
294   Airway::highLevel()->route(awy1, awy3, route);
295   Route::dumpRouteToLineString("egph-egcc", route, f);
296 
297   Airway::lowLevel()->route(awy1, awy2, route);
298   Route::dumpRouteToLineString("egph-big", route, f);
299 
300   Airway::lowLevel()->route(awy2, awy4, route);
301   Route::dumpRouteToLineString("big-mun", route, f);
302 
303   Airway::highLevel()->route(awy4, awy5, route);
304   Route::dumpRouteToLineString("mun-sfo", route, f);
305 
306   Airway::lowLevel()->route(awy5, awy6, route);
307   Route::dumpRouteToLineString("sfo-jfk", route, f);
308 
309   // post-amble
310   f << "</Document>\n"
311     "</kml>" << endl;
312   f.close();
313 
314 // procedures
315   SGPath op("/Users/jmt/Desktop/procedures.kml");
316   f.open(op, fstream::out | fstream::trunc);
317 
318   FGAirport* eham = (FGAirport*) fgFindAirportID("EHAM");
319   FGPositioned::TypeFilter fixFilt(FGPositioned::FIX);
320 
321   WayptVec approach;
322   FGPositionedRef redfa = FGPositioned::findClosestWithIdent("REDFA",
323     eham->geod(), &fixFilt);
324   bool ok = eham->buildApproach(new NavaidWaypoint(redfa, NULL),
325     eham->getRunwayByIdent("18R"), approach);
326   if (!ok ) {
327     SG_LOG(SG_GENERAL, SG_INFO, "failed to build approach");
328   }
329 
330 
331   FGAirport* egll = (FGAirport*) fgFindAirportID("EGLL");
332   WayptVec approach2;
333   ok = egll->buildApproach(new NavaidWaypoint(big, NULL),
334     egll->getRunwayByIdent("27R"), approach2);
335   if (!ok ) {
336     SG_LOG(SG_GENERAL, SG_INFO, "failed to build approach");
337   }
338 
339 // pre-amble
340   f << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
341       "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"
342     "<Document>\n";
343 
344   Route::dumpRouteToLineString("REDFA 18R", approach, f);
345   Route::dumpRouteToLineString("EGLL 27R", approach2, f);
346 
347   // post-amble
348   f << "</Document>\n"
349     "</kml>" << endl;
350   f.close();
351 }
352