FlightGear next
NasalPositioned.cxx
Go to the documentation of this file.
1// NasalPositioned.cxx -- expose FGPositioned classes to Nasal
2//
3// Written by James Turner, started 2012.
4//
5// Copyright (C) 2012 James Turner
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#include "config.h"
22
23#include <cstring>
24#include <algorithm>
25
26#include "NasalPositioned.hxx"
27
28#include <simgear/sg_inlines.h>
29#include <simgear/scene/material/mat.hxx>
30#include <simgear/magvar/magvar.hxx>
31#include <simgear/timing/sg_time.hxx>
32#include <simgear/bucket/newbucket.hxx>
33
34#include <Airports/runways.hxx>
35#include <Airports/airport.hxx>
36#include <Airports/dynamics.hxx>
37#include <Airports/parking.hxx>
39#include <Navaids/navlist.hxx>
40#include <Navaids/procedure.hxx>
41#include <Main/globals.hxx>
42#include <Main/fg_props.hxx>
43#include <Main/util.hxx>
44#include <Scenery/scenery.hxx>
45#include <ATC/CommStation.hxx>
46#include <Navaids/fix.hxx>
49
50#include "NasalFlightPlan.hxx"
51
52using namespace flightgear;
53
54static void positionedGhostDestroy(void* g);
55
57
58static const char* airportGhostGetMember(naContext c, void* g, naRef field, naRef* out);
59static naGhostType AirportGhostType = { positionedGhostDestroy, "airport", airportGhostGetMember, nullptr };
60
61static const char* navaidGhostGetMember(naContext c, void* g, naRef field, naRef* out);
62static naGhostType NavaidGhostType = { positionedGhostDestroy, "navaid", navaidGhostGetMember, nullptr };
63
64static const char* runwayGhostGetMember(naContext c, void* g, naRef field, naRef* out);
65static naGhostType RunwayGhostType = { positionedGhostDestroy, "runway", runwayGhostGetMember, nullptr };
66static naGhostType HelipadGhostType = { positionedGhostDestroy, "helipad", runwayGhostGetMember, nullptr };
67static naGhostType TaxiwayGhostType = { positionedGhostDestroy, "taxiway", runwayGhostGetMember, nullptr };
68
69static const char* fixGhostGetMember(naContext c, void* g, naRef field, naRef* out);
70static naGhostType FixGhostType = { positionedGhostDestroy, "fix", fixGhostGetMember, nullptr };
71
72static const char* commGhostGetMember(naContext c, void* g, naRef field, naRef* out);
73static naGhostType CommGhostType = {positionedGhostDestroy, "comm", commGhostGetMember, nullptr};
74
75static const char* poiGhostGetMember(naContext c, void* g, naRef field, naRef* out);
76static naGhostType POIGhostType = {positionedGhostDestroy, "poi", poiGhostGetMember, nullptr};
77
78static void hashset(naContext c, naRef hash, const char* key, naRef val)
79{
80 naRef s = naNewString(c);
81 naStr_fromdata(s, (char*)key, strlen(key));
82 naHash_set(hash, s, val);
83}
84
85static naRef stringToNasal(naContext c, const std::string& s)
86{
87 return naStr_fromdata(naNewString(c),
88 const_cast<char *>(s.c_str()),
89 s.length());
90}
91
93{
94 if ((naGhost_type(r) == &AirportGhostType) ||
95 (naGhost_type(r) == &NavaidGhostType) ||
96 (naGhost_type(r) == &RunwayGhostType) ||
97 (naGhost_type(r) == &FixGhostType) ||
98 (naGhost_type(r) == &FixGhostType) ||
99 (naGhost_type(r) == &POIGhostType)) {
100 return (FGPositioned*) naGhost_ptr(r);
101 }
102
103 return 0;
104}
105
107{
108 if (naGhost_type(r) == &AirportGhostType)
109 return (FGAirport*) naGhost_ptr(r);
110 return 0;
111}
112
113static FGNavRecord* navaidGhost(naRef r)
114{
115 if (naGhost_type(r) == &NavaidGhostType)
116 return (FGNavRecord*) naGhost_ptr(r);
117 return 0;
118}
119
121{
122 if (naGhost_type(r) == &RunwayGhostType)
123 return (FGRunway*) naGhost_ptr(r);
124 return 0;
125}
126
127static FGTaxiway* taxiwayGhost(naRef r)
128{
129 if (naGhost_type(r) == &TaxiwayGhostType)
130 return (FGTaxiway*) naGhost_ptr(r);
131 return 0;
132}
133
134static FGFix* fixGhost(naRef r)
135{
136 if (naGhost_type(r) == &FixGhostType)
137 return (FGFix*) naGhost_ptr(r);
138 return 0;
139}
140
141#if 0
142static flightgear::CommStation* commGhost(naRef r)
143{
144 if (naGhost_type(r) == &CommGhostType)
145 return (flightgear::CommStation*)naGhost_ptr(r);
146 return nullptr;
147}
148#endif
149
150static POI* poiGhost(naRef r)
151{
152 if (naGhost_type(r) == &POIGhostType)
153 return (POI*)naGhost_ptr(r);
154 return nullptr;
155}
156
157
158static void positionedGhostDestroy(void* g)
159{
160 FGPositioned* pos = (FGPositioned*)g;
161 if (!FGPositioned::put(pos)) // unref
162 delete pos;
163}
164
165
166static naRef airportPrototype;
167static naRef geoCoordClass;
168static naRef waypointPrototype;
169
170naRef ghostForAirport(naContext c, const FGAirport* apt)
171{
172 if (!apt) {
173 return naNil();
174 }
175
176 FGPositioned::get(apt); // take a ref
177 return naNewGhost2(c, &AirportGhostType, (void*) apt);
178}
179
180naRef ghostForNavaid(naContext c, const FGNavRecord* n)
181{
182 if (!n) {
183 return naNil();
184 }
185
186 FGPositioned::get(n); // take a ref
187 return naNewGhost2(c, &NavaidGhostType, (void*) n);
188}
189
190naRef ghostForRunway(naContext c, const FGRunway* r)
191{
192 if (!r) {
193 return naNil();
194 }
195
196 FGPositioned::get(r); // take a ref
197 return naNewGhost2(c, &RunwayGhostType, (void*) r);
198}
199
200naRef ghostForHelipad(naContext c, const FGHelipad* r)
201{
202 if (!r) {
203 return naNil();
204 }
205
206 FGPositioned::get(r); // take a ref
207 return naNewGhost2(c, &HelipadGhostType, (void*) r);
208}
209
210naRef ghostForTaxiway(naContext c, const FGTaxiway* r)
211{
212 if (!r) {
213 return naNil();
214 }
215
216 FGPositioned::get(r); // take a ref
217 return naNewGhost2(c, &TaxiwayGhostType, (void*) r);
218}
219
220naRef ghostForFix(naContext c, const FGFix* r)
221{
222 if (!r) {
223 return naNil();
224 }
225
226 FGPositioned::get(r); // take a ref
227 return naNewGhost2(c, &FixGhostType, (void*) r);
228}
229
230naRef ghostForComm(naContext c, const flightgear::CommStation* comm)
231{
232 if (!c) {
233 return naNil();
234 }
235
236 FGPositioned::get(comm); // take a ref
237 return naNewGhost2(c, &CommGhostType, (void*)comm);
238}
239
240naRef ghostForPOI(naContext c, const POI* r)
241{
242 if (!r) {
243 return naNil();
244 }
245
246 FGPositioned::get(r); // take a ref
247 return naNewGhost2(c, &POIGhostType, (void*)r);
248}
249
250naRef ghostForPositioned(naContext c, FGPositionedRef pos)
251{
252 if (!pos) {
253 return naNil();
254 }
255
256 switch (pos->type()) {
278
285 return ghostForPOI(c, fgpositioned_cast<POI>(pos));
286
287 default:
288 SG_LOG(SG_NASAL, SG_DEV_ALERT, "Type lacks Nasal ghost mapping:" << pos->typeString());
289 return naNil();
290 }
291}
292
293static const char* airportGhostGetMember(naContext c, void* g, naRef field, naRef* out)
294{
295 const char* fieldName = naStr_data(field);
296 FGAirport* apt = (FGAirport*) g;
297
298 if (!strcmp(fieldName, "parents")) {
299 *out = naNewVector(c);
300 naVec_append(*out, airportPrototype);
301 } else if (!strcmp(fieldName, "id")) *out = stringToNasal(c, apt->ident());
302 else if (!strcmp(fieldName, "name")) *out = stringToNasal(c, apt->name());
303 else if (!strcmp(fieldName, "lat")) *out = naNum(apt->getLatitude());
304 else if (!strcmp(fieldName, "lon")) *out = naNum(apt->getLongitude());
305 else if (!strcmp(fieldName, "elevation")) {
306 *out = naNum(apt->getElevation() * SG_FEET_TO_METER);
307 } else if (!strcmp(fieldName, "has_metar")) {
308 *out = naNum(apt->getMetar());
309 } else if (!strcmp(fieldName, "runways")) {
310 *out = naNewHash(c);
311 double minLengthFt = fgGetDouble("/sim/navdb/min-runway-length-ft");
312 for(unsigned int r=0; r<apt->numRunways(); ++r) {
313 FGRunway* rwy(apt->getRunwayByIndex(r));
314 // ignore unusably short runways
315 if (rwy->lengthFt() < minLengthFt) {
316 continue;
317 }
318 naRef rwyid = stringToNasal(c, rwy->ident());
319 naRef rwydata = ghostForRunway(c, rwy);
320 naHash_set(*out, rwyid, rwydata);
321 }
322 } else if (!strcmp(fieldName, "helipads")) {
323 *out = naNewHash(c);
324
325 for(unsigned int r=0; r<apt->numHelipads(); ++r) {
326 FGHelipad* hp(apt->getHelipadByIndex(r));
327
328 naRef rwyid = stringToNasal(c, hp->ident());
329 naRef rwydata = ghostForHelipad(c, hp);
330 naHash_set(*out, rwyid, rwydata);
331 }
332
333 } else if (!strcmp(fieldName, "taxiways")) {
334 *out = naNewVector(c);
335 for(unsigned int r=0; r<apt->numTaxiways(); ++r) {
336 FGTaxiway* taxi(apt->getTaxiwayByIndex(r));
337 naRef taxidata = ghostForTaxiway(c, taxi);
338 naVec_append(*out, taxidata);
339 }
340
341 } else {
342 return 0;
343 }
344
345 return "";
346}
347
348static const char* runwayGhostGetMember(naContext c, void* g, naRef field, naRef* out)
349{
350 const char* fieldName = naStr_data(field);
351 FGRunwayBase* base = (FGRunwayBase*) g;
352
353 if (!strcmp(fieldName, "id")) *out = stringToNasal(c, base->ident());
354 else if (!strcmp(fieldName, "lat")) *out = naNum(base->latitude());
355 else if (!strcmp(fieldName, "lon")) *out = naNum(base->longitude());
356 else if (!strcmp(fieldName, "heading")) *out = naNum(base->headingDeg());
357 else if (!strcmp(fieldName, "length")) *out = naNum(base->lengthM());
358 else if (!strcmp(fieldName, "width")) *out = naNum(base->widthM());
359 else if (!strcmp(fieldName, "surface")) *out = naNum(base->surface());
360 else if (!strcmp(fieldName, "airport"))
361 *out = ghostForAirport(c, base->airport());
362 else if (base->type() == FGRunwayBase::RUNWAY) {
363 FGRunway* rwy = (FGRunway*) g;
364 if (!strcmp(fieldName, "threshold")) *out = naNum(rwy->displacedThresholdM());
365 else if (!strcmp(fieldName, "stopway")) *out = naNum(rwy->stopwayM());
366 else if (!strcmp(fieldName, "reciprocal")) {
367 *out = ghostForRunway(c, rwy->reciprocalRunway());
368 } else if (!strcmp(fieldName, "ils_frequency_mhz")) {
369 *out = rwy->ILS() ? naNum(rwy->ILS()->get_freq() / 100.0) : naNil();
370 } else if (!strcmp(fieldName, "ils")) {
371 *out = ghostForNavaid(c, rwy->ILS());
372 } else {
373 return 0;
374 }
375 } else {
376 return 0;
377 }
378
379 return "";
380}
381
382static const char* navaidGhostGetMember(naContext c, void* g, naRef field, naRef* out)
383{
384 const char* fieldName = naStr_data(field);
385 FGNavRecord* nav = (FGNavRecord*) g;
386
387 if (!strcmp(fieldName, "id")) *out = stringToNasal(c, nav->ident());
388 else if (!strcmp(fieldName, "name")) *out = stringToNasal(c, nav->name());
389 else if (!strcmp(fieldName, "lat")) *out = naNum(nav->get_lat());
390 else if (!strcmp(fieldName, "lon")) *out = naNum(nav->get_lon());
391 else if (!strcmp(fieldName, "elevation")) {
392 *out = naNum(nav->get_elev_ft() * SG_FEET_TO_METER);
393 } else if (!strcmp(fieldName, "type")) {
394 *out = stringToNasal(c, nav->nameForType(nav->type()));
395 } else if (!strcmp(fieldName, "frequency")) {
396 *out = naNum(nav->get_freq());
397 } else if (!strcmp(fieldName, "range_nm")) {
398 *out = naNum(nav->get_range());
399 } else if (!strcmp(fieldName, "magvar")) {
400 if (nav->type() == FGPositioned::VOR) {
401 // For VORs, the multiuse function provides the magnetic variation
402 double variation = nav->get_multiuse();
403 SG_NORMALIZE_RANGE(variation, 0.0, 360.0);
404 *out = naNum(variation);
405 } else {
406 *out = naNil();
407 }
408 } else if (!strcmp(fieldName, "colocated_dme")) {
410 if (dme) {
411 *out = ghostForNavaid(c, dme);
412 } else {
413 *out = naNil();
414 }
415 } else if (!strcmp(fieldName, "dme")) {
416 *out = naNum(nav->hasDME());
417 } else if (!strcmp(fieldName, "vortac")) {
418 *out = naNum(nav->isVORTAC());
419 } else if (!strcmp(fieldName, "course")) {
420 if ((nav->type() == FGPositioned::ILS) || (nav->type() == FGPositioned::LOC)) {
421 double radial = nav->get_multiuse();
422 SG_NORMALIZE_RANGE(radial, 0.0, 360.0);
423 *out = naNum(radial);
424 } else {
425 *out = naNil();
426 }
427 } else if (!strcmp(fieldName, "guid")) {
428 *out = naNum(nav->guid());
429 } else if (!strcmp(fieldName, "runway")) {
430 *out = ghostForRunway(c, nav->runway());
431 } else if (!strcmp(fieldName, "airport")) {
432 if (nav->runway()) {
433 *out = ghostForAirport(c, nav->runway()->airport());
434 } else {
435 *out = naNil(); // not associated with an airport / runway
436 }
437 } else {
438 return 0;
439 }
440
441 return "";
442}
443
444static const char* fixGhostGetMember(naContext c, void* g, naRef field, naRef* out)
445{
446 const char* fieldName = naStr_data(field);
447 FGFix* fix = (FGFix*) g;
448
449 if (!strcmp(fieldName, "id")) *out = stringToNasal(c, fix->ident());
450 else if (!strcmp(fieldName, "lat")) *out = naNum(fix->get_lat());
451 else if (!strcmp(fieldName, "lon")) *out = naNum(fix->get_lon());
452 // for homogenity with other values returned by navinfo()
453 else if (!strcmp(fieldName, "type")) *out = stringToNasal(c, "fix");
454 else if (!strcmp(fieldName, "name")) *out = stringToNasal(c, fix->ident());
455 else if (!strcmp(fieldName, "guid"))
456 *out = naNum(fix->guid());
457 else {
458 return 0;
459 }
460
461 return "";
462}
463
464static const char* commGhostGetMember(naContext c, void* g, naRef field, naRef* out)
465{
466 const char* fieldName = naStr_data(field);
467 auto comm = static_cast<flightgear::CommStation*>(g);
468
469 if (!strcmp(fieldName, "id"))
470 *out = stringToNasal(c, comm->ident());
471 else if (!strcmp(fieldName, "lat"))
472 *out = naNum(comm->latitude());
473 else if (!strcmp(fieldName, "lon"))
474 *out = naNum(comm->longitude());
475 else if (!strcmp(fieldName, "airport"))
476 *out = ghostForAirport(c, comm->airport());
477 else if (!strcmp(fieldName, "range_nm"))
478 *out = naNum(comm->rangeNm());
479 else if (!strcmp(fieldName, "type")) {
480 *out = stringToNasal(c, comm->nameForType(comm->type()));
481 } else if (!strcmp(fieldName, "name"))
482 *out = stringToNasal(c, comm->name());
483 else if (!strcmp(fieldName, "frequency")) {
484 *out = naNum(comm->freqMHz());
485 } else if (!strcmp(fieldName, "guid")) {
486 *out = naNum(comm->guid());
487 } else {
488 return 0;
489 }
490
491 return "";
492}
493
494static const char* poiGhostGetMember(naContext c, void* g, naRef field, naRef* out)
495{
496 const char* fieldName = naStr_data(field);
497 POI* wpt = (POI*)g;
498
499 if (!strcmp(fieldName, "parents")) {
500 *out = naNewVector(c);
501 naVec_append(*out, waypointPrototype);
502 } else if (!strcmp(fieldName, "id"))
503 *out = stringToNasal(c, wpt->ident());
504 else if (!strcmp(fieldName, "lat"))
505 *out = naNum(wpt->latitude());
506 else if (!strcmp(fieldName, "lon"))
507 *out = naNum(wpt->longitude());
508 else if (!strcmp(fieldName, "type"))
509 *out = stringToNasal(c, wpt->nameForType(wpt->type()));
510 else if (!strcmp(fieldName, "name"))
511 *out = stringToNasal(c, wpt->name());
512 else if (!strcmp(fieldName, "guid"))
513 *out = naNum(wpt->guid());
514 else {
515 return 0;
516 }
517
518 return "";
519}
520
521
522static bool hashIsCoord(naRef h)
523{
524 naRef parents = naHash_cget(h, (char*) "parents");
525 if (!naIsVector(parents)) {
526 return false;
527 }
528
529 return naEqual(naVec_get(parents, 0), geoCoordClass) != 0;
530}
531
532bool geodFromHash(naRef ref, SGGeod& result)
533{
534 if (!naIsHash(ref)) {
535 return false;
536 }
537
538
539// check for manual latitude / longitude names
540 naRef lat = naHash_cget(ref, (char*) "lat");
541 naRef lon = naHash_cget(ref, (char*) "lon");
542 if (naIsNum(lat) && naIsNum(lon)) {
543 result = SGGeod::fromDeg(naNumValue(lon).num, naNumValue(lat).num);
544 return true;
545 }
546
547// handle geo.nas geo.Coord object
548 if (hashIsCoord(ref)) {
549 naRef polarDirtyFlag = naHash_cget(ref, (char*) "_pdirty");
550 naRef cartesianDirtyFlag = naHash_cget(ref, (char*) "_cdirty");
551
552 if (naNumValue(polarDirtyFlag).num == 0) {
553 // polar values are valid
554 naRef lat = naHash_cget(ref, (char*) "_lat");
555 naRef lon = naHash_cget(ref, (char*) "_lon");
556 naRef alt_feet = naHash_cget(ref, (char*) "_alt");
557
558 if (naIsNum(lat) && naIsNum(lon) && naIsNil(alt_feet)) {
559 result = SGGeod::fromRad(naNumValue(lon).num, naNumValue(lat).num);
560 return true;
561 }
562
563 if (naIsNum(lat) && naIsNum(lon) && naIsNum(alt_feet)) {
564 result = SGGeod::fromRadFt(naNumValue(lon).num, naNumValue(lat).num, naNumValue(alt_feet).num);
565 return true;
566 }
567 } else if (naNumValue(cartesianDirtyFlag).num == 0) {
568 // cartesian values are valid
569 naRef x = naHash_cget(ref, (char*) "_x");
570 naRef y = naHash_cget(ref, (char*) "_y");
571 naRef z = naHash_cget(ref, (char*) "_z");
572
573 if (naIsNum(x) && naIsNum(y) && naIsNum(z)) {
574 result = SGGeod::fromCart(SGVec3d{naNumValue(x).num,
575 naNumValue(y).num, naNumValue(z).num});
576 return true;
577 }
578 } else {
579 SG_LOG(SG_NASAL, SG_DEV_ALERT, "geo.Coord() instance has invalid coordinates");
580 }
581 }
582// check for any synonyms?
583 // latitude + longitude?
584
585 return false;
586}
587
588int geodFromArgs(naRef* args, int offset, int argc, SGGeod& result)
589{
590 if (offset >= argc || !args) {
591 return 0;
592 }
593
594 if (naIsGhost(args[offset])) {
595 naGhostType* gt = naGhost_type(args[offset]);
596 if (gt == &AirportGhostType) {
597 result = airportGhost(args[offset])->geod();
598 return 1;
599 }
600
601 if (gt == &NavaidGhostType) {
602 result = navaidGhost(args[offset])->geod();
603 return 1;
604 }
605
606 if (gt == &RunwayGhostType) {
607 result = runwayGhost(args[offset])->geod();
608 return 1;
609 }
610
611 if (gt == &TaxiwayGhostType) {
612 result = taxiwayGhost(args[offset])->geod();
613 return 1;
614 }
615
616 if (gt == &FixGhostType) {
617 result = fixGhost(args[offset])->geod();
618 return 1;
619 }
620
621 if (gt == &POIGhostType) {
622 result = poiGhost(args[offset])->geod();
623 return 1;
624 }
625
626 auto wp = wayptGhost(args[offset]);
627 if (wp) {
628 result = wp->position();
629 return 1;
630 }
631
632 auto leg = fpLegGhost(args[offset]);
633 if (leg) {
634 result = leg->waypoint()->position();
635 return 1;
636 }
637 }
638
639 if (geodFromHash(args[offset], result)) {
640 return 1;
641 }
642
643 if (((argc - offset) >= 2) && naIsNum(args[offset]) && naIsNum(args[offset + 1])) {
644 double lat = naNumValue(args[0]).num,
645 lon = naNumValue(args[1]).num;
646 result = SGGeod::fromDeg(lon, lat);
647 return 2;
648 }
649
650 return 0;
651}
652
653bool vec3dFromHash(naRef ref, SGVec3d& result)
654{
655 if (!naIsHash(ref)) {
656 return false;
657 }
658
659 // check for manual latitude / longitude names
660 naRef x = naHash_cget(ref, (char*) "x");
661 naRef y = naHash_cget(ref, (char*) "y");
662 naRef z = naHash_cget(ref, (char*) "z");
663 if (naIsNum(x) && naIsNum(y) && naIsNum(z)) {
664 result = SGVec3d(naNumValue(x).num, naNumValue(y).num, naNumValue(z).num);
665 return true;
666 }
667 return false;
668}
669
670// Convert a cartesian point to a geodetic lat/lon/altitude.
671static naRef f_carttogeod(naContext c, naRef me, int argc, naRef* args)
672{
673 double lat, lon, alt, xyz[3];
674 if(argc != 3) naRuntimeError(c, "carttogeod() expects 3 arguments");
675 for(int i=0; i<3; i++)
676 xyz[i] = naNumValue(args[i]).num;
677 sgCartToGeod(xyz, &lat, &lon, &alt);
678 lat *= SG_RADIANS_TO_DEGREES;
679 lon *= SG_RADIANS_TO_DEGREES;
680 naRef vec = naNewVector(c);
681 naVec_append(vec, naNum(lat));
682 naVec_append(vec, naNum(lon));
683 naVec_append(vec, naNum(alt));
684 return vec;
685}
686
687// Convert a geodetic lat/lon/altitude to a cartesian point.
688static naRef f_geodtocart(naContext c, naRef me, int argc, naRef* args)
689{
690 if(argc != 3) naRuntimeError(c, "geodtocart() expects 3 arguments");
691 double lat = naNumValue(args[0]).num * SG_DEGREES_TO_RADIANS;
692 double lon = naNumValue(args[1]).num * SG_DEGREES_TO_RADIANS;
693 double alt = naNumValue(args[2]).num;
694 double xyz[3];
695 sgGeodToCart(lat, lon, alt, xyz);
696 naRef vec = naNewVector(c);
697 naVec_append(vec, naNum(xyz[0]));
698 naVec_append(vec, naNum(xyz[1]));
699 naVec_append(vec, naNum(xyz[2]));
700 return vec;
701}
702
740static naRef f_get_cart_ground_intersection(naContext c, naRef me, int argc, naRef* args)
741{
742 SGVec3d dir;
743 SGVec3d pos;
744
745 if (argc != 2)
746 naRuntimeError(c, "geod_hash get_cart_ground_intersection(position: hash{x,y,z}, direction:hash{x,y,z}) expects 2 arguments");
747
748 if (!vec3dFromHash(args[0], pos))
749 naRuntimeError(c, "geod_hash get_cart_ground_intersection(position:hash{x,y,z}, direction:hash{x,y,z}) expects argument(0) to be hash of position containing x,y,z");
750
751 if (!vec3dFromHash(args[1], dir))
752 naRuntimeError(c, "geod_hash get_cart_ground_intersection(position: hash{x,y,z}, direction:hash{x,y,z}) expects argument(1) to be hash of direction containing x,y,z");
753
754 SGVec3d nearestHit;
755 if (!globals->get_scenery()->get_cart_ground_intersection(pos, dir, nearestHit))
756 return naNil();
757
758 const SGGeod geodHit = SGGeod::fromCart(nearestHit);
759
760 // build a hash for returned intersection
761 naRef intersection_h = naNewHash(c);
762 hashset(c, intersection_h, "lat", naNum(geodHit.getLatitudeDeg()));
763 hashset(c, intersection_h, "lon", naNum(geodHit.getLongitudeDeg()));
764 hashset(c, intersection_h, "elevation", naNum(geodHit.getElevationM()));
765 return intersection_h;
766}
767
768// convert from aircraft reference frame to global (ECEF) cartesian
769static naRef f_aircraftToCart(naContext c, naRef me, int argc, naRef* args)
770{
771 if (argc != 1)
772 naRuntimeError(c, "hash{x,y,z} aircraftToCart(position: hash{x,y,z}) expects one argument");
773
774 SGVec3d offset;
775 if (!vec3dFromHash(args[0], offset))
776 naRuntimeError(c, "aircraftToCart expects argument(0) to be a hash containing x,y,z");
777
778 double heading, pitch, roll;
779 globals->get_aircraft_orientation(heading, pitch, roll);
780
781 // Transform that one to the horizontal local coordinate system.
782 SGQuatd hlTrans = SGQuatd::fromLonLat(globals->get_aircraft_position());
783
784 // post-rotate the orientation of the aircraft wrt the horizontal local frame
785 hlTrans *= SGQuatd::fromYawPitchRollDeg(heading, pitch, roll);
786
787 // The offset converted to the usual body fixed coordinate system
788 // rotated to the earth fiexed coordinates axis
789 offset = hlTrans.backTransform(offset);
790
791 SGVec3d v = globals->get_aircraft_position_cart() + offset;
792
793 // build a hash for returned location
794 naRef pos_h = naNewHash(c);
795 hashset(c, pos_h, "x", naNum(v.x()));
796 hashset(c, pos_h, "y", naNum(v.y()));
797 hashset(c, pos_h, "z", naNum(v.z()));
798 return pos_h;
799}
800
801// For given geodetic point return array with elevation, and a material data
802// hash, or nil if there's no information available (tile not loaded). If
803// information about the material isn't available, then nil is returned instead
804// of the hash.
805static naRef f_geodinfo(naContext c, naRef me, int argc, naRef* args)
806{
807#define HASHSET(s,l,n) naHash_set(matdata, naStr_fromdata(naNewString(c),s,l),n)
808 if(argc < 2 || argc > 3)
809 naRuntimeError(c, "geodinfo() expects 2 or 3 arguments: lat, lon [, maxalt]");
810 double lat = naNumValue(args[0]).num;
811 double lon = naNumValue(args[1]).num;
812 double elev = argc == 3 ? naNumValue(args[2]).num : 10000;
813 const simgear::BVHMaterial *material;
814 SGGeod geod = SGGeod::fromDegM(lon, lat, elev);
815
816 if (globals == nullptr)
817 return naNil();
818
819 const auto scenery = globals->get_scenery();
820 if (scenery == nullptr)
821 return naNil();
822
823 if(!scenery->get_elevation_m(geod, elev, &material)) {
824 return naNil();
825 }
826
827 naRef vec = naNewVector(c);
828 naVec_append(vec, naNum(elev));
829
830 naRef matdata = naNil();
831
832 const SGMaterial *mat = dynamic_cast<const SGMaterial *>(material);
833 if(mat) {
834 matdata = naNewHash(c);
835 naRef names = naNewVector(c);
836 for (const std::string& n : mat->get_names())
837 naVec_append(names, stringToNasal(c, n));
838
839 HASHSET("region", 6, stringToNasal(c, mat->get_region_name()));
840 HASHSET("names", 5, names);
841 HASHSET("solid", 5, naNum(mat->get_solid()));
842 HASHSET("friction_factor", 15, naNum(mat->get_friction_factor()));
843 HASHSET("rolling_friction", 16, naNum(mat->get_rolling_friction()));
844 HASHSET("load_resistance", 15, naNum(mat->get_load_resistance()));
845 HASHSET("bumpiness", 9, naNum(mat->get_bumpiness()));
846 HASHSET("light_coverage", 14, naNum(mat->get_light_coverage()));
847 } else if (material) {
848 matdata = naNewHash(c);
849 naRef names = naNewVector(c);
850 naVec_append(names, stringToNasal(c, ""));
851
852 HASHSET("region", 6, stringToNasal(c, ""));
853 HASHSET("names", 5, names);
854 HASHSET("solid", 5, naNum(material->get_solid()));
855 HASHSET("friction_factor", 15, naNum(material->get_friction_factor()));
856 HASHSET("rolling_friction", 16, naNum(material->get_rolling_friction()));
857 HASHSET("load_resistance", 15, naNum(material->get_load_resistance()));
858 HASHSET("bumpiness", 9, naNum(material->get_bumpiness()));
859 }
860
861 naVec_append(vec, matdata);
862 return vec;
863#undef HASHSET
864}
865
866
867// Returns data hash for particular or nearest airport of a <type>, or nil
868// on error.
869//
870// airportinfo(<id>); e.g. "KSFO"
871// airportinfo(<type>); type := ("airport"|"seaport"|"heliport")
872// airportinfo() same as airportinfo("airport")
873// airportinfo(<lat>, <lon> [, <type>]);
874static naRef f_airportinfo(naContext c, naRef me, int argc, naRef* args)
875{
876 SGGeod pos = globals->get_aircraft_position();
877 FGAirport* apt = NULL;
878
879 if(argc >= 2 && naIsNum(args[0]) && naIsNum(args[1])) {
880 pos = SGGeod::fromDeg(args[1].num, args[0].num);
881 args += 2;
882 argc -= 2;
883 }
884
885 double maxRange = 10000.0; // expose this? or pick a smaller value?
886
887 FGAirport::TypeRunwayFilter filter; // defaults to airports only
888
889 if(argc == 0) {
890 // fall through and use AIRPORT
891 } else if(argc == 1 && naIsString(args[0])) {
892 if (filter.fromTypeString(naStr_data(args[0]))) {
893 // done!
894 } else {
895 // user provided an <id>, hopefully
896 apt = FGAirport::findByIdent(naStr_data(args[0]));
897 if (!apt) {
898 // return nil here, but don't raise a runtime error; this is a
899 // legitamate way to validate an ICAO code, for example in a
900 // dialog box or similar.
901 return naNil();
902 }
903 }
904 } else {
905 naRuntimeError(c, "airportinfo() with invalid function arguments");
906 return naNil();
907 }
908
909 if(!apt) {
910 apt = FGAirport::findClosest(pos, maxRange, &filter);
911 if(!apt) return naNil();
912 }
913
914 return ghostForAirport(c, apt);
915}
916
917static naRef f_findAirportsWithinRange(naContext c, naRef me, int argc, naRef* args)
918{
919 int argOffset = 0;
920 SGGeod pos = globals->get_aircraft_position();
921 argOffset += geodFromArgs(args, 0, argc, pos);
922
923 if (!naIsNum(args[argOffset])) {
924 naRuntimeError(c, "findAirportsWithinRange expected range (in nm) as arg %d", argOffset);
925 }
926
927 FGAirport::TypeRunwayFilter filter; // defaults to airports only
928 double rangeNm = args[argOffset++].num;
929 if (argOffset < argc) {
930 filter.fromTypeString(naStr_data(args[argOffset++]));
931 }
932
933 naRef r = naNewVector(c);
934
935 FGPositionedList apts = FGPositioned::findWithinRange(pos, rangeNm, &filter);
936 FGPositioned::sortByRange(apts, pos);
937
938 for (FGPositionedRef a : apts) {
939 naVec_append(r, ghostForAirport(c, fgpositioned_cast<FGAirport>(a)));
940 }
941
942 return r;
943}
944
945static naRef f_findAirportsByICAO(naContext c, naRef me, int argc, naRef* args)
946{
947 if (!naIsString(args[0])) {
948 naRuntimeError(c, "findAirportsByICAO expects string as arg 0");
949 }
950
951 int argOffset = 0;
952 std::string prefix(naStr_data(args[argOffset++]));
953 FGAirport::TypeRunwayFilter filter; // defaults to airports only
954 if (argOffset < argc) {
955 filter.fromTypeString(naStr_data(args[argOffset++]));
956 }
957
958 naRef r = naNewVector(c);
959
960 FGPositionedList apts = FGPositioned::findAllWithIdent(prefix, &filter, false);
961 for (FGPositionedRef a : apts) {
962 naVec_append(r, ghostForAirport(c, fgpositioned_cast<FGAirport>(a)));
963 }
964
965 return r;
966}
967
968static naRef f_airport_tower(naContext c, naRef me, int argc, naRef* args)
969{
970 FGAirport* apt = airportGhost(me);
971 if (!apt) {
972 naRuntimeError(c, "airport.tower called on non-airport object");
973 }
974
975 // build a hash for the tower position
976 SGGeod towerLoc = apt->getTowerLocation();
977 naRef tower = naNewHash(c);
978 hashset(c, tower, "lat", naNum(towerLoc.getLatitudeDeg()));
979 hashset(c, tower, "lon", naNum(towerLoc.getLongitudeDeg()));
980 hashset(c, tower, "elevation", naNum(towerLoc.getElevationM()));
981 return tower;
982}
983
984static naRef f_airport_comms(naContext c, naRef me, int argc, naRef* args)
985{
986 FGAirport* apt = airportGhost(me);
987 if (!apt) {
988 naRuntimeError(c, "airport.comms called on non-airport object");
989 }
990 naRef comms = naNewVector(c);
991
992// if we have an explicit type, return a simple vector of frequencies
993 if (argc > 0 && !naIsString(args[0])) {
994 naRuntimeError(c, "airport.comms argument must be a frequency type name");
995 }
996
997 if (argc > 0) {
998 std::string commName = naStr_data(args[0]);
1000
1001 for (auto comm : apt->commStationsOfType(commType)) {
1002 naVec_append(comms, naNum(comm->freqMHz()));
1003 }
1004 } else {
1005// otherwise return a vector of hashes, one for each comm station.
1006 for (auto comm : apt->commStations()) {
1007 naRef commHash = naNewHash(c);
1008 hashset(c, commHash, "frequency", naNum(comm->freqMHz()));
1009 hashset(c, commHash, "ident", stringToNasal(c, comm->ident()));
1010 naVec_append(comms, commHash);
1011 }
1012 }
1013
1014 return comms;
1015}
1016
1017static naRef f_airport_runway(naContext c, naRef me, int argc, naRef* args)
1018{
1019 FGAirport* apt = airportGhost(me);
1020 if (!apt) {
1021 naRuntimeError(c, "airport.runway called on non-airport object");
1022 }
1023
1024 if ((argc < 1) || !naIsString(args[0])) {
1025 naRuntimeError(c, "airport.runway expects a runway ident argument");
1026 }
1027
1028 std::string ident = simgear::strutils::uppercase(naStr_data(args[0]));
1029
1030 if (apt->hasRunwayWithIdent(ident)) {
1031 return ghostForRunway(c, apt->getRunwayByIdent(ident));
1032 } else if (apt->hasHelipadWithIdent(ident)) {
1033 return ghostForHelipad(c, apt->getHelipadByIdent(ident));
1034 }
1035 return naNil();
1036}
1037
1038static naRef f_airport_runwaysWithoutReciprocals(naContext c, naRef me, int argc, naRef* args)
1039{
1040 FGAirport* apt = airportGhost(me);
1041 if (!apt) {
1042 naRuntimeError(c, "airport.runwaysWithoutReciprocals called on non-airport object");
1043 }
1044
1046 naRef runways = naNewVector(c);
1047 for (unsigned int r=0; r<rwylist.size(); ++r) {
1048 FGRunway* rwy(rwylist[r]);
1049 naVec_append(runways, ghostForRunway(c, apt->getRunwayByIdent(rwy->ident())));
1050 }
1051 return runways;
1052}
1053
1054static naRef f_airport_sids(naContext c, naRef me, int argc, naRef* args)
1055{
1056 FGAirport* apt = airportGhost(me);
1057 if (!apt) {
1058 naRuntimeError(c, "airport.sids called on non-airport object");
1059 }
1060
1061 naRef sids = naNewVector(c);
1062
1063 FGRunway* rwy = NULL;
1064 if (argc > 0 && naIsString(args[0])) {
1065 if (!apt->hasRunwayWithIdent(naStr_data(args[0]))) {
1066 return naNil();
1067 }
1068
1069 rwy = apt->getRunwayByIdent(naStr_data(args[0]));
1070 } else if (argc > 0) {
1071 rwy = runwayGhost(args[0]);
1072 }
1073
1074 if (rwy) {
1075 for (auto sid : rwy->getSIDs()) {
1076 naRef procId = stringToNasal(c, sid->ident());
1077 naVec_append(sids, procId);
1078 }
1079 } else {
1080 for (unsigned int s=0; s<apt->numSIDs(); ++s) {
1081 flightgear::SID* sid = apt->getSIDByIndex(s);
1082 naRef procId = stringToNasal(c, sid->ident());
1083 naVec_append(sids, procId);
1084 }
1085 }
1086
1087 return sids;
1088}
1089
1090static naRef f_airport_stars(naContext c, naRef me, int argc, naRef* args)
1091{
1092 FGAirport* apt = airportGhost(me);
1093 if (!apt) {
1094 naRuntimeError(c, "airport.stars called on non-airport object");
1095 }
1096
1097 naRef stars = naNewVector(c);
1098
1099 FGRunway* rwy = NULL;
1100 if (argc > 0 && naIsString(args[0])) {
1101 if (!apt->hasRunwayWithIdent(naStr_data(args[0]))) {
1102 return naNil();
1103 }
1104
1105 rwy = apt->getRunwayByIdent(naStr_data(args[0]));
1106 } else if (argc > 0) {
1107 rwy = runwayGhost(args[0]);
1108 }
1109
1110 if (rwy) {
1111 for (flightgear::STAR* s : rwy->getSTARs()) {
1112 naRef procId = stringToNasal(c, s->ident());
1113 naVec_append(stars, procId);
1114 }
1115 } else {
1116 for (unsigned int s=0; s<apt->numSTARs(); ++s) {
1117 flightgear::STAR* star = apt->getSTARByIndex(s);
1118 naRef procId = stringToNasal(c, star->ident());
1119 naVec_append(stars, procId);
1120 }
1121 }
1122
1123 return stars;
1124}
1125
1126static naRef f_airport_approaches(naContext c, naRef me, int argc, naRef* args)
1127{
1128 FGAirport* apt = airportGhost(me);
1129 if (!apt) {
1130 naRuntimeError(c, "airport.getApproachList called on non-airport object");
1131 }
1132
1133 naRef approaches = naNewVector(c);
1134
1136 if ((argc > 1) && naIsString(args[1])) {
1137 std::string u = simgear::strutils::uppercase(naStr_data(args[1]));
1138 if (u == "NDB") ty = PROCEDURE_APPROACH_NDB;
1139 if (u == "VOR") ty = PROCEDURE_APPROACH_VOR;
1140 if (u == "ILS") ty = PROCEDURE_APPROACH_ILS;
1141 if (u == "RNAV") ty = PROCEDURE_APPROACH_RNAV;
1142 }
1143
1144 FGRunway* rwy = NULL;
1145 STAR* star = nullptr;
1146 if (argc > 0 && (rwy = runwayGhost(args[0]))) {
1147 // ok
1148 } else if (argc > 0 && (procedureGhost(args[0]))) {
1149 Procedure* proc = procedureGhost(args[0]);
1150 if (proc->type() != PROCEDURE_STAR)
1151 return naNil();
1152 star = static_cast<STAR*>(proc);
1153 } else if (argc > 0 && naIsString(args[0])) {
1154 if (!apt->hasRunwayWithIdent(naStr_data(args[0]))) {
1155 return naNil();
1156 }
1157
1158 rwy = apt->getRunwayByIdent(naStr_data(args[0]));
1159 }
1160
1161 if (rwy) {
1162 for (Approach* s : rwy->getApproaches()) {
1163 if ((ty != PROCEDURE_INVALID) && (s->type() != ty)) {
1164 continue;
1165 }
1166
1167 naRef procId = stringToNasal(c, s->ident());
1168 naVec_append(approaches, procId);
1169 }
1170 } else if (star) {
1171 std::set<std::string> appIds;
1172 for (auto rwy : star->runways()) {
1173 for (auto app : rwy->getApproaches()) {
1174 appIds.insert(app->ident());
1175 }
1176 }
1177
1178 for (auto s : appIds) {
1179 naVec_append(approaches, stringToNasal(c, s));
1180 }
1181 } else {
1182 // no runway specified, report them all
1183 RunwayVec runways;
1184 if (star)
1185 runways = star->runways();
1186
1187 for (unsigned int s=0; s<apt->numApproaches(); ++s) {
1188 Approach* app = apt->getApproachByIndex(s);
1189 if ((ty != PROCEDURE_INVALID) && (app->type() != ty)) {
1190 continue;
1191 }
1192
1193 naRef procId = stringToNasal(c, app->ident());
1194 naVec_append(approaches, procId);
1195 }
1196 }
1197
1198 return approaches;
1199}
1200
1201static naRef f_airport_parking(naContext c, naRef me, int argc, naRef* args)
1202{
1203 FGAirport* apt = airportGhost(me);
1204 if (!apt) {
1205 naRuntimeError(c, "airport.parking called on non-airport object");
1206 }
1207
1208 naRef r = naNewVector(c);
1209 std::string type;
1210 bool onlyAvailable = false;
1211
1212 if (argc > 0 && naIsString(args[0])) {
1213 type = naStr_data(args[0]);
1214 }
1215
1216 if ((argc > 1) && naIsNum(args[1])) {
1217 onlyAvailable = (args[1].num != 0.0);
1218 }
1219
1220 FGAirportDynamicsRef dynamics = apt->getDynamics();
1221 FGParkingList parkings = dynamics->getParkings(onlyAvailable, type);
1222 FGParkingList::const_iterator it;
1223 for (it = parkings.begin(); it != parkings.end(); ++it) {
1224 FGParkingRef park = *it;
1225 const SGGeod& parkLoc = park->geod();
1226 naRef ph = naNewHash(c);
1227 hashset(c, ph, "name", stringToNasal(c, park->getName()));
1228 hashset(c, ph, "lat", naNum(parkLoc.getLatitudeDeg()));
1229 hashset(c, ph, "lon", naNum(parkLoc.getLongitudeDeg()));
1230 hashset(c, ph, "elevation", naNum(parkLoc.getElevationM()));
1231 naVec_append(r, ph);
1232 }
1233
1234 return r;
1235}
1236
1237static naRef f_airport_getSid(naContext c, naRef me, int argc, naRef* args)
1238{
1239 FGAirport* apt = airportGhost(me);
1240 if (!apt) {
1241 naRuntimeError(c, "airport.getSid called on non-airport object");
1242 }
1243
1244 if ((argc != 1) || !naIsString(args[0])) {
1245 naRuntimeError(c, "airport.getSid passed invalid argument");
1246 }
1247
1248 std::string ident = naStr_data(args[0]);
1249 return ghostForProcedure(c, apt->findSIDWithIdent(ident));
1250}
1251
1252static naRef f_airport_getStar(naContext c, naRef me, int argc, naRef* args)
1253{
1254 FGAirport* apt = airportGhost(me);
1255 if (!apt) {
1256 naRuntimeError(c, "airport.getStar called on non-airport object");
1257 }
1258
1259 if ((argc != 1) || !naIsString(args[0])) {
1260 naRuntimeError(c, "airport.getStar passed invalid argument");
1261 }
1262
1263 std::string ident = naStr_data(args[0]);
1264 return ghostForProcedure(c, apt->findSTARWithIdent(ident));
1265}
1266
1267static naRef f_airport_getApproach(naContext c, naRef me, int argc, naRef* args)
1268{
1269 FGAirport* apt = airportGhost(me);
1270 if (!apt) {
1271 naRuntimeError(c, "airport.getIAP called on non-airport object");
1272 }
1273
1274 if ((argc != 1) || !naIsString(args[0])) {
1275 naRuntimeError(c, "airport.getIAP passed invalid argument");
1276 }
1277
1278 std::string ident = naStr_data(args[0]);
1279 return ghostForProcedure(c, apt->findApproachWithIdent(ident));
1280}
1281
1282static naRef f_airport_findBestRunway(naContext c, naRef me, int argc, naRef* args)
1283{
1284 FGAirport* apt = airportGhost(me);
1285 if (!apt) {
1286 naRuntimeError(c, "findBestRunway called on non-airport object");
1287 }
1288
1289 SGGeod pos;
1290 if (!geodFromArgs(args, 0, argc, pos)) {
1291 naRuntimeError(c, "findBestRunway must be passed a position");
1292 }
1293
1294 return ghostForRunway(c, apt->findBestRunwayForPos(pos));
1295}
1296
1297static naRef f_airport_toString(naContext c, naRef me, int argc, naRef* args)
1298{
1299 FGAirport* apt = airportGhost(me);
1300 if (!apt) {
1301 naRuntimeError(c, "airport.tostring called on non-airport object");
1302 }
1303
1304 return stringToNasal(c, "an airport " + apt->ident());
1305}
1306
1307// Returns vector of data hash for navaid of a <type>, nil on error
1308// navaids sorted by ascending distance
1309// navinfo([<lat>,<lon>],[<type>],[<id>])
1310// lat/lon (numeric): use latitude/longitude instead of ac position
1311// type: ("fix"|"vor"|"ndb"|"ils"|"dme"|"tacan"|"any")
1312// id: (partial) id of the fix
1313// examples:
1314// navinfo("vor") returns all vors
1315// navinfo("HAM") return all navaids who's name start with "HAM"
1316// navinfo("vor", "HAM") return all vor who's name start with "HAM"
1317//navinfo(34,48,"vor","HAM") return all vor who's name start with "HAM"
1318// sorted by distance relative to lat=34, lon=48
1319static naRef f_navinfo(naContext c, naRef me, int argc, naRef* args)
1320{
1321 SGGeod pos;
1322
1323 if(argc >= 2 && naIsNum(args[0]) && naIsNum(args[1])) {
1324 pos = SGGeod::fromDeg(args[1].num, args[0].num);
1325 args += 2;
1326 argc -= 2;
1327 } else {
1328 pos = globals->get_aircraft_position();
1329 }
1330
1332 nav_list_type navlist;
1333 const char * id = "";
1334
1335 if(argc > 0 && naIsString(args[0])) {
1336 const char *s = naStr_data(args[0]);
1337 if(!strcmp(s, "any")) type = FGPositioned::INVALID;
1338 else if(!strcmp(s, "fix")) type = FGPositioned::FIX;
1339 else if(!strcmp(s, "vor")) type = FGPositioned::VOR;
1340 else if(!strcmp(s, "ndb")) type = FGPositioned::NDB;
1341 else if(!strcmp(s, "ils")) type = FGPositioned::ILS;
1342 else if(!strcmp(s, "dme")) type = FGPositioned::DME;
1343 else if(!strcmp(s, "tacan")) type = FGPositioned::TACAN;
1344 else id = s; // this is an id
1345 ++args;
1346 --argc;
1347 }
1348
1349 if(argc > 0 && naIsString(args[0])) {
1350 if( *id != 0 ) {
1351 naRuntimeError(c, "navinfo() called with navaid id");
1352 return naNil();
1353 }
1354 id = naStr_data(args[0]);
1355 ++args;
1356 --argc;
1357 }
1358
1359 if( argc > 0 ) {
1360 naRuntimeError(c, "navinfo() called with too many arguments");
1361 return naNil();
1362 }
1363
1364 FGNavList::TypeFilter filter(type);
1365 navlist = FGNavList::findByIdentAndFreq( pos, id, 0.0, &filter );
1366
1367 naRef reply = naNewVector(c);
1368 for( nav_list_type::const_iterator it = navlist.begin(); it != navlist.end(); ++it ) {
1369 naVec_append( reply, ghostForNavaid(c, *it) );
1370 }
1371 return reply;
1372}
1373
1374static naRef f_findNavaidsWithinRange(naContext c, naRef me, int argc, naRef* args)
1375{
1376 int argOffset = 0;
1377 SGGeod pos = globals->get_aircraft_position();
1378 argOffset += geodFromArgs(args, 0, argc, pos);
1379
1380 if (!naIsNum(args[argOffset])) {
1381 naRuntimeError(c, "findNavaidsWithinRange expected range (in nm) as arg %d", argOffset);
1382 }
1383
1385 double rangeNm = args[argOffset++].num;
1386 if (argOffset < argc) {
1387 type = FGPositioned::typeFromName(naStr_data(args[argOffset]));
1388 }
1389
1390 naRef r = naNewVector(c);
1391 FGNavList::TypeFilter filter(type);
1392 FGPositionedList navs = FGPositioned::findWithinRange(pos, rangeNm, &filter);
1393 FGPositioned::sortByRange(navs, pos);
1394
1395 for (FGPositionedRef a : navs) {
1396 FGNavRecord* nav = (FGNavRecord*) a.get();
1397 naVec_append(r, ghostForNavaid(c, nav));
1398 }
1399
1400 return r;
1401}
1402
1403static naRef f_findNDBByFrequency(naContext c, naRef me, int argc, naRef* args)
1404{
1405 int argOffset = 0;
1406 SGGeod pos = globals->get_aircraft_position();
1407 argOffset += geodFromArgs(args, 0, argc, pos);
1408
1409 if (!naIsNum(args[argOffset])) {
1410 naRuntimeError(c, "findNDBByFrquency expectes frequency (in kHz) as arg %d", argOffset);
1411 }
1412
1413 double dbFreq = args[argOffset++].num;
1415 nav_list_type navs = FGNavList::findAllByFreq(dbFreq, pos, &filter);
1416 if (navs.empty()) {
1417 return naNil();
1418 }
1419
1420 return ghostForNavaid(c, navs.front().ptr());
1421}
1422
1423static naRef f_findNDBsByFrequency(naContext c, naRef me, int argc, naRef* args)
1424{
1425 int argOffset = 0;
1426 SGGeod pos = globals->get_aircraft_position();
1427 argOffset += geodFromArgs(args, 0, argc, pos);
1428
1429 if (!naIsNum(args[argOffset])) {
1430 naRuntimeError(c, "findNDBsByFrquency expectes frequency (in kHz) as arg %d", argOffset);
1431 }
1432
1433 double dbFreq = args[argOffset++].num;
1435 nav_list_type navs = FGNavList::findAllByFreq(dbFreq, pos, &filter);
1436 if (navs.empty()) {
1437 return naNil();
1438 }
1439
1440 naRef r = naNewVector(c);
1441 for (nav_rec_ptr a : navs) {
1442 naVec_append(r, ghostForNavaid(c, a.ptr()));
1443 }
1444 return r;
1445}
1446
1447static naRef f_findNavaidByFrequency(naContext c, naRef me, int argc, naRef* args)
1448{
1449 int argOffset = 0;
1450 SGGeod pos = globals->get_aircraft_position();
1451 argOffset += geodFromArgs(args, 0, argc, pos);
1452
1453 if (!naIsNum(args[argOffset])) {
1454 naRuntimeError(c, "findNavaidByFrequency expectes frequency (in Mhz) as arg %d", argOffset);
1455 }
1456
1458 double freqMhz = args[argOffset++].num;
1459 if (argOffset < argc) {
1460 type = FGPositioned::typeFromName(naStr_data(args[argOffset]));
1461 if (type == FGPositioned::NDB) {
1462 naRuntimeError(c, "Use findNDBByFrquency to seach NDBs");
1463 }
1464 }
1465
1466 FGNavList::TypeFilter filter(type);
1467 auto navs = FGNavList::findAllByFreq(freqMhz, pos, &filter);
1468 if (navs.empty()) {
1469 return naNil();
1470 }
1471
1472 return ghostForNavaid(c, navs.front().ptr());
1473}
1474
1475static naRef f_findNavaidsByFrequency(naContext c, naRef me, int argc, naRef* args)
1476{
1477 int argOffset = 0;
1478 SGGeod pos = globals->get_aircraft_position();
1479 argOffset += geodFromArgs(args, 0, argc, pos);
1480
1481 if (!naIsNum(args[argOffset])) {
1482 naRuntimeError(c, "findNavaidsByFrequency expectes frequency (in Mhz) as arg %d", argOffset);
1483 }
1484
1486 double freqMhz = args[argOffset++].num;
1487 if (argOffset < argc) {
1488 type = FGPositioned::typeFromName(naStr_data(args[argOffset]));
1489 if (type == FGPositioned::NDB) {
1490 naRuntimeError(c, "Use findNDBsByFrquency to seach NDBs");
1491 }
1492 }
1493
1494 naRef r = naNewVector(c);
1495 FGNavList::TypeFilter filter(type);
1496 auto navs = FGNavList::findAllByFreq(freqMhz, pos, &filter);
1497 for (auto a : navs) {
1498 naVec_append(r, ghostForNavaid(c, a.ptr()));
1499 }
1500
1501 return r;
1502}
1503
1504static naRef f_findCommByFrequency(naContext c, naRef me, int argc, naRef* args)
1505{
1506 int argOffset = 0;
1507 SGGeod pos = globals->get_aircraft_position();
1508 argOffset += geodFromArgs(args, 0, argc, pos);
1509
1510 if (!naIsNum(args[argOffset])) {
1511 naRuntimeError(c, "findCommByFrequencyMhz expectes frequency (in Mhz) as arg %d", argOffset);
1512 }
1513
1514 // initial filter is all comm types
1516 double freqMhz = args[argOffset++].num;
1517 if (argOffset < argc) {
1518 // allow specifying an explicitly type by name
1519 filter = FGPositioned::TypeFilter::fromString(naStr_data(args[argOffset]));
1520 }
1521
1522 auto ref = NavDataCache::instance()->findCommByFreq(static_cast<int>(freqMhz * 1000), pos, &filter);
1523 if (!ref) {
1524 return naNil();
1525 }
1526
1528 return ghostForComm(c, comm);
1529}
1530
1531static naRef f_findCommsByFrequency(naContext c, naRef me, int argc, naRef* args)
1532{
1533 int argOffset = 0;
1534 SGGeod pos = globals->get_aircraft_position();
1535 argOffset += geodFromArgs(args, 0, argc, pos);
1536
1537 if (!naIsNum(args[argOffset])) {
1538 naRuntimeError(c, "f_findCommsByFrequency expectes frequency (in Mhz) as arg %d", argOffset);
1539 }
1540
1542 double freqMhz = args[argOffset++].num;
1543 if (argOffset < argc) {
1544 // allow specifying an explicitly type by name
1545 filter = FGPositioned::TypeFilter::fromString(naStr_data(args[argOffset]));
1546 }
1547
1548 naRef r = naNewVector(c);
1549 auto stations = NavDataCache::instance()->findCommsByFreq(static_cast<int>(freqMhz * 1000), pos, &filter);
1550 for (auto id : stations) {
1552 naVec_append(r, ghostForComm(c, sta.ptr()));
1553 }
1554
1555 return r;
1556}
1557
1558static naRef f_findNavaidsByIdent(naContext c, naRef me, int argc, naRef* args)
1559{
1560 int argOffset = 0;
1561 SGGeod pos = globals->get_aircraft_position();
1562 argOffset += geodFromArgs(args, 0, argc, pos);
1563
1564 if (!naIsString(args[argOffset])) {
1565 naRuntimeError(c, "findNavaidsByIdent expectes ident string as arg %d", argOffset);
1566 }
1567
1569 std::string ident = naStr_data(args[argOffset++]);
1570 if (argOffset < argc) {
1571 type = FGPositioned::typeFromName(naStr_data(args[argOffset]));
1572 }
1573
1574 FGNavList::TypeFilter filter(type);
1575 naRef r = naNewVector(c);
1576 nav_list_type navs = FGNavList::findByIdentAndFreq(pos, ident, 0.0, &filter);
1577
1578 for (nav_rec_ptr a : navs) {
1579 naVec_append(r, ghostForNavaid(c, a.ptr()));
1580 }
1581
1582 return r;
1583}
1584
1585static naRef f_findFixesByIdent(naContext c, naRef me, int argc, naRef* args)
1586{
1587 int argOffset = 0;
1588 SGGeod pos = globals->get_aircraft_position();
1589 argOffset += geodFromArgs(args, 0, argc, pos);
1590
1591 if (!naIsString(args[argOffset])) {
1592 naRuntimeError(c, "findFixesByIdent expectes ident string as arg %d", argOffset);
1593 }
1594
1595 std::string ident(naStr_data(args[argOffset]));
1596 naRef r = naNewVector(c);
1597
1599 FGPositionedList fixes = FGPositioned::findAllWithIdent(ident, &filter);
1600 FGPositioned::sortByRange(fixes, pos);
1601
1602 for (FGPositionedRef f : fixes) {
1603 naVec_append(r, ghostForFix(c, (FGFix*) f.ptr()));
1604 }
1605
1606 return r;
1607}
1608
1609static naRef f_findByIdent(naContext c, naRef me, int argc, naRef* args)
1610{
1611 if ((argc < 2) || !naIsString(args[0]) || !naIsString(args[1]) ) {
1612 naRuntimeError(c, "finxByIdent: expects ident and type as first two args");
1613 }
1614
1615 std::string ident(naStr_data(args[0]));
1616 std::string typeSpec(naStr_data(args[1]));
1617
1618 // optional specify search pos as final argument
1619 SGGeod pos = globals->get_aircraft_position();
1620 geodFromArgs(args, 2, argc, pos);
1622
1623 naRef r = naNewVector(c);
1624
1625 FGPositionedList matches = FGPositioned::findAllWithIdent(ident, &filter);
1626 FGPositioned::sortByRange(matches, pos);
1627
1628 for (auto f : matches) {
1629 naVec_append(r, ghostForPositioned(c, f));
1630 }
1631
1632 return r;
1633}
1634
1635
1636// Convert a cartesian point to a geodetic lat/lon/altitude.
1637static naRef f_magvar(naContext c, naRef me, int argc, naRef* args)
1638{
1639 SGGeod pos = globals->get_aircraft_position();
1640 if (argc == 0) {
1641 // fine, use aircraft position
1642 } else if (geodFromArgs(args, 0, argc, pos)) {
1643 // okay
1644 } else {
1645 naRuntimeError(c, "magvar() expects no arguments, a positioned hash or lat,lon pair");
1646 }
1647
1648 double jd = globals->get_time_params()->getJD();
1649 double magvarDeg = sgGetMagVar(pos, jd) * SG_RADIANS_TO_DEGREES;
1650 return naNum(magvarDeg);
1651}
1652
1653static naRef f_courseAndDistance(naContext c, naRef me, int argc, naRef* args)
1654{
1655 SGGeod from = globals->get_aircraft_position(), to, p;
1656 int argOffset = geodFromArgs(args, 0, argc, p);
1657 if (geodFromArgs(args, argOffset, argc, to)) {
1658 from = p; // we parsed both FROM and TO args, so first was from
1659 } else {
1660 to = p; // only parsed one arg, so FROM is current
1661 }
1662
1663 if (argOffset == 0) {
1664 naRuntimeError(c, "invalid arguments to courseAndDistance");
1665 }
1666
1667 double course, course2, d;
1668 SGGeodesy::inverse(from, to, course, course2, d);
1669
1670 naRef result = naNewVector(c);
1671 naVec_append(result, naNum(course));
1672 naVec_append(result, naNum(d * SG_METER_TO_NM));
1673 return result;
1674}
1675
1676static naRef f_formatLatLon(naContext c, naRef me, int argc, naRef* args)
1677{
1678 SGGeod p;
1679 int argOffset = geodFromArgs(args, 0, argc, p);
1680 if (argOffset == 0) {
1681 naRuntimeError(c, "invalid arguments to formatLatLon, expect a geod or lat,lon");
1682 }
1683
1684 simgear::strutils::LatLonFormat format =
1685 static_cast<simgear::strutils::LatLonFormat>(fgGetInt("/sim/lon-lat-format"));
1686 if (argOffset < argc && naIsNum(args[argOffset])) {
1687 format = static_cast<simgear::strutils::LatLonFormat>((int) args[argOffset].num);
1688 if (format > simgear::strutils::LatLonFormat::DECIMAL_DEGREES_SYMBOL) {
1689 naRuntimeError(c, "invalid lat-lon format requested");
1690 }
1691 }
1692
1693 const auto s = simgear::strutils::formatGeodAsString(p, format);
1694 return stringToNasal(c, s);
1695}
1696
1697static naRef f_parseStringAsLatLonValue(naContext c, naRef me, int argc, naRef* args)
1698{
1699 if ((argc < 1) || !naIsString(args[0])) {
1700 naRuntimeError(c, "Missing / bad argument to parseStringAsLatLonValue");
1701 }
1702
1703 double value;
1704 bool ok = simgear::strutils::parseStringAsLatLonValue(naStr_data(args[0]), value);
1705 if (!ok) {
1706 return naNil();
1707 }
1708
1709 return naNum(value);
1710}
1711
1712
1713static naRef f_greatCircleMove(naContext c, naRef me, int argc, naRef* args)
1714{
1715 SGGeod from = globals->get_aircraft_position(), to;
1716 int argOffset = 0;
1717
1718 // complication - don't inerpret two doubles (as the only args)
1719 // as a lat,lon pair - only do so if we have at least three args.
1720 if (argc > 2) {
1721 argOffset = geodFromArgs(args, 0, argc, from);
1722 }
1723
1724 if ((argOffset + 1) >= argc) {
1725 naRuntimeError(c, "isufficent arguments to greatCircleMove");
1726 }
1727
1728 if (!naIsNum(args[argOffset]) || !naIsNum(args[argOffset+1])) {
1729 naRuntimeError(c, "invalid arguments %d and %d to greatCircleMove",
1730 argOffset, argOffset + 1);
1731 }
1732
1733 double course = args[argOffset].num, course2;
1734 double distanceNm = args[argOffset + 1].num;
1735 SGGeodesy::direct(from, course, distanceNm * SG_NM_TO_METER, to, course2);
1736
1737 // return geo.Coord
1738 naRef coord = naNewHash(c);
1739 hashset(c, coord, "lat", naNum(to.getLatitudeDeg()));
1740 hashset(c, coord, "lon", naNum(to.getLongitudeDeg()));
1741 return coord;
1742}
1743
1744static naRef f_tilePath(naContext c, naRef me, int argc, naRef* args)
1745{
1746 SGGeod pos = globals->get_aircraft_position();
1747 geodFromArgs(args, 0, argc, pos);
1748 SGBucket b(pos);
1749 return stringToNasal(c, b.gen_base_path());
1750}
1751
1752static naRef f_tileIndex(naContext c, naRef me, int argc, naRef* args)
1753{
1754 SGGeod pos = globals->get_aircraft_position();
1755 geodFromArgs(args, 0, argc, pos);
1756 SGBucket b(pos);
1757 return naNum(b.gen_index());
1758}
1759
1760static naRef f_createWaypoint(naContext c, naRef me, int argc, naRef* args)
1761{
1762 if ((argc < 3) || !naIsString(args[0]) || !naIsString(args[1])) {
1763 naRuntimeError(c, "createWaypoint: expects type and ident as first two args");
1764 }
1765
1766 std::string typeSpec(naStr_data(args[0]));
1767 std::string ident(naStr_data(args[1]));
1768 std::string name;
1769
1771
1772 SGGeod pos;
1773 int argOffset = geodFromArgs(args, 2, argc, pos) + 2;
1774 if ((argc > argOffset) && naIsString(args[argOffset])) {
1775 name = naStr_data(args[argOffset]);
1776 ++argOffset;
1777 }
1778
1779 bool isTemporary = false;
1780 if ((argc > argOffset) && naIsNum(args[argOffset])) {
1781 isTemporary = (args[argOffset].num > 0);
1782 }
1783
1784 try {
1785 auto wpt = FGPositioned::createWaypoint(wptType, ident, pos, isTemporary, name);
1786 if (wptType == FGPositioned::FIX) {
1787 return ghostForFix(c, fgpositioned_cast<FGFix>(wpt));
1788 }
1789
1790 auto poi = fgpositioned_cast<POI>(wpt);
1791 return ghostForPOI(c, poi);
1792 } catch (std::exception& e) {
1793 naRuntimeError(c, "Failed to create waypoint: %s", e.what());
1794 }
1795
1796 return naNil();
1797}
1798
1799
1800static naRef f_deleteWaypoint(naContext c, naRef me, int argc, naRef* args)
1801{
1802 if (argc < 1) {
1803 naRuntimeError(c, "deleteWaypoint: missing argument");
1804 }
1805
1806 FGPositioned* wpt = poiGhost(args[0]);
1807 if (!wpt && naIsNum(args[0])) {
1808 PositionedID guid = static_cast<PositionedID>(args[0].num);
1809 wpt = NavDataCache::instance()->loadById(guid);
1810 if (!POI::isType(wpt->type())) {
1811 naRuntimeError(c, "deleteWaypoint: only waypoints can be deleted for now");
1812 }
1813 }
1814
1816 // note wpt is dead here, don't access
1817 return naNil();
1818}
1819
1820static naRef f_waypoint_move(naContext c, naRef me, int argc, naRef* args)
1821{
1822 POI* wpt = poiGhost(me);
1823 if (!wpt) {
1824 naRuntimeError(c, "waypoint.move called on non-POI object");
1825 }
1826
1827 SGGeod pos;
1828 geodFromArgs(args, 0, argc, pos);
1829
1831 return naNil();
1832}
1833
1835{
1836}
1837
1839{
1840 if (!naIsGhost(ref))
1841 return {};
1842
1843 naGhostType* gt = naGhost_type(ref);
1844 if (gt == &AirportGhostType)
1845 return airportGhost(ref);
1846
1847 if (gt == &NavaidGhostType)
1848 return navaidGhost(ref);
1849
1850 if (gt == &RunwayGhostType)
1851 return runwayGhost(ref);
1852
1853 if (gt == &TaxiwayGhostType)
1854 return taxiwayGhost(ref);
1855
1856 if (gt == &FixGhostType)
1857 return fixGhost(ref);
1858
1859 auto wpg = wayptGhost(ref);
1860 if (wpg)
1861 return wpg->source();
1862
1863 return {};
1864}
1865
1866// Table of extension functions. Terminate with zeros.
1867static struct {
1868 const char* name;
1869 naCFunction func;
1870} funcs[] = {
1871 {"carttogeod", f_carttogeod},
1872 {"geodtocart", f_geodtocart},
1873 {"geodinfo", f_geodinfo},
1874 {"formatLatLon", f_formatLatLon},
1875 {"parseStringAsLatLonValue", f_parseStringAsLatLonValue},
1876 {"get_cart_ground_intersection", f_get_cart_ground_intersection},
1877 {"aircraftToCart", f_aircraftToCart},
1878 {"airportinfo", f_airportinfo},
1879 {"findAirportsWithinRange", f_findAirportsWithinRange},
1880 {"findAirportsByICAO", f_findAirportsByICAO},
1881 {"navinfo", f_navinfo},
1882 {"findNavaidsWithinRange", f_findNavaidsWithinRange},
1883 {"findNDBByFrequencyKHz", f_findNDBByFrequency},
1884 {"findNDBsByFrequencyKHz", f_findNDBsByFrequency},
1885 {"findNavaidByFrequencyMHz", f_findNavaidByFrequency},
1886 {"findNavaidsByFrequencyMHz", f_findNavaidsByFrequency},
1887 {"findCommByFrequencyMHz", f_findCommByFrequency},
1888 {"findCommsByFrequencyMHz", f_findCommsByFrequency},
1889 {"findNavaidsByID", f_findNavaidsByIdent},
1890 {"findFixesByID", f_findFixesByIdent},
1891 {"findByIdent", f_findByIdent},
1892 {"magvar", f_magvar},
1893 {"courseAndDistance", f_courseAndDistance},
1894 {"greatCircleMove", f_greatCircleMove},
1895 {"tileIndex", f_tileIndex},
1896 {"tilePath", f_tilePath},
1897 {"createWaypoint", f_createWaypoint},
1898 {"deleteWaypoint", f_deleteWaypoint},
1899 {0, 0}};
1900
1901
1902naRef initNasalPositioned(naRef globals, naContext c)
1903{
1904 airportPrototype = naNewHash(c);
1905 naSave(c, airportPrototype);
1906
1907 hashset(c, airportPrototype, "runway", naNewFunc(c, naNewCCode(c, f_airport_runway)));
1908 hashset(c, airportPrototype, "runwaysWithoutReciprocals", naNewFunc(c, naNewCCode(c, f_airport_runwaysWithoutReciprocals)));
1909 hashset(c, airportPrototype, "helipad", naNewFunc(c, naNewCCode(c, f_airport_runway)));
1910 hashset(c, airportPrototype, "tower", naNewFunc(c, naNewCCode(c, f_airport_tower)));
1911 hashset(c, airportPrototype, "comms", naNewFunc(c, naNewCCode(c, f_airport_comms)));
1912 hashset(c, airportPrototype, "sids", naNewFunc(c, naNewCCode(c, f_airport_sids)));
1913 hashset(c, airportPrototype, "stars", naNewFunc(c, naNewCCode(c, f_airport_stars)));
1914 hashset(c, airportPrototype, "getApproachList", naNewFunc(c, naNewCCode(c, f_airport_approaches)));
1915 hashset(c, airportPrototype, "parking", naNewFunc(c, naNewCCode(c, f_airport_parking)));
1916 hashset(c, airportPrototype, "getSid", naNewFunc(c, naNewCCode(c, f_airport_getSid)));
1917 hashset(c, airportPrototype, "getStar", naNewFunc(c, naNewCCode(c, f_airport_getStar)));
1918
1919 naRef approachFunc = naNewFunc(c, naNewCCode(c, f_airport_getApproach));
1920
1921 // allow this to be used under either name
1922 hashset(c, airportPrototype, "getIAP", approachFunc);
1923 hashset(c, airportPrototype, "getApproach", approachFunc);
1924
1925 hashset(c, airportPrototype, "findBestRunwayForPos", naNewFunc(c, naNewCCode(c, f_airport_findBestRunway)));
1926 hashset(c, airportPrototype, "tostring", naNewFunc(c, naNewCCode(c, f_airport_toString)));
1927
1928 waypointPrototype = naNewHash(c);
1929 naSave(c, waypointPrototype);
1930 hashset(c, waypointPrototype, "move", naNewFunc(c, naNewCCode(c, f_waypoint_move)));
1931
1932 for(int i=0; funcs[i].name; i++) {
1933 hashset(c, globals, funcs[i].name,
1934 naNewFunc(c, naNewCCode(c, funcs[i].func)));
1935 }
1936
1937 return naNil();
1938}
1939
1940void postinitNasalPositioned(naRef globals, naContext c)
1941{
1942 naRef geoModule = naHash_cget(globals, (char*) "geo");
1943 if (naIsNil(geoModule)) {
1944 SG_LOG(SG_GENERAL, SG_WARN, "postinitNasalPositioned: geo.nas not loaded");
1945 return;
1946 }
1947
1948 geoCoordClass = naHash_cget(geoModule, (char*) "Coord");
1949}
#define p(x)
static struct @032150236342374176343243244364035346052374146336 funcs[]
FlightPlan::Leg * fpLegGhost(naRef r)
naRef ghostForProcedure(naContext c, const Procedure *proc)
Procedure * procedureGhost(naRef r)
Waypt * wayptGhost(naRef r)
static naRef f_findNavaidsByIdent(naContext c, naRef me, int argc, naRef *args)
static const char * poiGhostGetMember(naContext c, void *g, naRef field, naRef *out)
static naRef f_airport_getStar(naContext c, naRef me, int argc, naRef *args)
bool vec3dFromHash(naRef ref, SGVec3d &result)
naRef ghostForNavaid(naContext c, const FGNavRecord *n)
static naRef stringToNasal(naContext c, const std::string &s)
bool geodFromHash(naRef ref, SGGeod &result)
static naRef f_airport_parking(naContext c, naRef me, int argc, naRef *args)
static const char * navaidGhostGetMember(naContext c, void *g, naRef field, naRef *out)
static naRef f_parseStringAsLatLonValue(naContext c, naRef me, int argc, naRef *args)
static naRef f_airport_runway(naContext c, naRef me, int argc, naRef *args)
static naRef f_airport_runwaysWithoutReciprocals(naContext c, naRef me, int argc, naRef *args)
static naRef f_airport_sids(naContext c, naRef me, int argc, naRef *args)
static naGhostType TaxiwayGhostType
static naGhostType CommGhostType
static void hashset(naContext c, naRef hash, const char *key, naRef val)
static naGhostType FixGhostType
static naRef f_navinfo(naContext c, naRef me, int argc, naRef *args)
FGAirport * airportGhost(naRef r)
static FGFix * fixGhost(naRef r)
static naRef f_findNDBByFrequency(naContext c, naRef me, int argc, naRef *args)
static naGhostType RunwayGhostType
static POI * poiGhost(naRef r)
static naRef f_greatCircleMove(naContext c, naRef me, int argc, naRef *args)
static const char * airportGhostGetMember(naContext c, void *g, naRef field, naRef *out)
static naGhostType PositionedGhostType = { positionedGhostDestroy, "positioned", nullptr,...
naRef ghostForPOI(naContext c, const POI *r)
static naRef f_findNDBsByFrequency(naContext c, naRef me, int argc, naRef *args)
static naRef f_geodinfo(naContext c, naRef me, int argc, naRef *args)
static naRef f_airport_stars(naContext c, naRef me, int argc, naRef *args)
static naRef airportPrototype
static naRef f_findNavaidByFrequency(naContext c, naRef me, int argc, naRef *args)
static naRef f_get_cart_ground_intersection(naContext c, naRef me, int argc, naRef *args)
static naRef f_magvar(naContext c, naRef me, int argc, naRef *args)
static naRef f_tileIndex(naContext c, naRef me, int argc, naRef *args)
naRef ghostForHelipad(naContext c, const FGHelipad *r)
static naGhostType POIGhostType
static void positionedGhostDestroy(void *g)
static naRef f_formatLatLon(naContext c, naRef me, int argc, naRef *args)
static naRef f_findAirportsWithinRange(naContext c, naRef me, int argc, naRef *args)
FGRunway * runwayGhost(naRef r)
#define HASHSET(s, l, n)
static naRef f_findNavaidsByFrequency(naContext c, naRef me, int argc, naRef *args)
static naRef f_airport_getApproach(naContext c, naRef me, int argc, naRef *args)
static naGhostType HelipadGhostType
static FGTaxiway * taxiwayGhost(naRef r)
static const char * fixGhostGetMember(naContext c, void *g, naRef field, naRef *out)
naRef ghostForRunway(naContext c, const FGRunway *r)
int geodFromArgs(naRef *args, int offset, int argc, SGGeod &result)
naRef ghostForFix(naContext c, const FGFix *r)
static naRef f_courseAndDistance(naContext c, naRef me, int argc, naRef *args)
static const char * commGhostGetMember(naContext c, void *g, naRef field, naRef *out)
static bool hashIsCoord(naRef h)
naRef ghostForComm(naContext c, const flightgear::CommStation *comm)
static naRef f_findNavaidsWithinRange(naContext c, naRef me, int argc, naRef *args)
static naRef f_waypoint_move(naContext c, naRef me, int argc, naRef *args)
static naRef f_createWaypoint(naContext c, naRef me, int argc, naRef *args)
static naRef f_airport_comms(naContext c, naRef me, int argc, naRef *args)
static naRef f_findCommsByFrequency(naContext c, naRef me, int argc, naRef *args)
static naRef f_airport_findBestRunway(naContext c, naRef me, int argc, naRef *args)
static naRef f_airport_toString(naContext c, naRef me, int argc, naRef *args)
static naRef f_findAirportsByICAO(naContext c, naRef me, int argc, naRef *args)
static naRef f_carttogeod(naContext c, naRef me, int argc, naRef *args)
static naRef f_findByIdent(naContext c, naRef me, int argc, naRef *args)
static naGhostType AirportGhostType
FGPositionedRef positionedFromArg(naRef ref)
static naRef f_airport_getSid(naContext c, naRef me, int argc, naRef *args)
naRef ghostForPositioned(naContext c, FGPositionedRef pos)
static naGhostType NavaidGhostType
static naRef waypointPrototype
static naRef f_tilePath(naContext c, naRef me, int argc, naRef *args)
void shutdownNasalPositioned()
FGPositioned * positionedGhost(naRef r)
static naRef f_aircraftToCart(naContext c, naRef me, int argc, naRef *args)
static naRef f_airportinfo(naContext c, naRef me, int argc, naRef *args)
static naRef f_findFixesByIdent(naContext c, naRef me, int argc, naRef *args)
static naRef f_deleteWaypoint(naContext c, naRef me, int argc, naRef *args)
static naRef geoCoordClass
static naRef f_airport_tower(naContext c, naRef me, int argc, naRef *args)
static naRef f_geodtocart(naContext c, naRef me, int argc, naRef *args)
static naRef f_airport_approaches(naContext c, naRef me, int argc, naRef *args)
naRef ghostForTaxiway(naContext c, const FGTaxiway *r)
static const char * runwayGhostGetMember(naContext c, void *g, naRef field, naRef *out)
naRef initNasalPositioned(naRef globals, naContext c)
static naRef f_findCommByFrequency(naContext c, naRef me, int argc, naRef *args)
naRef ghostForAirport(naContext c, const FGAirport *apt)
static FGNavRecord * navaidGhost(naRef r)
void postinitNasalPositioned(naRef globals, naContext c)
#define i(x)
SGSharedPtr< FGAirportDynamics > FGAirportDynamicsRef
std::vector< FGRunwayRef > FGRunwayList
std::vector< FGParkingRef > FGParkingList
SGSharedPtr< FGParking > FGParkingRef
Filter which passes specified port type and in case of airport checks if a runway larger the /sim/nav...
Definition airport.hxx:233
bool fromTypeString(const std::string &type)
Construct from string containing type (airport, seaport or heliport)
Definition airport.cxx:461
FGAirportDynamicsRef getDynamics() const
Definition airport.cxx:1048
bool getMetar() const
Definition airport.hxx:62
unsigned int numRunways() const
Definition airport.cxx:102
flightgear::STAR * getSTARByIndex(unsigned int aIndex) const
Definition airport.cxx:914
FGHelipadRef getHelipadByIndex(unsigned int aIndex) const
Definition airport.cxx:123
FGRunwayRef findBestRunwayForPos(const SGGeod &aPos) const
return the most likely target runway based on a position.
Definition airport.cxx:248
unsigned int numApproaches() const
Definition airport.cxx:940
unsigned int numSIDs() const
Definition airport.cxx:873
unsigned int numTaxiways() const
Definition airport.cxx:330
FGRunwayRef getRunwayByIndex(unsigned int aIndex) const
Definition airport.cxx:116
FGRunwayList getRunwaysWithoutReciprocals() const
Retrieve all runways at the airport, but excluding the reciprocal runways.
Definition airport.cxx:308
double getElevation() const
Definition airport.hxx:61
double getLatitude() const
Definition airport.hxx:59
double getLongitude() const
Definition airport.hxx:57
FGRunwayRef getRunwayByIdent(const std::string &aIdent) const
Definition airport.cxx:182
flightgear::CommStationList commStationsOfType(FGPositioned::Type aTy) const
Definition airport.cxx:997
static FGAirportRef findClosest(const SGGeod &aPos, double aCuttofNm, Filter *filter=NULL)
Syntactic wrapper around FGPositioned::findClosest - find the closest match for filter,...
Definition airport.cxx:425
flightgear::Approach * getApproachByIndex(unsigned int aIndex) const
Definition airport.cxx:947
unsigned int numHelipads() const
Definition airport.cxx:109
static FGAirportRef findByIdent(const std::string &aIdent)
Helper to look up an FGAirport instance by unique ident.
Definition airport.cxx:489
flightgear::STAR * findSTARWithIdent(const std::string &aIdent) const
Definition airport.cxx:921
bool hasHelipadWithIdent(const std::string &aIdent) const
Definition airport.cxx:175
virtual const std::string & name() const
Return the name of this positioned.
Definition airport.hxx:75
bool hasRunwayWithIdent(const std::string &aIdent) const
Definition airport.cxx:162
FGTaxiwayRef getTaxiwayByIndex(unsigned int aIndex) const
Definition airport.cxx:337
flightgear::CommStationList commStations() const
Definition airport.cxx:983
SGGeod getTowerLocation() const
Definition airport.cxx:696
flightgear::Approach * findApproachWithIdent(const std::string &aIdent) const
Definition airport.cxx:954
flightgear::SID * findSIDWithIdent(const std::string &aIdent) const
Definition airport.cxx:887
FGHelipadRef getHelipadByIdent(const std::string &aIdent) const
Definition airport.cxx:199
unsigned int numSTARs() const
Definition airport.cxx:907
flightgear::SID * getSIDByIndex(unsigned int aIndex) const
Definition airport.cxx:880
Definition fix.hxx:34
double get_lat() const
Definition fix.hxx:44
double get_lon() const
Definition fix.hxx:43
static nav_list_type findAllByFreq(double freq, const SGGeod &position, TypeFilter *filter=NULL)
Definition navlist.cxx:244
static nav_list_type findByIdentAndFreq(const std::string &ident, const double freq, TypeFilter *filter=NULL)
int get_freq() const
Definition navrecord.hxx:76
int get_range() const
Definition navrecord.hxx:77
double get_lat() const
Definition navrecord.hxx:73
double get_elev_ft() const
Definition navrecord.hxx:74
double get_lon() const
Definition navrecord.hxx:72
bool hasDME() const
Definition navrecord.cxx:96
virtual const std::string & name() const
Return the name of this positioned.
Definition navrecord.hxx:85
double get_multiuse() const
Definition navrecord.hxx:78
PositionedID colocatedDME() const
FGRunwayRef runway() const
Retrieve the runway this navaid is associated with (for ILS/LOC/GS)
Definition navrecord.cxx:58
bool isVORTAC() const
static TypeFilter fromString(const std::string &aFilterSpec)
static Type typeFromName(const std::string &aName)
Map a candidate type string to a real type.
static FGPositionedRef createWaypoint(FGPositioned::Type aType, const std::string &aIdent, const SGGeod &aPos, bool isTemporary=false, const std::string &aName={})
double longitude() const
PositionedID guid() const
static FGPositionedList findWithinRange(const SGGeod &aPos, double aRangeNm, Filter *aFilter)
virtual const SGGeod & geod() const
double latitude() const
static void sortByRange(FGPositionedList &, const SGGeod &aPos)
Sort an FGPositionedList by distance from a position.
static SGSharedPtr< T > loadById(PositionedID id)
@ DME
important that DME & TACAN are adjacent to keep the TacanFilter efficient - DMEs are proxies for TACA...
static FGPositionedList findAllWithIdent(const std::string &aIdent, Filter *aFilter=NULL, bool aExact=true)
Find all items with the specified ident.
static const char * nameForType(Type aTy)
Map a type to a human-readable string.
Type type() const
const std::string & ident() const
static bool deleteWaypoint(FGPositionedRef aWpt)
double headingDeg() const
Runway heading in degrees.
double lengthFt() const
int surface() const
Retrieve runway surface code, as define in Robin Peel's data.
double widthM() const
double lengthM() const
FGAirportRef airport() const
flightgear::STARList getSTARs() const
Get STARs associared with this runway.
Definition runways.cxx:154
FGNavRecord * ILS() const
Definition runways.cxx:120
FGRunway * reciprocalRunway() const
Definition runways.cxx:115
flightgear::SIDList getSIDs() const
Get SIDs (DPs) associated with this runway.
Definition runways.cxx:140
double stopwayM() const
Definition runways.hxx:72
flightgear::ApproachList getApproaches(flightgear::ProcedureType type=flightgear::PROCEDURE_INVALID) const
Definition runways.cxx:169
double displacedThresholdM() const
Definition runways.hxx:69
static bool isType(FGPositioned::Type ty)
const std::string & name() const override
Return the name of this positioned.
Describe an approach procedure, including the missed approach segment.
virtual ProcedureType type() const
virtual RunwayVec runways() const
FGPositionedRef findCommByFreq(int freqKhz, const SGGeod &pos, FGPositioned::Filter *filt)
Find the closest matching comm-station on a frequency, to a position.
PositionedIDVec findCommsByFreq(int freqKhz, const SGGeod &pos, FGPositioned::Filter *filt)
Find all on a frequency, sorted by distance from a position The filter with be used for both type ran...
void updatePosition(PositionedID item, const SGGeod &pos)
Modify the position of an existing item.
FGPositionedRef loadById(PositionedID guid)
retrieve an FGPositioned from the cache.
static NavDataCache * instance()
virtual ProcedureType type() const =0
virtual std::string ident() const
Definition procedure.hxx:53
std::vector< FGRunwayRef > RunwayVec
Definition dynamics.cxx:444
const char * name
int fgGetInt(const char *name, int defaultValue)
Get an int value for a property.
Definition fg_props.cxx:532
FGGlobals * globals
Definition globals.cxx:142
FlightPlan.hxx - defines a full flight-plan object, including departure, cruise, arrival information ...
Definition Addon.cxx:53
SGSharedPtr< FGPositioned > FGPositionedRef
Definition airways.cxx:49
@ PROCEDURE_INVALID
Definition procedure.hxx:37
@ PROCEDURE_APPROACH_NDB
Definition procedure.hxx:40
@ PROCEDURE_APPROACH_VOR
Definition procedure.hxx:39
@ PROCEDURE_APPROACH_RNAV
Definition procedure.hxx:41
@ PROCEDURE_APPROACH_ILS
Definition procedure.hxx:38
naCFunction func
SGSharedPtr< FGNavRecord > FGNavRecordRef
std::vector< nav_rec_ptr > nav_list_type
Definition navlist.hxx:44
SGSharedPtr< FGNavRecord > nav_rec_ptr
Definition navlist.hxx:43
T * fgpositioned_cast(FGPositioned *p)
std::vector< FGPositionedRef > FGPositionedList
int64_t PositionedID
double fgGetDouble(const char *name, double defaultValue)
Get a double value for a property.
Definition proptest.cpp:30