Add Melchior FRANZ's metar class. It is not yet used anywhere (but in the resulting metar executable), but it makes adding live weather quite easy.
This commit is contained in:
parent
816d84457c
commit
f845aa9b2a
4 changed files with 1858 additions and 3 deletions
src/Environment
|
@ -4,8 +4,19 @@
|
||||||
|
|
||||||
noinst_LIBRARIES = libEnvironment.a
|
noinst_LIBRARIES = libEnvironment.a
|
||||||
|
|
||||||
libEnvironment_a_SOURCES = environment.cxx environment.hxx \
|
libEnvironment_a_SOURCES = \
|
||||||
|
environment.cxx environment.hxx \
|
||||||
environment_mgr.cxx environment_mgr.hxx \
|
environment_mgr.cxx environment_mgr.hxx \
|
||||||
environment_ctrl.cxx environment_ctrl.hxx
|
environment_ctrl.cxx environment_ctrl.hxx \
|
||||||
|
metar.cxx metar.hxx
|
||||||
|
|
||||||
|
bin_PROGRAMS = metar
|
||||||
|
|
||||||
|
metar_SOURCES = metar-main.cxx metar.cxx metar.hxx
|
||||||
|
|
||||||
|
metar_LDADD = \
|
||||||
|
-lsgio -lsgbucket -lsgmisc -lsgstructure -lsgdebug \
|
||||||
|
-lplibnet -lplibul \
|
||||||
|
-lz $(base_LIBS)
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
||||||
|
|
482
src/Environment/metar-main.cxx
Normal file
482
src/Environment/metar-main.cxx
Normal file
|
@ -0,0 +1,482 @@
|
||||||
|
// metar interface class demo
|
||||||
|
//
|
||||||
|
// Written by Melchior FRANZ, started December 2003.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2003 Melchior FRANZ - mfranz@aon.at
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <simgear/structure/exception.hxx>
|
||||||
|
|
||||||
|
#include "metar.hxx"
|
||||||
|
|
||||||
|
using std::ostringstream;
|
||||||
|
|
||||||
|
// text color
|
||||||
|
#if defined(__linux__) || defined( __sun__ ) ||defined(__CYGWIN__) || defined( __FreeBSD__ )
|
||||||
|
# define R "\033[31;1m" // red
|
||||||
|
# define G "\033[32;1m" // green
|
||||||
|
# define Y "\033[33;1m" // yellow
|
||||||
|
# define B "\033[34;1m" // blue
|
||||||
|
# define M "\033[35;1m" // magenta
|
||||||
|
# define C "\033[36;1m" // cyan
|
||||||
|
# define W "\033[37;1m" // white
|
||||||
|
# define N "\033[m" // normal
|
||||||
|
#else
|
||||||
|
# define R ""
|
||||||
|
# define G ""
|
||||||
|
# define Y ""
|
||||||
|
# define B ""
|
||||||
|
# define M ""
|
||||||
|
# define C ""
|
||||||
|
# define W ""
|
||||||
|
# define N ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
const char *azimuthName(double d);
|
||||||
|
double rnd(double number, int digits);
|
||||||
|
void printReport(Metar *m);
|
||||||
|
void printVisibility(FGMetarVisibility *v);
|
||||||
|
void printArgs(Metar *m, double airport_elevation);
|
||||||
|
|
||||||
|
|
||||||
|
const char *azimuthName(double d)
|
||||||
|
{
|
||||||
|
const char *dir[] = {
|
||||||
|
"N", "NNE", "NE", "ENE",
|
||||||
|
"E", "ESE", "SE", "SSE",
|
||||||
|
"S", "SSW", "SW", "WSW",
|
||||||
|
"W", "WNW", "NW", "NNW"
|
||||||
|
};
|
||||||
|
d += 11.25;
|
||||||
|
while (d < 0)
|
||||||
|
d += 360;
|
||||||
|
while (d >= 360)
|
||||||
|
d -= 360;
|
||||||
|
return dir[int(d / 22.5)];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// round double to 10^g
|
||||||
|
double rnd(double r, int g = 0)
|
||||||
|
{
|
||||||
|
double f = pow(10.0, g);
|
||||||
|
return f * rint(r / f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ostream& operator<<(ostream& s, FGMetarVisibility& v)
|
||||||
|
{
|
||||||
|
ostringstream buf;
|
||||||
|
int m = v.getModifier();
|
||||||
|
const char *mod;
|
||||||
|
if (m == FGMetarVisibility::GREATER_THAN)
|
||||||
|
mod = ">=";
|
||||||
|
else if (m == FGMetarVisibility::LESS_THAN)
|
||||||
|
mod = "<";
|
||||||
|
else
|
||||||
|
mod = "";
|
||||||
|
buf << mod;
|
||||||
|
|
||||||
|
double dist = rnd(v.getVisibility_m(), 1);
|
||||||
|
if (dist < 1000.0)
|
||||||
|
buf << rnd(dist, 1) << " m";
|
||||||
|
else
|
||||||
|
buf << rnd(dist / 1000.0, -1) << " km";
|
||||||
|
|
||||||
|
const char *dir = "";
|
||||||
|
int i;
|
||||||
|
if ((i = v.getDirection()) != -1) {
|
||||||
|
dir = azimuthName(i);
|
||||||
|
buf << " " << dir;
|
||||||
|
}
|
||||||
|
buf << "\t\t\t\t\t" << mod << rnd(v.getVisibility_sm(), -1) << " US-miles " << dir;
|
||||||
|
return s << buf.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void printReport(Metar *m)
|
||||||
|
{
|
||||||
|
#define NaN FGMetarNaN
|
||||||
|
const char *s;
|
||||||
|
char buf[256];
|
||||||
|
double d;
|
||||||
|
int i, lineno;
|
||||||
|
|
||||||
|
if ((i = m->getReportType()) == Metar::AUTO)
|
||||||
|
s = "\t\t(automatically generated)";
|
||||||
|
else if (i == Metar::COR)
|
||||||
|
s = "\t\t(manually corrected)";
|
||||||
|
else if (i == Metar::RTD)
|
||||||
|
s = "\t\t(routine delayed)";
|
||||||
|
else
|
||||||
|
s = "";
|
||||||
|
|
||||||
|
cout << "METAR Report" << s << endl;
|
||||||
|
cout << "============" << endl;
|
||||||
|
cout << "Airport-Id:\t\t" << m->getId() << endl;
|
||||||
|
|
||||||
|
|
||||||
|
// date/time
|
||||||
|
int year = m->getYear();
|
||||||
|
int month = m->getMonth();
|
||||||
|
cout << "Report time:\t\t";
|
||||||
|
if (year != -1 && month != -1)
|
||||||
|
cout << year << '/' << month << '/' << m->getDay();
|
||||||
|
cout << ' ' << m->getHour() << ':';
|
||||||
|
cout << std::setw(2) << std::setfill('0') << m->getMinute() << " UTC" << endl;
|
||||||
|
|
||||||
|
|
||||||
|
// visibility
|
||||||
|
FGMetarVisibility minvis = m->getMinVisibility();
|
||||||
|
FGMetarVisibility maxvis = m->getMaxVisibility();
|
||||||
|
double min = minvis.getVisibility_m();
|
||||||
|
double max = maxvis.getVisibility_m();
|
||||||
|
if (min != NaN) {
|
||||||
|
if (max != NaN) {
|
||||||
|
cout << "min. Visibility:\t" << minvis << endl;
|
||||||
|
cout << "max. Visibility:\t" << maxvis << endl;
|
||||||
|
} else
|
||||||
|
cout << "Visibility:\t\t" << minvis << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// directed visibility
|
||||||
|
FGMetarVisibility *dirvis = m->getDirVisibility();
|
||||||
|
for (i = 0; i < 8; i++, dirvis++)
|
||||||
|
if (dirvis->getVisibility_m() != NaN)
|
||||||
|
cout << "\t\t\t" << *dirvis << endl;
|
||||||
|
|
||||||
|
|
||||||
|
// vertical visibility
|
||||||
|
FGMetarVisibility vertvis = m->getVertVisibility();
|
||||||
|
if ((d = vertvis.getVisibility_ft()) != NaN)
|
||||||
|
cout << "Vert. visibility:\t" << vertvis << endl;
|
||||||
|
else if (vertvis.getModifier() == FGMetarVisibility::NOGO)
|
||||||
|
cout << "Vert. visibility:\timpossible to determine" << endl;
|
||||||
|
|
||||||
|
|
||||||
|
// wind
|
||||||
|
d = m->getWindSpeed_kmh();
|
||||||
|
cout << "Wind:\t\t\t";
|
||||||
|
if (d < .1)
|
||||||
|
cout << "none" << endl;
|
||||||
|
else {
|
||||||
|
if ((i = m->getWindDir()) == -1)
|
||||||
|
cout << "from variable directions";
|
||||||
|
else
|
||||||
|
cout << "from the " << azimuthName(i) << " (" << i << "°)";
|
||||||
|
cout << " at " << rnd(d, -1) << " km/h";
|
||||||
|
|
||||||
|
cout << "\t\t" << rnd(m->getWindSpeed_kt(), -1) << " kt";
|
||||||
|
cout << " = " << rnd(m->getWindSpeed_mph(), -1) << " mph";
|
||||||
|
cout << " = " << rnd(m->getWindSpeed_mps(), -1) << " m/s";
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
if ((d = m->getGustSpeed_kmh()) != NaN) {
|
||||||
|
cout << "\t\t\twith gusts at " << rnd(d, -1) << " km/h";
|
||||||
|
cout << "\t\t\t" << rnd(m->getGustSpeed_kt(), -1) << " kt";
|
||||||
|
cout << " = " << rnd(m->getGustSpeed_mph(), -1) << " mph";
|
||||||
|
cout << " = " << rnd(m->getGustSpeed_mps(), -1) << " m/s";
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int from = m->getWindRangeFrom();
|
||||||
|
int to = m->getWindRangeTo();
|
||||||
|
if (from != to) {
|
||||||
|
cout << "\t\t\tvariable from " << azimuthName(from);
|
||||||
|
cout << " to " << azimuthName(to);
|
||||||
|
cout << " (" << from << "°--" << to << "°)" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// temperature/humidity/air pressure
|
||||||
|
if ((d = m->getTemperature_C()) != NaN) {
|
||||||
|
cout << "Temperature:\t\t" << d << "°C\t\t\t\t\t";
|
||||||
|
cout << rnd(m->getTemperature_F(), -1) << "°F" << endl;
|
||||||
|
|
||||||
|
if ((d = m->getDewpoint_C()) != NaN) {
|
||||||
|
cout << "Dewpoint:\t\t" << d << "°C\t\t\t\t\t";
|
||||||
|
cout << rnd(m->getDewpoint_F(), -1) << "°F" << endl;
|
||||||
|
cout << "Rel. Humidity:\t\t" << rnd(m->getRelHumidity()) << "%" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((d = m->getPressure_hPa()) != NaN) {
|
||||||
|
cout << "Pressure:\t\t" << rnd(d) << " hPa\t\t\t\t";
|
||||||
|
cout << rnd(m->getPressure_inHg(), -2) << " in. Hg" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// weather phenomena
|
||||||
|
vector<string> wv = m->getWeather();
|
||||||
|
vector<string>::iterator weather;
|
||||||
|
for (i = 0, weather = wv.begin(); weather != wv.end(); weather++, i++) {
|
||||||
|
cout << (i ? ", " : "Weather:\t\t") << weather->c_str();
|
||||||
|
}
|
||||||
|
if (i)
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
|
||||||
|
// cloud layers
|
||||||
|
const char *coverage_string[5] = {
|
||||||
|
"clear skies", "few clouds", "scattered clouds", "broken clouds", "sky overcast"
|
||||||
|
};
|
||||||
|
vector<FGMetarCloud> cv = m->getClouds();
|
||||||
|
vector<FGMetarCloud>::iterator cloud;
|
||||||
|
for (lineno = 0, cloud = cv.begin(); cloud != cv.end(); cloud++, lineno++) {
|
||||||
|
cout << (lineno ? "\t\t\t" : "Sky condition:\t\t");
|
||||||
|
|
||||||
|
if ((i = cloud->getCoverage()) != -1)
|
||||||
|
cout << coverage_string[i];
|
||||||
|
if ((d = cloud->getAltitude_ft()) != NaN)
|
||||||
|
cout << " at " << rnd(d, 1) << " ft";
|
||||||
|
if ((s = cloud->getTypeLongString()))
|
||||||
|
cout << " (" << s << ')';
|
||||||
|
if (d != NaN)
|
||||||
|
cout << "\t\t\t" << rnd(cloud->getAltitude_m(), 1) << " m";
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// runways
|
||||||
|
map<string, FGMetarRunway> rm = m->getRunways();
|
||||||
|
map<string, FGMetarRunway>::iterator runway;
|
||||||
|
for (runway = rm.begin(); runway != rm.end(); runway++) {
|
||||||
|
lineno = 0;
|
||||||
|
if (!strcmp(runway->first.c_str(), "ALL"))
|
||||||
|
cout << "All runways:\t\t";
|
||||||
|
else
|
||||||
|
cout << "Runway " << runway->first << ":\t\t";
|
||||||
|
FGMetarRunway rwy = runway->second;
|
||||||
|
|
||||||
|
// assemble surface string
|
||||||
|
vector<string> surface;
|
||||||
|
if ((s = rwy.getDeposit()) && strlen(s))
|
||||||
|
surface.push_back(s);
|
||||||
|
if ((s = rwy.getExtentString()) && strlen(s))
|
||||||
|
surface.push_back(s);
|
||||||
|
if ((d = rwy.getDepth()) != NaN) {
|
||||||
|
sprintf(buf, "%.0lf mm", d * 1000.0);
|
||||||
|
surface.push_back(buf);
|
||||||
|
}
|
||||||
|
if ((s = rwy.getFrictionString()) && strlen(s))
|
||||||
|
surface.push_back(s);
|
||||||
|
if ((d = rwy.getFriction()) != NaN) {
|
||||||
|
sprintf(buf, "friction: %.2lf", d);
|
||||||
|
surface.push_back(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (surface.size()) {
|
||||||
|
vector<string>::iterator rwysurf = surface.begin();
|
||||||
|
for (i = 0; rwysurf != surface.end(); rwysurf++, i++) {
|
||||||
|
if (i)
|
||||||
|
cout << ", ";
|
||||||
|
cout << *rwysurf;
|
||||||
|
}
|
||||||
|
lineno++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// assemble visibility string
|
||||||
|
FGMetarVisibility minvis = rwy.getMinVisibility();
|
||||||
|
FGMetarVisibility maxvis = rwy.getMaxVisibility();
|
||||||
|
if ((d = minvis.getVisibility_m()) != NaN) {
|
||||||
|
if (lineno++)
|
||||||
|
cout << endl << "\t\t\t";
|
||||||
|
cout << minvis;
|
||||||
|
}
|
||||||
|
if (maxvis.getVisibility_m() != d) {
|
||||||
|
cout << endl << "\t\t\t" << maxvis << endl;
|
||||||
|
lineno++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rwy.getWindShear()) {
|
||||||
|
if (lineno++)
|
||||||
|
cout << endl << "\t\t\t";
|
||||||
|
cout << "critical wind shear" << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
#undef NaN
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void printArgs(Metar *m, double airport_elevation)
|
||||||
|
{
|
||||||
|
#define NaN FGMetarNaN
|
||||||
|
vector<string> args;
|
||||||
|
char buf[256];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// ICAO id
|
||||||
|
sprintf(buf, "--airport=%s ", m->getId());
|
||||||
|
args.push_back(buf);
|
||||||
|
|
||||||
|
// report time
|
||||||
|
sprintf(buf, "--start-date-gmt=%4d:%02d:%02d:%02d:%02d:00 ",
|
||||||
|
m->getYear(), m->getMonth(), m->getDay(),
|
||||||
|
m->getHour(), m->getMinute());
|
||||||
|
args.push_back(buf);
|
||||||
|
|
||||||
|
// cloud layers
|
||||||
|
const char *coverage_string[5] = {
|
||||||
|
"clear", "few", "scattered", "broken", "overcast"
|
||||||
|
};
|
||||||
|
vector<FGMetarCloud> cv = m->getClouds();
|
||||||
|
vector<FGMetarCloud>::iterator cloud;
|
||||||
|
for (i = 0, cloud = cv.begin(); i < 5; i++) {
|
||||||
|
int coverage = 0;
|
||||||
|
double altitude = -99999;
|
||||||
|
if (cloud != cv.end()) {
|
||||||
|
coverage = cloud->getCoverage();
|
||||||
|
altitude = coverage ? cloud->getAltitude_ft() + airport_elevation : -99999;
|
||||||
|
cloud++;
|
||||||
|
}
|
||||||
|
sprintf(buf, "--prop:/environment/clouds/layer[%d]/coverage=%s ", i, coverage_string[coverage]);
|
||||||
|
args.push_back(buf);
|
||||||
|
sprintf(buf, "--prop:/environment/clouds/layer[%d]/elevation-ft=%.0lf ", i, altitude);
|
||||||
|
args.push_back(buf);
|
||||||
|
sprintf(buf, "--prop:/environment/clouds/layer[%d]/thickness-ft=500 ", i);
|
||||||
|
args.push_back(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// environment (temperature, dewpoint, visibility, pressure)
|
||||||
|
// metar sets don't provide aloft information; we have to
|
||||||
|
// set the same values for all boundary levels
|
||||||
|
int wind_dir = m->getWindDir();
|
||||||
|
double visibility = m->getMinVisibility().getVisibility_m();
|
||||||
|
double dewpoint = m->getDewpoint_C();
|
||||||
|
double temperature = m->getTemperature_C();
|
||||||
|
double pressure = m->getPressure_inHg();
|
||||||
|
double wind_speed = m->getWindSpeed_kt();
|
||||||
|
double elevation = -100;
|
||||||
|
for (i = 0; i < 3; i++, elevation += 2000.0) {
|
||||||
|
sprintf(buf, "--prop:/environment/config/boundary/entry[%d]/", i);
|
||||||
|
int pos = strlen(buf);
|
||||||
|
|
||||||
|
sprintf(&buf[pos], "elevation-ft=%.0lf", elevation);
|
||||||
|
args.push_back(buf);
|
||||||
|
sprintf(&buf[pos], "turbulence-norm=%.0lf", 0.0);
|
||||||
|
args.push_back(buf);
|
||||||
|
|
||||||
|
if (visibility != NaN) {
|
||||||
|
sprintf(&buf[pos], "visibility-m=%.0lf", visibility);
|
||||||
|
args.push_back(buf);
|
||||||
|
}
|
||||||
|
if (temperature != NaN) {
|
||||||
|
sprintf(&buf[pos], "temperature-degc=%.0lf", temperature);
|
||||||
|
args.push_back(buf);
|
||||||
|
}
|
||||||
|
if (dewpoint != NaN) {
|
||||||
|
sprintf(&buf[pos], "dewpoint-degc=%.0lf", dewpoint);
|
||||||
|
args.push_back(buf);
|
||||||
|
}
|
||||||
|
if (pressure != NaN) {
|
||||||
|
sprintf(&buf[pos], "pressure-sea-level-inhg=%.0lf", pressure);
|
||||||
|
args.push_back(buf);
|
||||||
|
}
|
||||||
|
if (wind_dir != NaN) {
|
||||||
|
sprintf(&buf[pos], "wind-from-heading-deg=%d", wind_dir);
|
||||||
|
args.push_back(buf);
|
||||||
|
}
|
||||||
|
if (wind_speed != NaN) {
|
||||||
|
sprintf(&buf[pos], "wind-speed-kt=%.0lf", wind_speed);
|
||||||
|
args.push_back(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// wind dir@speed
|
||||||
|
int range_from = m->getWindRangeFrom();
|
||||||
|
int range_to = m->getWindRangeTo();
|
||||||
|
double gust_speed = m->getGustSpeed_kt();
|
||||||
|
if (wind_speed != NaN && wind_dir != -1) {
|
||||||
|
strcpy(buf, "--wind=");
|
||||||
|
if (range_from != -1 && range_to != -1)
|
||||||
|
sprintf(&buf[strlen(buf)], "%d:%d", range_from, range_to);
|
||||||
|
else
|
||||||
|
sprintf(&buf[strlen(buf)], "%d", wind_dir);
|
||||||
|
sprintf(&buf[strlen(buf)], "@%.0lf", wind_speed);
|
||||||
|
if (gust_speed != NaN)
|
||||||
|
sprintf(&buf[strlen(buf)], ":%.0lf", gust_speed);
|
||||||
|
args.push_back(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// output everything
|
||||||
|
cout << "fgfs" << endl;
|
||||||
|
vector<string>::iterator arg;
|
||||||
|
for (i = 0, arg = args.begin(); arg != args.end(); i++, arg++) {
|
||||||
|
cout << "\t" << *arg << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
#undef NaN
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const char *metar_list[] = {
|
||||||
|
"LOWW", "VHHH", "ULLI", "EHTW", "EFHK", "CYXU", 0, // note the trailing zero
|
||||||
|
"CYGK", "CYOW", "CYQY", "CYTZ", "CYXU", "EBBR", "EDDB", "EDDK", "EDVE", "EFHF",
|
||||||
|
"EFHK", "EGLC", "EGLL", "EHTW", "EIDW", "ENGM", "GMMN", "KART", "KBFI", "KBOS",
|
||||||
|
"KCCR", "KCEZ", "KCOF", "KDAL", "KDEN", "KDSM", "KEDW", "KEMT", "KENW", "KHON",
|
||||||
|
"KIGM", "KJFK", "KLAX", "KMCI", "KMKE", "KMLB", "KMSY", "KNBC", "KOAK", "KORD",
|
||||||
|
"KPNE", "KSAC", "KSAN", "KSEA", "KSFO", "KSJC", "KSMF", "KSMO", "KSNS", "KSQL",
|
||||||
|
"KSUN", "LBSF", "LEMD", "LFPG", "LFPO", "LGAT", "LHBP", "LIPQ", "LIRA", "LKPR",
|
||||||
|
"LLJR", "LOWG", "LOWI", "LOWK", "LOWL", "LOWS", "LOWW", "LOWZ", "LOXA", "LOXT",
|
||||||
|
"LOXZ", "LSZH", "LYBE", "NZWP", "ORBS", "PHNL", "ULLI", "VHHH", "WMKB", "YSSY",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
const char **src = metar_list;
|
||||||
|
if (argc > 1)
|
||||||
|
src = (const char **)&argv[1];
|
||||||
|
|
||||||
|
for (int i = 0; src[i]; i++) {
|
||||||
|
const char *icao = src[i];
|
||||||
|
|
||||||
|
try {
|
||||||
|
Metar *m = new Metar(icao);
|
||||||
|
//Metar *m = new Metar("2004/01/11 01:20\nLOWG 110120Z AUTO VRB01KT 0050 1600N R35/0600 FG M06/M06 Q1019 88//////\n");
|
||||||
|
|
||||||
|
printf(G"INPUT: %s\n"N, m->getData());
|
||||||
|
const char *unused = m->getUnusedData();
|
||||||
|
if (*unused)
|
||||||
|
printf(R"UNUSED: %s\n"N, unused);
|
||||||
|
|
||||||
|
printReport(m);
|
||||||
|
//printArgs(m, 0.0);
|
||||||
|
|
||||||
|
delete m;
|
||||||
|
} catch (const sg_io_exception& e) {
|
||||||
|
fprintf(stderr, R"ERROR: %s\n\n"N, e.getFormattedMessage().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
1101
src/Environment/metar.cxx
Normal file
1101
src/Environment/metar.cxx
Normal file
File diff suppressed because it is too large
Load diff
261
src/Environment/metar.hxx
Normal file
261
src/Environment/metar.hxx
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
// metar interface class
|
||||||
|
//
|
||||||
|
// Written by Melchior FRANZ, started December 2003.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2003 Melchior FRANZ - mfranz@aon.at
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
#ifndef _METAR_HXX
|
||||||
|
#define _METAR_HXX
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
|
||||||
|
SG_USING_STD(vector);
|
||||||
|
SG_USING_STD(map);
|
||||||
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
const double FGMetarNaN = -1E20;
|
||||||
|
#define NaN FGMetarNaN
|
||||||
|
|
||||||
|
struct Token {
|
||||||
|
char *id;
|
||||||
|
char *text;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Metar;
|
||||||
|
|
||||||
|
class FGMetarVisibility {
|
||||||
|
friend class Metar;
|
||||||
|
public:
|
||||||
|
FGMetarVisibility() :
|
||||||
|
_distance(NaN),
|
||||||
|
_direction(-1),
|
||||||
|
_modifier(EQUALS),
|
||||||
|
_tendency(NONE) {}
|
||||||
|
|
||||||
|
enum Modifier {
|
||||||
|
NOGO,
|
||||||
|
EQUALS,
|
||||||
|
LESS_THAN,
|
||||||
|
GREATER_THAN
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Tendency {
|
||||||
|
NONE,
|
||||||
|
STABLE,
|
||||||
|
INCREASING,
|
||||||
|
DECREASING
|
||||||
|
};
|
||||||
|
|
||||||
|
inline double getVisibility_m() const { return _distance; }
|
||||||
|
inline double getVisibility_ft() const { return _distance == NaN ? NaN : _distance * SG_METER_TO_FEET; }
|
||||||
|
inline double getVisibility_sm() const { return _distance == NaN ? NaN : _distance * SG_METER_TO_SM; }
|
||||||
|
inline int getDirection() const { return _direction; }
|
||||||
|
inline int getModifier() const { return _modifier; }
|
||||||
|
inline int getTendency() const { return _tendency; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
double _distance;
|
||||||
|
int _direction;
|
||||||
|
int _modifier;
|
||||||
|
int _tendency;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// runway condition (surface and visibility)
|
||||||
|
class FGMetarRunway {
|
||||||
|
friend class Metar;
|
||||||
|
public:
|
||||||
|
FGMetarRunway() :
|
||||||
|
_deposit(0),
|
||||||
|
_extent(-1),
|
||||||
|
_extent_string(0),
|
||||||
|
_depth(NaN),
|
||||||
|
_friction(NaN),
|
||||||
|
_friction_string(0),
|
||||||
|
_comment(0),
|
||||||
|
_wind_shear(false) {}
|
||||||
|
|
||||||
|
inline const char *getDeposit() const { return _deposit; }
|
||||||
|
inline double getExtent() const { return _extent; }
|
||||||
|
inline const char *getExtentString() const { return _extent_string; }
|
||||||
|
inline double getDepth() const { return _depth; }
|
||||||
|
inline double getFriction() const { return _friction; }
|
||||||
|
inline const char *getFrictionString() const { return _friction_string; }
|
||||||
|
inline const char *getComment() const { return _comment; }
|
||||||
|
inline const bool getWindShear() const { return _wind_shear; }
|
||||||
|
inline FGMetarVisibility getMinVisibility() const { return _min_visibility; }
|
||||||
|
inline FGMetarVisibility getMaxVisibility() const { return _max_visibility; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
FGMetarVisibility _min_visibility;
|
||||||
|
FGMetarVisibility _max_visibility;
|
||||||
|
const char *_deposit;
|
||||||
|
int _extent;
|
||||||
|
const char *_extent_string;
|
||||||
|
double _depth;
|
||||||
|
double _friction;
|
||||||
|
const char *_friction_string;
|
||||||
|
const char *_comment;
|
||||||
|
bool _wind_shear;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// cloud layer
|
||||||
|
class FGMetarCloud {
|
||||||
|
friend class Metar;
|
||||||
|
public:
|
||||||
|
FGMetarCloud() :
|
||||||
|
_coverage(-1),
|
||||||
|
_altitude(NaN),
|
||||||
|
_type(0),
|
||||||
|
_type_long(0) {}
|
||||||
|
|
||||||
|
inline int getCoverage() const { return _coverage; }
|
||||||
|
inline double getAltitude_m() const { return _altitude; }
|
||||||
|
inline double getAltitude_ft() const { return _altitude == NaN ? NaN : _altitude * SG_METER_TO_FEET; }
|
||||||
|
inline char *getTypeString() const { return _type; }
|
||||||
|
inline char *getTypeLongString() const { return _type_long; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int _coverage; // quarters: 0 -> clear ... 4 -> overcast
|
||||||
|
double _altitude; // 1000 m
|
||||||
|
char *_type; // CU
|
||||||
|
char *_type_long; // cumulus
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Metar {
|
||||||
|
public:
|
||||||
|
Metar(const char *m);
|
||||||
|
Metar(const string m) { Metar(m.c_str()); }
|
||||||
|
~Metar();
|
||||||
|
|
||||||
|
enum ReportType {
|
||||||
|
NONE,
|
||||||
|
AUTO,
|
||||||
|
COR,
|
||||||
|
RTD
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const char *getData() const { return _data; }
|
||||||
|
inline const char *getUnusedData() const { return _m; }
|
||||||
|
inline const char *getId() const { return _icao; }
|
||||||
|
inline int getYear() const { return _year; }
|
||||||
|
inline int getMonth() const { return _month; }
|
||||||
|
inline int getDay() const { return _day; }
|
||||||
|
inline int getHour() const { return _hour; }
|
||||||
|
inline int getMinute() const { return _minute; }
|
||||||
|
inline int getReportType() const { return _report_type; }
|
||||||
|
|
||||||
|
inline int getWindDir() const { return _wind_dir; }
|
||||||
|
inline double getWindSpeed_mps() const { return _wind_speed; }
|
||||||
|
inline double getWindSpeed_kmh() const { return _wind_speed == NaN ? NaN : _wind_speed * 3.6; }
|
||||||
|
inline double getWindSpeed_kt() const { return _wind_speed == NaN ? NaN : _wind_speed * SG_MPS_TO_KT; }
|
||||||
|
inline double getWindSpeed_mph() const { return _wind_speed == NaN ? NaN : _wind_speed * SG_MPS_TO_MPH; }
|
||||||
|
|
||||||
|
inline double getGustSpeed_mps() const { return _gust_speed; }
|
||||||
|
inline double getGustSpeed_kmh() const { return _gust_speed == NaN ? NaN : _gust_speed * 3.6; }
|
||||||
|
inline double getGustSpeed_kt() const { return _gust_speed == NaN ? NaN : _gust_speed * SG_MPS_TO_KT; }
|
||||||
|
inline double getGustSpeed_mph() const { return _gust_speed == NaN ? NaN : _gust_speed * SG_MPS_TO_MPH; }
|
||||||
|
|
||||||
|
inline int getWindRangeFrom() const { return _wind_range_from; }
|
||||||
|
inline int getWindRangeTo() const { return _wind_range_to; }
|
||||||
|
|
||||||
|
inline FGMetarVisibility& getMinVisibility() { return _min_visibility; }
|
||||||
|
inline FGMetarVisibility& getMaxVisibility() { return _max_visibility; }
|
||||||
|
inline FGMetarVisibility& getVertVisibility() { return _vert_visibility; }
|
||||||
|
inline FGMetarVisibility *getDirVisibility() { return _dir_visibility; }
|
||||||
|
|
||||||
|
inline double getTemperature_C() const { return _temp; }
|
||||||
|
inline double getTemperature_F() const { return _temp == NaN ? NaN : 1.8 * _temp + 32; }
|
||||||
|
inline double getDewpoint_C() const { return _dewp; }
|
||||||
|
inline double getDewpoint_F() const { return _dewp == NaN ? NaN : 1.8 * _dewp + 32; }
|
||||||
|
inline double getPressure_hPa() const { return _pressure == NaN ? NaN : _pressure / 100; }
|
||||||
|
inline double getPressure_inHg() const { return _pressure == NaN ? NaN : _pressure * SG_PA_TO_INHG; }
|
||||||
|
|
||||||
|
double getRelHumidity() const;
|
||||||
|
|
||||||
|
inline vector<FGMetarCloud>& getClouds() { return _clouds; }
|
||||||
|
inline map<string, FGMetarRunway>& getRunways() { return _runways; }
|
||||||
|
inline vector<string>& getWeather() { return _weather; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int _grpcount;
|
||||||
|
char *_data;
|
||||||
|
char *_m;
|
||||||
|
char _icao[5];
|
||||||
|
int _year;
|
||||||
|
int _month;
|
||||||
|
int _day;
|
||||||
|
int _hour;
|
||||||
|
int _minute;
|
||||||
|
int _report_type;
|
||||||
|
int _wind_dir;
|
||||||
|
double _wind_speed;
|
||||||
|
double _gust_speed;
|
||||||
|
int _wind_range_from;
|
||||||
|
int _wind_range_to;
|
||||||
|
double _temp;
|
||||||
|
double _dewp;
|
||||||
|
double _pressure;
|
||||||
|
|
||||||
|
FGMetarVisibility _min_visibility;
|
||||||
|
FGMetarVisibility _max_visibility;
|
||||||
|
FGMetarVisibility _vert_visibility;
|
||||||
|
FGMetarVisibility _dir_visibility[8];
|
||||||
|
vector<FGMetarCloud> _clouds;
|
||||||
|
map<string, FGMetarRunway> _runways;
|
||||||
|
vector<string> _weather;
|
||||||
|
|
||||||
|
bool scanPreambleDate();
|
||||||
|
bool scanPreambleTime();
|
||||||
|
|
||||||
|
bool scanType();
|
||||||
|
bool scanId();
|
||||||
|
bool scanDate();
|
||||||
|
bool scanModifier();
|
||||||
|
bool scanWind();
|
||||||
|
bool scanVariability();
|
||||||
|
bool scanVisibility();
|
||||||
|
bool scanRwyVisRange();
|
||||||
|
bool scanSkyCondition();
|
||||||
|
bool scanWeather();
|
||||||
|
bool scanTemperature();
|
||||||
|
bool scanPressure();
|
||||||
|
bool scanRunwayReport();
|
||||||
|
bool scanWindShear();
|
||||||
|
bool scanTrendForecast();
|
||||||
|
bool scanColorState();
|
||||||
|
bool scanRemark();
|
||||||
|
bool scanRemainder();
|
||||||
|
|
||||||
|
int scanNumber(char **str, int *num, int min, int max = 0);
|
||||||
|
bool scanBoundary(char **str);
|
||||||
|
const struct Token *scanToken(char **str, const struct Token *list);
|
||||||
|
char *loadData(const char *id);
|
||||||
|
void normalizeData();
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef NaN
|
||||||
|
#endif // _METAR_HXX
|
Loading…
Add table
Reference in a new issue