]> git.mxchange.org Git - flightgear.git/blob - src/Scripting/NasalPositioned_cppbind.cxx
b2ae98c4d3390875b775dfbe127ed736227dbe18
[flightgear.git] / src / Scripting / NasalPositioned_cppbind.cxx
1 // NasalPositioned_cppbind.cxx -- expose FGPositioned classes to Nasal
2 //
3 // Port of NasalPositioned.cpp to the new nasal/cppbind helpers. Will replace
4 // old NasalPositioned.cpp once finished.
5 //
6 // Copyright (C) 2013  Thomas Geymayer <tomgey@gmail.com>
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25
26 #include "NasalPositioned.hxx"
27
28 #include <algorithm>
29 #include <functional>
30
31 #include <boost/foreach.hpp>
32 #include <boost/algorithm/string/case_conv.hpp>
33
34 #include <simgear/nasal/cppbind/from_nasal.hxx>
35 #include <simgear/nasal/cppbind/to_nasal.hxx>
36 #include <simgear/nasal/cppbind/NasalHash.hxx>
37 #include <simgear/nasal/cppbind/Ghost.hxx>
38
39 #include <Airports/airport.hxx>
40 #include <Airports/dynamics.hxx>
41 #include <ATC/CommStation.hxx>
42 #include <Navaids/NavDataCache.hxx>
43
44 typedef nasal::Ghost<FGPositionedRef> NasalPositioned;
45 typedef nasal::Ghost<FGRunwayRef> NasalRunway;
46 typedef nasal::Ghost<FGParkingRef> NasalParking;
47 typedef nasal::Ghost<FGAirportRef> NasalAirport;
48 typedef nasal::Ghost<flightgear::CommStationRef> NasalCommStation;
49
50 //------------------------------------------------------------------------------
51 naRef to_nasal_helper(naContext c, FGPositioned* positioned)
52 {
53   return NasalPositioned::create(c, positioned);
54 }
55
56 //------------------------------------------------------------------------------
57 naRef to_nasal_helper(naContext c, FGPavement* rwy)
58 {
59   return NasalPositioned::create(c, (FGPositioned*)rwy);
60 }
61
62 //------------------------------------------------------------------------------
63 naRef to_nasal_helper(naContext c, FGRunwayBase* rwy)
64 {
65   return NasalPositioned::create(c, (FGPositioned*)rwy);
66 }
67
68 //------------------------------------------------------------------------------
69 naRef to_nasal_helper(naContext c, FGParking* parking)
70 {
71   return NasalParking::create(c, parking);
72 }
73
74 //------------------------------------------------------------------------------
75 naRef to_nasal_helper(naContext c, flightgear::SID* sid)
76 {
77   // TODO SID ghost
78   return nasal::to_nasal(c, sid->ident());
79 }
80
81 //------------------------------------------------------------------------------
82 naRef to_nasal_helper(naContext c, flightgear::STAR* star)
83 {
84   // TODO STAR ghost
85   return nasal::to_nasal(c, star->ident());
86 }
87
88 //------------------------------------------------------------------------------
89 naRef to_nasal_helper(naContext c, flightgear::Approach* iap)
90 {
91   // TODO Approach ghost
92   return nasal::to_nasal(c, iap->ident());
93 }
94
95 //------------------------------------------------------------------------------
96 naRef to_nasal_helper(naContext c, FGAirport* apt)
97 {
98   return NasalAirport::create(c, apt);
99 }
100
101 //------------------------------------------------------------------------------
102 naRef to_nasal_helper(naContext c, const SGGeod& pos)
103 {
104   nasal::Hash hash(c);
105   hash.set("lat", pos.getLatitudeDeg());
106   hash.set("lon", pos.getLongitudeDeg());
107   hash.set("elevation", pos.getElevationM());
108   return hash.get_naRef();
109 }
110
111 //------------------------------------------------------------------------------
112 static FGRunwayBase* f_airport_runway(FGAirport& apt, std::string ident)
113 {
114   boost::to_upper(ident);
115
116   if( apt.hasRunwayWithIdent(ident) )
117     return apt.getRunwayByIdent(ident);
118   else if( apt.hasHelipadWithIdent(ident) )
119     return apt.getHelipadByIdent(ident);
120
121   return 0;
122 }
123
124 //------------------------------------------------------------------------------
125 template<class T, class C1, class C2>
126 std::vector<T> extract( const std::vector<C1*>& in,
127                         T (C2::*getter)() const )
128 {
129   std::vector<T> ret(in.size());
130   std::transform(in.begin(), in.end(), ret.begin(), std::mem_fun(getter));
131   return ret;
132 }
133
134 //------------------------------------------------------------------------------
135 static naRef f_airport_comms(FGAirport& apt, const nasal::CallContext& ctx)
136 {
137   FGPositioned::Type comm_type =
138     FGPositioned::typeFromName( ctx.getArg<std::string>(0) );
139
140   // if we have an explicit type, return a simple vector of frequencies
141   if( comm_type != FGPositioned::INVALID )
142     return ctx.to_nasal
143     (
144       extract( apt.commStationsOfType(comm_type),
145                &flightgear::CommStation::freqMHz )
146     );
147   else
148     // otherwise return a vector of ghosts, one for each comm station.
149     return ctx.to_nasal(apt.commStations());
150 }
151
152 //------------------------------------------------------------------------------
153 FGRunway* runwayFromNasalArg( const FGAirport& apt,
154                               const nasal::CallContext& ctx,
155                               size_t index = 0 )
156 {
157   if( index >= ctx.argc )
158     return NULL;
159
160   try
161   {
162     std::string ident = ctx.getArg<std::string>(index);
163     if( !ident.empty() )
164     {
165       if( !apt.hasRunwayWithIdent(ident) )
166         // TODO warning/exception?
167         return NULL;
168
169       return apt.getRunwayByIdent(ident);
170     }
171   }
172   catch(...)
173   {}
174
175   // TODO warn/error if no runway?
176   return NasalRunway::fromNasal(ctx.c, ctx.args[index]);
177 }
178
179 //------------------------------------------------------------------------------
180 static naRef f_airport_sids(FGAirport& apt, const nasal::CallContext& ctx)
181 {
182   FGRunway* rwy = runwayFromNasalArg(apt, ctx);
183   return ctx.to_nasal
184   (
185     extract(rwy ? rwy->getSIDs() : apt.getSIDs(), &flightgear::SID::ident)
186   );
187 }
188
189 //------------------------------------------------------------------------------
190 static naRef f_airport_stars(FGAirport& apt, const nasal::CallContext& ctx)
191 {
192   FGRunway* rwy = runwayFromNasalArg(apt, ctx);
193   return ctx.to_nasal
194   (
195     extract(rwy ? rwy->getSTARs() : apt.getSTARs(), &flightgear::STAR::ident)
196   );
197 }
198
199 //------------------------------------------------------------------------------
200 static naRef f_airport_approaches(FGAirport& apt, const nasal::CallContext& ctx)
201 {
202   FGRunway* rwy = runwayFromNasalArg(apt, ctx);
203
204   flightgear::ProcedureType type = flightgear::PROCEDURE_INVALID;
205   std::string type_str = ctx.getArg<std::string>(1);
206   if( !type_str.empty() )
207   {
208     boost::to_upper(type_str);
209     if(      type_str == "NDB" ) type = flightgear::PROCEDURE_APPROACH_NDB;
210     else if( type_str == "VOR" ) type = flightgear::PROCEDURE_APPROACH_VOR;
211     else if( type_str == "ILS" ) type = flightgear::PROCEDURE_APPROACH_ILS;
212     else if( type_str == "RNAV") type = flightgear::PROCEDURE_APPROACH_RNAV;
213   }
214
215   return ctx.to_nasal
216   (
217     extract( rwy ? rwy->getApproaches(type)
218                  // no runway specified, report them all
219                  : apt.getApproaches(type),
220              &flightgear::Approach::ident )
221   );
222 }
223
224 //------------------------------------------------------------------------------
225 static FGParkingList
226 f_airport_parking(FGAirport& apt, const nasal::CallContext& ctx)
227 {
228   std::string type = ctx.getArg<std::string>(0);
229   bool only_available = ctx.getArg<bool>(1);
230
231   FGAirportDynamics* dynamics = apt.getDynamics();
232   PositionedIDVec parkings =
233     flightgear::NavDataCache::instance()
234       ->airportItemsOfType(apt.guid(), FGPositioned::PARKING);
235
236   FGParkingList ret;
237   BOOST_FOREACH(PositionedID parking, parkings)
238   {
239     // filter out based on availability and type
240     if( only_available && !dynamics->isParkingAvailable(parking) )
241       continue;
242
243     FGParking* park = dynamics->getParking(parking);
244     if( !type.empty() && (park->getType() != type) )
245       continue;
246
247     ret.push_back(park);
248   }
249
250   return ret;
251 }
252
253 //------------------------------------------------------------------------------
254 // Returns Nasal ghost for particular or nearest airport of a <type>, or nil
255 // on error. (Currently only airportinfo(<id>) is implemented)
256 //
257 // airportinfo(<id>);                   e.g. "KSFO"
258 // airportinfo(<type>);                 type := ("airport"|"seaport"|"heliport")
259 // airportinfo()                        same as  airportinfo("airport")
260 // airportinfo(<lat>, <lon> [, <type>]);
261 static naRef f_airportinfo(naContext c, naRef me, int argc, naRef* args)
262 {
263   nasal::CallContext ctx(c, argc, args);
264   // TODO think of something comfortable to overload functions or use variable
265   //      number/types of arguments.
266   return ctx.to_nasal(FGAirport::findByIdent( ctx.requireArg<std::string>(0) ));
267 }
268
269 //------------------------------------------------------------------------------
270 naRef initNasalPositioned_cppbind(naRef globalsRef, naContext c, naRef gcSave)
271 {
272   NasalPositioned::init("FGPositioned")
273     .member("id", &FGPositioned::ident)
274     .member("ident", &FGPositioned::ident) // TODO to we really need id and ident?
275     .member("name", &FGPositioned::name)
276     .member("lat", &FGPositioned::latitude)
277     .member("lon", &FGPositioned::longitude)
278     .member("elevation", &FGPositioned::elevationM);
279   NasalRunway::init("FGRunway")
280     .bases<NasalPositioned>();
281   NasalParking::init("FGParking")
282     .bases<NasalPositioned>();
283   NasalCommStation::init("CommStation")
284     .bases<NasalPositioned>()
285     .member("frequency", &flightgear::CommStation::freqMHz);
286   NasalAirport::init("FGAirport")
287     .bases<NasalPositioned>()
288     .member("has_metar", &FGAirport::getMetar)
289     .member("runways", &FGAirport::getRunwayMap)
290     .member("helipads", &FGAirport::getHelipadMap)
291     .member("taxiways", &FGAirport::getTaxiways)
292     .member("pavements", &FGAirport::getPavements)
293     .method("runway", &f_airport_runway)
294     .method("helipad", &f_airport_runway)
295     .method("tower", &FGAirport::getTowerLocation)
296     .method("comms", &f_airport_comms)
297     .method("sids", &f_airport_sids)
298     .method("stars", &f_airport_stars)
299     .method("getApproachList", f_airport_approaches)
300     .method("parking", &f_airport_parking)
301     .method("getSid", &FGAirport::findSIDWithIdent)
302     .method("getStar", &FGAirport::findSTARWithIdent)
303     .method("getIAP", &FGAirport::findApproachWithIdent)
304     .method("tostring", &FGAirport::toString);
305
306   nasal::Hash globals(globalsRef, c),
307               positioned( globals.createHash("positioned") );
308
309   positioned.set("airportinfo", &f_airportinfo);
310
311   return naNil();
312 }