1 // NasalPositioned_cppbind.cxx -- expose FGPositioned classes to Nasal
3 // Port of NasalPositioned.cpp to the new nasal/cppbind helpers. Will replace
4 // old NasalPositioned.cpp once finished.
6 // Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
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.
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.
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.
26 #include "NasalPositioned.hxx"
31 #include <boost/foreach.hpp>
32 #include <boost/algorithm/string/case_conv.hpp>
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>
39 #include <Airports/airport.hxx>
40 #include <Airports/dynamics.hxx>
41 #include <ATC/CommStation.hxx>
42 #include <Main/globals.hxx>
43 #include <Navaids/NavDataCache.hxx>
45 typedef nasal::Ghost<FGPositionedRef> NasalPositioned;
46 typedef nasal::Ghost<FGRunwayRef> NasalRunway;
47 typedef nasal::Ghost<FGParkingRef> NasalParking;
48 typedef nasal::Ghost<FGAirportRef> NasalAirport;
49 typedef nasal::Ghost<flightgear::CommStationRef> NasalCommStation;
51 //------------------------------------------------------------------------------
52 naRef to_nasal_helper(naContext c, FGPositioned* positioned)
54 return NasalPositioned::create(c, positioned);
57 //------------------------------------------------------------------------------
58 naRef to_nasal_helper(naContext c, FGPavement* rwy)
60 return NasalPositioned::create(c, (FGPositioned*)rwy);
63 //------------------------------------------------------------------------------
64 naRef to_nasal_helper(naContext c, FGRunwayBase* rwy)
66 return NasalPositioned::create(c, (FGPositioned*)rwy);
69 //------------------------------------------------------------------------------
70 naRef to_nasal_helper(naContext c, FGParking* parking)
72 return NasalParking::create(c, parking);
75 //------------------------------------------------------------------------------
76 naRef to_nasal_helper(naContext c, flightgear::SID* sid)
79 return nasal::to_nasal(c, sid->ident());
82 //------------------------------------------------------------------------------
83 naRef to_nasal_helper(naContext c, flightgear::STAR* star)
86 return nasal::to_nasal(c, star->ident());
89 //------------------------------------------------------------------------------
90 naRef to_nasal_helper(naContext c, flightgear::Approach* iap)
92 // TODO Approach ghost
93 return nasal::to_nasal(c, iap->ident());
96 //------------------------------------------------------------------------------
97 naRef to_nasal_helper(naContext c, FGAirport* apt)
99 return NasalAirport::create(c, apt);
102 //------------------------------------------------------------------------------
103 naRef to_nasal_helper(naContext c, const SGGeod& pos)
106 hash.set("lat", pos.getLatitudeDeg());
107 hash.set("lon", pos.getLongitudeDeg());
108 hash.set("elevation", pos.getElevationM());
109 return hash.get_naRef();
112 //------------------------------------------------------------------------------
113 static FGRunwayBase* f_airport_runway(FGAirport& apt, std::string ident)
115 boost::to_upper(ident);
117 if( apt.hasRunwayWithIdent(ident) )
118 return apt.getRunwayByIdent(ident);
119 else if( apt.hasHelipadWithIdent(ident) )
120 return apt.getHelipadByIdent(ident);
125 //------------------------------------------------------------------------------
126 template<class T, class C1, class C2>
127 std::vector<T> extract( const std::vector<C1*>& in,
128 T (C2::*getter)() const )
130 std::vector<T> ret(in.size());
131 std::transform(in.begin(), in.end(), ret.begin(), std::mem_fun(getter));
135 //------------------------------------------------------------------------------
136 static naRef f_airport_comms(FGAirport& apt, const nasal::CallContext& ctx)
138 FGPositioned::Type comm_type =
139 FGPositioned::typeFromName( ctx.getArg<std::string>(0) );
141 // if we have an explicit type, return a simple vector of frequencies
142 if( comm_type != FGPositioned::INVALID )
145 extract( apt.commStationsOfType(comm_type),
146 &flightgear::CommStation::freqMHz )
149 // otherwise return a vector of ghosts, one for each comm station.
150 return ctx.to_nasal(apt.commStations());
153 //------------------------------------------------------------------------------
154 FGRunway* runwayFromNasalArg( const FGAirport& apt,
155 const nasal::CallContext& ctx,
158 if( index >= ctx.argc )
163 std::string ident = ctx.getArg<std::string>(index);
166 if( !apt.hasRunwayWithIdent(ident) )
167 // TODO warning/exception?
170 return apt.getRunwayByIdent(ident);
176 // TODO warn/error if no runway?
177 return NasalRunway::fromNasal(ctx.c, ctx.args[index]);
180 //------------------------------------------------------------------------------
181 static naRef f_airport_sids(FGAirport& apt, const nasal::CallContext& ctx)
183 FGRunway* rwy = runwayFromNasalArg(apt, ctx);
186 extract(rwy ? rwy->getSIDs() : apt.getSIDs(), &flightgear::SID::ident)
190 //------------------------------------------------------------------------------
191 static naRef f_airport_stars(FGAirport& apt, const nasal::CallContext& ctx)
193 FGRunway* rwy = runwayFromNasalArg(apt, ctx);
196 extract(rwy ? rwy->getSTARs() : apt.getSTARs(), &flightgear::STAR::ident)
200 //------------------------------------------------------------------------------
201 static naRef f_airport_approaches(FGAirport& apt, const nasal::CallContext& ctx)
203 FGRunway* rwy = runwayFromNasalArg(apt, ctx);
205 flightgear::ProcedureType type = flightgear::PROCEDURE_INVALID;
206 std::string type_str = ctx.getArg<std::string>(1);
207 if( !type_str.empty() )
209 boost::to_upper(type_str);
210 if( type_str == "NDB" ) type = flightgear::PROCEDURE_APPROACH_NDB;
211 else if( type_str == "VOR" ) type = flightgear::PROCEDURE_APPROACH_VOR;
212 else if( type_str == "ILS" ) type = flightgear::PROCEDURE_APPROACH_ILS;
213 else if( type_str == "RNAV") type = flightgear::PROCEDURE_APPROACH_RNAV;
218 extract( rwy ? rwy->getApproaches(type)
219 // no runway specified, report them all
220 : apt.getApproaches(type),
221 &flightgear::Approach::ident )
225 //------------------------------------------------------------------------------
227 f_airport_parking(FGAirport& apt, const nasal::CallContext& ctx)
229 std::string type = ctx.getArg<std::string>(0);
230 bool only_available = ctx.getArg<bool>(1);
232 FGAirportDynamics* dynamics = apt.getDynamics();
233 PositionedIDVec parkings =
234 flightgear::NavDataCache::instance()
235 ->airportItemsOfType(apt.guid(), FGPositioned::PARKING);
238 BOOST_FOREACH(PositionedID parking, parkings)
240 // filter out based on availability and type
241 if( only_available && !dynamics->isParkingAvailable(parking) )
244 FGParking* park = dynamics->getParking(parking);
245 if( !type.empty() && (park->getType() != type) )
254 //------------------------------------------------------------------------------
255 // Returns Nasal ghost for particular or nearest airport of a <type>, or nil
258 // airportinfo(<id>); e.g. "KSFO"
259 // airportinfo(<type>); type := ("airport"|"seaport"|"heliport")
260 // airportinfo() same as airportinfo("airport")
261 // airportinfo(<lat>, <lon> [, <type>]);
262 static naRef f_airportinfo(naContext c, naRef me, int argc, naRef* args)
264 nasal::CallContext ctx(c, argc, args);
265 // TODO think of something comfortable to overload functions or use variable
266 // number/types of arguments.
268 std::string ident = "airport";
269 SGGeod pos = globals->get_aircraft_position();
273 ident = ctx.requireArg<std::string>(0);
275 else if( ctx.argc >= 2 )
277 // Why are lat/lon swapped?
278 pos = SGGeod::fromDeg( ctx.requireArg<double>(1),
279 ctx.requireArg<double>(0) );
282 ident = ctx.requireArg<std::string>(2);
285 naRuntimeError(ctx.c, "airportinfo() with invalid function arguments");
288 FGAirport::TypeRunwayFilter filter;
289 if( !filter.fromTypeString(ident) )
290 // user provided an <id>, hopefully
291 return ctx.to_nasal(FGAirport::findByIdent(ident));
293 double maxRange = 10000.0; // expose this? or pick a smaller value?
294 return ctx.to_nasal( FGAirport::findClosest(pos, maxRange, &filter) );
297 //------------------------------------------------------------------------------
298 naRef initNasalPositioned_cppbind(naRef globalsRef, naContext c, naRef gcSave)
300 NasalPositioned::init("FGPositioned")
301 .member("id", &FGPositioned::ident)
302 .member("ident", &FGPositioned::ident) // TODO to we really need id and ident?
303 .member("name", &FGPositioned::name)
304 .member("lat", &FGPositioned::latitude)
305 .member("lon", &FGPositioned::longitude)
306 .member("elevation", &FGPositioned::elevationM);
307 NasalRunway::init("FGRunway")
308 .bases<NasalPositioned>();
309 NasalParking::init("FGParking")
310 .bases<NasalPositioned>();
311 NasalCommStation::init("CommStation")
312 .bases<NasalPositioned>()
313 .member("frequency", &flightgear::CommStation::freqMHz);
314 NasalAirport::init("FGAirport")
315 .bases<NasalPositioned>()
316 .member("has_metar", &FGAirport::getMetar)
317 .member("runways", &FGAirport::getRunwayMap)
318 .member("helipads", &FGAirport::getHelipadMap)
319 .member("taxiways", &FGAirport::getTaxiways)
320 .member("pavements", &FGAirport::getPavements)
321 .method("runway", &f_airport_runway)
322 .method("helipad", &f_airport_runway)
323 .method("tower", &FGAirport::getTowerLocation)
324 .method("comms", &f_airport_comms)
325 .method("sids", &f_airport_sids)
326 .method("stars", &f_airport_stars)
327 .method("getApproachList", f_airport_approaches)
328 .method("parking", &f_airport_parking)
329 .method("getSid", &FGAirport::findSIDWithIdent)
330 .method("getStar", &FGAirport::findSTARWithIdent)
331 .method("getIAP", &FGAirport::findApproachWithIdent)
332 .method("tostring", &FGAirport::toString);
334 nasal::Hash globals(globalsRef, c),
335 positioned( globals.createHash("positioned") );
337 positioned.set("airportinfo", &f_airportinfo);