FlightGear next
ATISEncoder.cxx
Go to the documentation of this file.
1/*
2Encode an ATIS into spoken words
3Copyright (C) 2014 Torsten Dreyer
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18*/
19
20#include "ATISEncoder.hxx"
21#include <Airports/dynamics.hxx>
22#include <Main/globals.hxx>
23#include <Main/locale.hxx>
24#include <simgear/structure/exception.hxx>
25#include <simgear/props/props_io.hxx>
26
27#include <map>
28#include <string>
29#include <vector>
30
31using std::string;
32using std::vector;
33using simgear::PropertyList;
34
35static string NO_ATIS("nil");
36static string EMPTY("");
37#define SPACE append(1,' ')
38
39static string getSpokenForm(const string& text)
40{
41 return globals->get_locale()->getLocalizedString(text, "atc", text);
42}
43
44static string getSpokenFormWithDefault(const string& text,
45 const string& defaultValue)
46{
47 return globals->get_locale()->getLocalizedString(text, "atc", defaultValue);
48}
49
50std::string ATCSpeech::getSpokenDigit( int i )
51{
52 string key = "n" + std::to_string(i);
53 return getSpokenFormWithDefault(key, "");
54}
55
56string ATCSpeech::getSpokenNumber( string number )
57{
58 string result;
59 for( string::iterator it = number.begin(); it != number.end(); ++it ) {
60 if( !result.empty() )
61 result.SPACE;
62 result.append( getSpokenDigit( (*it) - '0' ));
63 }
64 return result;
65}
66
67string ATCSpeech::getSpokenNumber( int number, bool leadingZero, int digits )
68{
69 string_list spokenDigits;
70 bool negative = false;
71 if( number < 0 ) {
72 negative = true;
73 number = -number;
74 }
75
76 int n = 0;
77 while( number > 0 ) {
78 spokenDigits.push_back( getSpokenDigit(number%10) );
79 number /= 10;
80 n++;
81 }
82
83 if( digits > 0 ) {
84 while( n++ < digits ) {
85 spokenDigits.push_back( getSpokenDigit(0) );
86 }
87 }
88
89 string result;
90 if( negative ) {
91 result.append(getSpokenForm("minus"));
92 }
93
94 while( !spokenDigits.empty() ) {
95 if( !result.empty() )
96 result.SPACE;
97
98 result.append( spokenDigits.back() );
99 spokenDigits.pop_back();
100 }
101
102 return result;
103}
104
106{
107 string result;
108 int thousands = altitude / 1000;
109 int hundreds = (altitude % 1000) / 100;
110
111 if( thousands > 0 ) {
112 result.append( getSpokenNumber(thousands) );
113 result.SPACE;
114 result.append( getSpokenDigit(1000) );
115 result.SPACE;
116 }
117 if( hundreds > 0 )
118 result.append( getSpokenNumber(hundreds) )
119 .SPACE
120 .append( getSpokenDigit(100) );
121
122 return result;
123}
124
126{
127 handlerMap.insert( std::make_pair( "text", &ATISEncoder::processTextToken ));
128 handlerMap.insert( std::make_pair( "token", &ATISEncoder::processTokenToken ));
129 handlerMap.insert( std::make_pair( "if", &ATISEncoder::processIfToken ));
130 handlerMap.insert( std::make_pair( "section", &ATISEncoder::processTokens ));
131
132 handlerMap.insert( std::make_pair( "id", &ATISEncoder::getAtisId ));
133 handlerMap.insert( std::make_pair( "airport-name", &ATISEncoder::getAirportName ));
134 handlerMap.insert( std::make_pair( "time", &ATISEncoder::getTime ));
135 handlerMap.insert( std::make_pair( "approach-type", &ATISEncoder::getApproachType ));
136 handlerMap.insert( std::make_pair( "rwy-land", &ATISEncoder::getLandingRunway ));
137 handlerMap.insert( std::make_pair( "rwy-to", &ATISEncoder::getTakeoffRunway ));
138 handlerMap.insert( std::make_pair( "transition-level", &ATISEncoder::getTransitionLevel ));
139 handlerMap.insert( std::make_pair( "wind-dir", &ATISEncoder::getWindDirection ));
140 handlerMap.insert( std::make_pair( "wind-from", &ATISEncoder::getWindMinDirection ));
141 handlerMap.insert( std::make_pair( "wind-to", &ATISEncoder::getWindMaxDirection ));
142 handlerMap.insert( std::make_pair( "wind-speed-kn", &ATISEncoder::getWindspeedKnots ));
143 handlerMap.insert( std::make_pair( "gusts", &ATISEncoder::getGustsKnots ));
144 handlerMap.insert( std::make_pair( "visibility-metric", &ATISEncoder::getVisibilityMetric ));
145 handlerMap.insert( std::make_pair( "visibility-miles", &ATISEncoder::getVisibilityMiles ));
146 handlerMap.insert( std::make_pair( "phenomena", &ATISEncoder::getPhenomena ));
147 handlerMap.insert( std::make_pair( "clouds", &ATISEncoder::getClouds ));
148 handlerMap.insert( std::make_pair( "clouds-brief", &ATISEncoder::getCloudsBrief ));
149 handlerMap.insert( std::make_pair( "cavok", &ATISEncoder::getCavok ));
150 handlerMap.insert( std::make_pair( "temperature-deg", &ATISEncoder::getTemperatureDeg ));
151 handlerMap.insert( std::make_pair( "dewpoint-deg", &ATISEncoder::getDewpointDeg ));
152 handlerMap.insert( std::make_pair( "qnh", &ATISEncoder::getQnh ));
153 handlerMap.insert( std::make_pair( "inhg", &ATISEncoder::getInhg ));
154 handlerMap.insert( std::make_pair( "inhg-integer", &ATISEncoder::getInhgInteger ));
155 handlerMap.insert( std::make_pair( "inhg-fraction", &ATISEncoder::getInhgFraction ));
156 handlerMap.insert( std::make_pair( "trend", &ATISEncoder::getTrend ));
157}
158
162
163SGPropertyNode_ptr findAtisTemplate( const std::string & stationId, SGPropertyNode_ptr atisSchemaNode )
164{
165 using simgear::strutils::starts_with;
166 SGPropertyNode_ptr atisTemplate;
167
168 PropertyList schemaNodes = atisSchemaNode->getChildren("atis-schema");
169 for( PropertyList::iterator asit = schemaNodes.begin(); asit != schemaNodes.end(); ++asit ) {
170 SGPropertyNode_ptr ppp = (*asit)->getNode("station-starts-with", false );
171 atisTemplate = (*asit)->getNode("atis", false );
172 if( !atisTemplate.valid() ) continue; // no <atis> node - ignore entry
173
174 PropertyList startsWithNodes = (*asit)->getChildren("station-starts-with");
175 for( PropertyList::iterator swit = startsWithNodes.begin(); swit != startsWithNodes.end(); ++swit ) {
176
177 if( starts_with( stationId, (*swit)->getStringValue() ) ) {
178 return atisTemplate;
179 }
180 }
181
182 }
183
184 return atisTemplate;
185}
186
188{
189 using simgear::strutils::lowercase;
190
191 if( !atisInformation->isValid() ) return NO_ATIS;
192
193 airport = FGAirport::getByIdent( atisInformation->airportId() );
194 if( !airport.valid() ) {
195 SG_LOG( SG_ATC, SG_WARN, "ATISEncoder: unknown airport id " << atisInformation->airportId() );
196 return NO_ATIS;
197 }
198
199 _atis = atisInformation;
200
201 // lazily load the schema file on the first call
202 if( !atisSchemaNode.valid() ) {
203 atisSchemaNode = new SGPropertyNode();
204 try
205 {
206 SGPath path = globals->resolve_maybe_aircraft_path("ATC/atis.xml");
207 readProperties( path, atisSchemaNode );
208 }
209 catch (const sg_exception& e)
210 {
211 SG_LOG( SG_ATC, SG_ALERT, "ATISEncoder: Failed to load atis schema definition: " << e.getMessage());
212 return NO_ATIS;
213 }
214 }
215
216 string stationId = lowercase( airport->ident() );
217
218 SGPropertyNode_ptr atisTemplate = findAtisTemplate( stationId, atisSchemaNode );;
219 if( !atisTemplate.valid() ) {
220 SG_LOG(SG_ATC, SG_WARN, "no matching atis template for station " << stationId );
221 return NO_ATIS; // no template for this station!?
222 }
223
224 return processTokens( atisTemplate );
225}
226
227string ATISEncoder::processTokens( SGPropertyNode_ptr node )
228{
229 string result;
230 if( node.valid() ) {
231 for( int i = 0; i < node->nChildren(); i++ ) {
232 result.append(processToken( node->getChild(i) ));
233 }
234 }
235 return result;
236}
237
238string ATISEncoder::processToken( SGPropertyNode_ptr token )
239{
240 HandlerMap::iterator it = handlerMap.find( token->getNameString());
241 if( it == handlerMap.end() ) {
242 SG_LOG(SG_ATC, SG_WARN, "ATISEncoder: unknown token: " << token->getNameString() );
243 return EMPTY;
244 }
245 handler_t h = it->second;
246 return (this->*h)( token );
247}
248
249string ATISEncoder::processTextToken( SGPropertyNode_ptr token )
250{
251 return token->getStringValue();
252}
253
254string ATISEncoder::processTokenToken( SGPropertyNode_ptr token )
255{
256 HandlerMap::iterator it = handlerMap.find( token->getStringValue());
257 if( it == handlerMap.end() ) {
258 SG_LOG(SG_ATC, SG_WARN, "ATISEncoder: unknown token: " << token->getStringValue() );
259 return EMPTY;
260 }
261 handler_t h = it->second;
262 return (this->*h)( token );
263}
264
265string ATISEncoder::processIfToken( SGPropertyNode_ptr token )
266{
267 using namespace simgear::strutils;
268
269 SGPropertyNode_ptr n;
270
271 if( (n = token->getChild("empty", false )).valid() ) {
272 return checkEmptyCondition( n, true) ?
273 processTokens(token->getChild("then",false)) :
274 processTokens(token->getChild("else",false));
275 }
276
277 if( (n = token->getChild("not-empty", false )).valid() ) {
278 return checkEmptyCondition( n, false) ?
279 processTokens(token->getChild("then",false)) :
280 processTokens(token->getChild("else",false));
281 }
282
283 if( (n = token->getChild("contains", false )).valid() ) {
284 return checkCondition( n, true, &contains, "contains") ?
285 processTokens(token->getChild("then",false)) :
286 processTokens(token->getChild("else",false));
287 }
288
289 if( (n = token->getChild("not-contains", false )).valid() ) {
290 return checkCondition( n, false, &contains, "not-contains") ?
291 processTokens(token->getChild("then",false)) :
292 processTokens(token->getChild("else",false));
293 }
294
295 if( (n = token->getChild("ends-with", false )).valid() ) {
296 return checkCondition( n, true, &ends_with, "ends-with") ?
297 processTokens(token->getChild("then",false)) :
298 processTokens(token->getChild("else",false));
299 }
300
301 if( (n = token->getChild("not-ends-with", false )).valid() ) {
302 return checkCondition( n, false, &ends_with, "not-ends-with") ?
303 processTokens(token->getChild("then",false)) :
304 processTokens(token->getChild("else",false));
305 }
306
307 if( (n = token->getChild("equals", false )).valid() ) {
308 return checkCondition( n, true, &equals, "equals") ?
309 processTokens(token->getChild("then",false)) :
310 processTokens(token->getChild("else",false));
311 }
312
313 if( (n = token->getChild("not-equals", false )).valid() ) {
314 return checkCondition( n, false, &equals, "not-equals") ?
315 processTokens(token->getChild("then",false)) :
316 processTokens(token->getChild("else",false));
317 }
318
319 if( (n = token->getChild("starts-with", false )).valid() ) {
320 return checkCondition( n, true, &starts_with, "starts-with") ?
321 processTokens(token->getChild("then",false)) :
322 processTokens(token->getChild("else",false));
323 }
324
325 if( (n = token->getChild("not-starts-with", false )).valid() ) {
326 return checkCondition( n, false, &starts_with, "not-starts-with") ?
327 processTokens(token->getChild("then",false)) :
328 processTokens(token->getChild("else",false));
329 }
330
331 SG_LOG(SG_ATC, SG_WARN, "ATISEncoder: no valid token found for <if> element" );
332
333 return EMPTY;
334}
335
336bool ATISEncoder::checkEmptyCondition( SGPropertyNode_ptr node, bool isEmpty )
337{
338 SGPropertyNode_ptr n1 = node->getNode( "token", false );
339 if( !n1.valid() ) {
340 SG_LOG(SG_ATC, SG_WARN, "missing <token> node for (not)-empty" );
341 return false;
342 }
343 return processToken( n1 ).empty() == isEmpty;
344}
345
346bool ATISEncoder::checkCondition( SGPropertyNode_ptr node, bool notInverted,
347 bool (*fp)(const string &, const string &), const string &name )
348{
349 using namespace simgear::strutils;
350
351 SGPropertyNode_ptr n1 = node->getNode( "token", 0, false );
352 SGPropertyNode_ptr n2 = node->getNode( "token", 1, false );
353
354 if( n1.valid() && n2.valid() ) {
355 bool comp = fp( processToken( n1 ), processToken( n2 ) );
356 return comp == notInverted;
357 }
358
359 if( n1.valid() && !n2.valid() ) {
360 SGPropertyNode_ptr t1 = node->getNode( "text", 0, false );
361 if( t1.valid() ) {
362 string n1s = lowercase( strip( processToken( n1 ) ) );
363 string t1s = lowercase( strip( processTextToken( t1 ) ) );
364 return fp( n1s, t1s ) == notInverted;
365 }
366 SG_LOG(SG_ATC, SG_WARN, "missing <token> or <text> node for " << name);
367 return false;
368 }
369
370 SG_LOG(SG_ATC, SG_WARN, "missing <token> node for " << name);
371 return false;
372}
373
374string ATISEncoder::getAtisId( SGPropertyNode_ptr )
375{
376 FGAirportDynamics * dynamics = airport->getDynamics();
377 if( NULL != dynamics ) {
378 dynamics->updateAtisSequence( 30*60, false );
379 return dynamics->getAtisSequence();
380 }
381 return EMPTY;
382}
383
384string ATISEncoder::getAirportName( SGPropertyNode_ptr )
385{
386 return airport->getName();
387}
388
389string ATISEncoder::getTime( SGPropertyNode_ptr )
390{
391 return getSpokenNumber( _atis->getTime() % (100*100), true, 4 );
392}
393
394static inline FGRunwayRef findBestRunwayForWind( FGAirportRef airport, int windDeg, int windKt )
395{
397 // TODO: ramp down the heading weight with wind speed
398 p.ilsWeight = 4;
399 return airport->findBestRunwayForHeading( windDeg, &p );
400}
401
402string ATISEncoder::getApproachType( SGPropertyNode_ptr )
403{
404 FGRunwayRef runway = findBestRunwayForWind( airport, _atis->getWindDeg(), _atis->getWindSpeedKt() );
405 if( runway.valid() ) {
406 if (runway->ILS() != nullptr) {
407 return getSpokenForm("ils");
408 }
409 // TODO: any chance to find other approach types? localizer-dme, vor-dme, vor, ndb?
410 }
411
412 return getSpokenForm("visual");
413}
414
415string ATISEncoder::getLandingRunway( SGPropertyNode_ptr )
416{
417 FGRunwayRef runway = findBestRunwayForWind( airport, _atis->getWindDeg(), _atis->getWindSpeedKt() );
418 if( runway.valid() ) {
419 string runwayIdent = runway->ident();
420 if(runwayIdent != "NN") {
421 return getSpokenNumber(runwayIdent);
422 }
423 }
424 return EMPTY;
425}
426
427string ATISEncoder::getTakeoffRunway( SGPropertyNode_ptr p )
428{
429 // TODO: if the airport has more than one runway, probably pick another one?
430 return getLandingRunway( p );
431}
432
433string ATISEncoder::getTransitionLevel(SGPropertyNode_ptr)
434{
435 double hPa = _atis->getQnh();
436
437 /* Transition level is the flight level above which aircraft must use standard pressure and below
438 * which airport pressure settings must be used.
439 * Following definitions are taken from German ATIS:
440 * QNH <= 977 hPa: TRL 80
441 * QNH <= 1013 hPa: TRL 70
442 * QNH > 1013 hPa: TRL 60
443 * (maybe differs slightly for other countries...)
444 */
445 int tl;
446 if (hPa <= 978) {
447 tl = 80;
448 } else if (hPa <= 1013) {
449 tl = 70;
450 } else if (hPa <= 1046) {
451 tl = 60;
452 } else {
453 tl = 50;
454 }
455
456 // add an offset to the transition level for high altitude airports (just guessing here,
457 // seems reasonable)
458 int e = int(airport->getElevation() / 1000.0);
459 if (e >= 3) {
460 // TL steps in 10(00)ft
461 tl += (e - 2) * 10;
462 }
463
464 return getSpokenNumber(tl);
465}
466
467string ATISEncoder::getWindDirection( SGPropertyNode_ptr )
468{
469 string variable = getSpokenForm("variable");
470
471 bool vrb = _atis->getWindMinDeg() == 0 && _atis->getWindMaxDeg() == 359;
472 return vrb ? variable : getSpokenNumber( _atis->getWindDeg(), true, 3 );
473}
474
475string ATISEncoder::getWindMinDirection( SGPropertyNode_ptr )
476{
477 return getSpokenNumber( _atis->getWindMinDeg(), true, 3 );
478}
479
480string ATISEncoder::getWindMaxDirection( SGPropertyNode_ptr )
481{
482 return getSpokenNumber( _atis->getWindMaxDeg(), true, 3 );
483}
484
485string ATISEncoder::getWindspeedKnots( SGPropertyNode_ptr )
486{
487 return getSpokenNumber( _atis->getWindSpeedKt() );
488}
489
490string ATISEncoder::getGustsKnots( SGPropertyNode_ptr )
491{
492 int g = _atis->getGustsKt();
493 return g > 0 ? getSpokenNumber( g ) : EMPTY;
494}
495
496string ATISEncoder::getCavok( SGPropertyNode_ptr )
497{
498 string CAVOK = getSpokenForm("cavok");
499
500 return _atis->isCavok() ? CAVOK : EMPTY;
501}
502
503string ATISEncoder::getVisibilityMetric( SGPropertyNode_ptr )
504{
505 string m = getSpokenForm("meters");
506 string km = getSpokenForm("kilometers");
507 string or_more = getSpokenFormWithDefault("ormore", "or more");
508
509 int v = _atis->getVisibilityMeters();
510 string reply;
511 if( v < 5000 ) return reply.append( getSpokenAltitude( v ) ).SPACE.append( m );
512 if( v >= 9999 ) return reply.append( getSpokenNumber(10) ).SPACE.append( km ).SPACE.append(or_more);
513 return reply.append( getSpokenNumber( v/1000 ).SPACE.append( km ) );
514}
515
516string ATISEncoder::getVisibilityMiles( SGPropertyNode_ptr )
517{
518 string feet = getSpokenForm("feet");
519
520 int v = _atis->getVisibilityMeters();
521 int vft = int( v * SG_METER_TO_FEET / 100 + 0.5 ) * 100; // Rounded to 100 ft
522 int vsm = int( v * SG_METER_TO_SM + 0.5 );
523
524 string reply;
525 if( vsm < 1 ) return reply.append( getSpokenAltitude( vft ) ).SPACE.append( feet );
526 if( vsm >= 10 ) return reply.append( getSpokenNumber(10) );
527 return reply.append( getSpokenNumber( vsm ) );
528}
529
530string ATISEncoder::getPhenomena( SGPropertyNode_ptr )
531{
532 return _atis->getPhenomena();
533}
534
535string ATISEncoder::getClouds( SGPropertyNode_ptr )
536{
537 string FEET = getSpokenForm("feet");
538 string reply;
539
540 ATISInformationProvider::CloudEntries cloudEntries = _atis->getClouds();
541
542 for (ATISInformationProvider::CloudEntries::iterator it = cloudEntries.begin(); it != cloudEntries.end(); ++it) {
543 if (!reply.empty())
544 reply.SPACE;
545 reply.append( it->second ).SPACE.append( getSpokenAltitude(it->first).SPACE.append( FEET ) );
546 }
547
548 return reply;
549}
550
551string ATISEncoder::getCloudsBrief( SGPropertyNode_ptr )
552{
553 string reply;
554
555 ATISInformationProvider::CloudEntries cloudEntries = _atis->getClouds();
556
557 for (ATISInformationProvider::CloudEntries::iterator it = cloudEntries.begin(); it != cloudEntries.end(); ++it) {
558 if (!reply.empty())
559 reply.append(",").SPACE;
560 reply.append( it->second ).SPACE.append( getSpokenAltitude(it->first) );
561 }
562
563 return reply;
564}
565
566string ATISEncoder::getTemperatureDeg( SGPropertyNode_ptr )
567{
568 return getSpokenNumber( _atis->getTemperatureDeg() );
569}
570
571string ATISEncoder::getDewpointDeg( SGPropertyNode_ptr )
572{
573 return getSpokenNumber( _atis->getDewpointDeg() );
574}
575
576string ATISEncoder::getQnh( SGPropertyNode_ptr )
577{
578 return getSpokenNumber( _atis->getQnh() );
579}
580
581string ATISEncoder::getInhgInteger( SGPropertyNode_ptr )
582{
583 double qnh = _atis->getQnhInHg();
584 return getSpokenNumber( (int)qnh, true, 2 );
585}
586
587string ATISEncoder::getInhgFraction( SGPropertyNode_ptr )
588{
589 double qnh = _atis->getQnhInHg();
590 int f = int(100 * (qnh - int(qnh)) + 0.5);
591 return getSpokenNumber( f, true, 2 );
592}
593
594string ATISEncoder::getInhg( SGPropertyNode_ptr node)
595{
596 string DECIMAL = getSpokenFormWithDefault("dp", "decimal");
597 return getInhgInteger(node)
598 .SPACE.append(DECIMAL).SPACE
599 .append(getInhgFraction(node));
600}
601
602string ATISEncoder::getTrend( SGPropertyNode_ptr )
603{
604 return _atis->getTrend();
605}
606
double altitude
Definition ADA.cxx:46
static string getSpokenFormWithDefault(const string &text, const string &defaultValue)
SGPropertyNode_ptr findAtisTemplate(const std::string &stationId, SGPropertyNode_ptr atisSchemaNode)
static FGRunwayRef findBestRunwayForWind(FGAirportRef airport, int windDeg, int windKt)
#define SPACE
static string NO_ATIS("nil")
static string EMPTY("")
static string getSpokenForm(const string &text)
#define p(x)
#define i(x)
SGSharedPtr< FGAirport > FGAirportRef
SGSharedPtr< FGRunway > FGRunwayRef
static std::string getSpokenNumber(std::string number)
static std::string getSpokenAltitude(int altitude)
static std::string getSpokenDigit(int i)
virtual std::string getCavok(SGPropertyNode_ptr)
virtual std::string getInhg(SGPropertyNode_ptr)
ATISInformationProvider * _atis
virtual std::string getAtisId(SGPropertyNode_ptr)
virtual std::string getVisibilityMiles(SGPropertyNode_ptr)
static bool equals(const std::string &s1, const std::string &s2)
std::string processTokenToken(SGPropertyNode_ptr baseNode)
virtual std::string getVisibilityMetric(SGPropertyNode_ptr)
virtual std::string getCloudsBrief(SGPropertyNode_ptr)
virtual std::string getQnh(SGPropertyNode_ptr)
virtual std::string getApproachType(SGPropertyNode_ptr)
virtual std::string getInhgFraction(SGPropertyNode_ptr)
std::string processIfToken(SGPropertyNode_ptr baseNode)
virtual std::string getPhenomena(SGPropertyNode_ptr)
virtual std::string getAirportName(SGPropertyNode_ptr)
std::string processTextToken(SGPropertyNode_ptr baseNode)
std::string processTokens(SGPropertyNode_ptr baseNode)
virtual std::string getLandingRunway(SGPropertyNode_ptr)
virtual ~ATISEncoder()
std::string(ATISEncoder::* handler_t)(SGPropertyNode_ptr baseNode)
virtual std::string getTakeoffRunway(SGPropertyNode_ptr)
bool checkCondition(SGPropertyNode_ptr node, bool notInverted, bool(*fp)(const std::string &, const std::string &), const std::string &name)
std::string processToken(SGPropertyNode_ptr baseNode)
virtual std::string getClouds(SGPropertyNode_ptr)
virtual std::string encodeATIS(ATISInformationProvider *atisInformationProvider)
virtual std::string getDewpointDeg(SGPropertyNode_ptr)
virtual std::string getTransitionLevel(SGPropertyNode_ptr)
HandlerMap handlerMap
virtual std::string getWindMaxDirection(SGPropertyNode_ptr)
virtual std::string getTemperatureDeg(SGPropertyNode_ptr)
virtual std::string getTime(SGPropertyNode_ptr)
virtual std::string getInhgInteger(SGPropertyNode_ptr)
SGPropertyNode_ptr atisSchemaNode
virtual std::string getWindDirection(SGPropertyNode_ptr)
virtual std::string getWindMinDirection(SGPropertyNode_ptr)
virtual std::string getGustsKnots(SGPropertyNode_ptr)
static bool contains(const std::string &s, const std::string &substring)
virtual std::string getWindspeedKnots(SGPropertyNode_ptr)
virtual std::string getTrend(SGPropertyNode_ptr)
FGAirportRef airport
bool checkEmptyCondition(SGPropertyNode_ptr node, bool isEmpty)
virtual bool isValid() const =0
std::map< int, std::string > CloudEntries
virtual std::string airportId() const =0
const std::string getAtisSequence()
get current ATIS sequence letter
Definition dynamics.cxx:980
int updateAtisSequence(int interval, bool forceUpdate)
get the current ATIS sequence number, updating it if necessary
Definition dynamics.cxx:993
static FGAirportRef getByIdent(const std::string &aIdent)
Helper to look up an FGAirport instance by unique ident.
Definition airport.cxx:509
const char * name
FGGlobals * globals
Definition globals.cxx:142
std::vector< std::string > string_list
Definition globals.hxx:36
FlightGear Localization Support.