]> git.mxchange.org Git - simgear.git/blobdiff - simgear/environment/metar.cxx
Consolidate the different ReaderWriterOptions classes.
[simgear.git] / simgear / environment / metar.cxx
index 8a06a4cfb3cbbd47bb874eb78f1c19c17165bfde..75109b75651d03eb413a08b9975696ec02315384 100644 (file)
@@ -32,7 +32,6 @@
 #include <time.h>
 #include <cstring>
 
-#include <simgear/io/sg_socket.hxx>
 #include <simgear/debug/logstream.hxx>
 #include <simgear/structure/exception.hxx>
 
 
 #define NaN SGMetarNaN
 
+using std::string;
+using std::map;
+using std::vector;
+
 /**
- * The constructor takes a Metar string, or a four-letter ICAO code. In the
- * latter case the metar string is downloaded from
- * http://weather.noaa.gov/pub/data/observations/metar/stations/.
+ * The constructor takes a Metar string
  * The constructor throws sg_io_exceptions on failure. The "METAR"
  * keyword has no effect (apart from incrementing the group counter
  * @a grpcount) and can be left away. A keyword "SPECI" is
  * likewise accepted.
  *
  * @param m     ICAO station id or metar string
- * @param proxy proxy host (optional; default: "")
- * @param port  proxy port (optional; default: "80")
- * @param auth  proxy authorization information (optional; default: "")
  *
  * @par Examples:
  * @code
  * SGMetar *m = new SGMetar("METAR KSFO 061656Z 19004KT 9SM SCT100 OVC200 08/03 A3013");
  * double t = m->getTemperature_F();
  * delete m;
- *
- * SGMetar n("KSFO", "proxy.provider.foo", "3128", "proxy-password");
- * double d = n.getDewpoint_C();
+
  * @endcode
  */
-SGMetar::SGMetar(const string& m, const string& proxy, const string& port,
-               const string& auth, const time_t time) :
+SGMetar::SGMetar(const string& m) :
        _grpcount(0),
        _x_proxy(false),
        _year(-1),
@@ -87,16 +82,10 @@ SGMetar::SGMetar(const string& m, const string& proxy, const string& port,
        _snow(false),
        _cavok(false)
 {
-       if (m.length() == 4 && isalnum(m[0]) && isalnum(m[1]) && isalnum(m[2]) && isalnum(m[3])) {
-               for (int i = 0; i < 4; i++)
-                       _icao[i] = toupper(m[i]);
-               _icao[4] = '\0';
-               _data = loadData(_icao, proxy, port, auth, time);
-       } else {
-               _data = new char[m.length() + 2];       // make room for " \0"
-               strcpy(_data, m.c_str());
-               _url = _data;
-       }
+       _data = new char[m.length() + 2];       // make room for " \0"
+       strcpy(_data, m.c_str());
+       _url = _data;
+               
        normalizeData();
 
        _m = _data;
@@ -169,85 +158,6 @@ void SGMetar::useCurrentDate()
        _month = now.tm_mon + 1;
 }
 
-
-/**
-  * If called with "KSFO" loads data from
-  * @code
-  * http://weather.noaa.gov/pub/data/observations/metar/stations/KSFO.TXT.
-  * @endcode
-  * Throws sg_io_exception on failure. Gives up after waiting longer than 10 seconds.
-  *
-  * @param id four-letter ICAO Metar station code, e.g. "KSFO".
-  * @param proxy proxy host (optional; default: "")
-  * @param port  proxy port (optional; default: "80")
-  * @param auth  proxy authorization information (optional; default: "")
-  * @return pointer to Metar data string, allocated by new char[].
-  * @see rfc2068.txt for proxy spec ("Proxy-Authorization")
-  */
-char *SGMetar::loadData(const char *id, const string& proxy, const string& port,
-               const string& auth, time_t time)
-{
-       const int buflen = 512;
-       char buf[2 * buflen];
-
-       string metar_server = "weather.noaa.gov";
-       string host = proxy.empty() ? metar_server : proxy;
-       string path = "/pub/data/observations/metar/stations/";
-
-       path += string(id) + ".TXT";
-       _url = "http://" + metar_server + path;
-
-       SGSocket *sock = new SGSocket(host, port.empty() ? "80" : port, "tcp");
-       sock->set_timeout(10000);
-       if (!sock->open(SG_IO_OUT)) {
-               delete sock;
-               throw sg_io_exception("cannot connect to ", sg_location(host));
-       }
-
-       string get = "GET ";
-       if (!proxy.empty())
-               get += "http://" + metar_server;
-
-       sprintf(buf, "%ld", time);
-       get += path + " HTTP/1.0\015\012X-Time: " + buf + "\015\012";
-       get += "Host: " + metar_server + "\015\012";
-
-       if (!auth.empty())
-               get += "Proxy-Authorization: " + auth + "\015\012";
-
-       get += "\015\012";
-       sock->writestring(get.c_str());
-
-       int i;
-
-       // skip HTTP header
-       while ((i = sock->readline(buf, buflen))) {
-               if (i <= 2 && isspace(buf[0]) && (!buf[1] || isspace(buf[1])))
-                       break;
-               if (!strncmp(buf, "X-MetarProxy: ", 13))
-                       _x_proxy = true;
-       }
-       if (i) {
-               i = sock->readline(buf, buflen);
-               if (i)
-                       sock->readline(&buf[i], buflen);
-       }
-
-       sock->close();
-       delete sock;
-
-       char *b = buf;
-       scanBoundary(&b);
-       if (*b == '<')
-               throw sg_io_exception("no metar data available from ", 
-                               sg_location(_url));
-
-       char *metar = new char[strlen(b) + 2];  // make room for " \0"
-       strcpy(metar, b);
-       return metar;
-}
-
-
 /**
   * Replace any number of subsequent spaces by just one space, and add
   * a trailing space. This makes scanning for things like "ALL RWY" easier.
@@ -596,7 +506,7 @@ bool SGMetar::scanRwyVisRange()
        r._max_visibility._distance = to;
 
        if (*m == '/')                                  // this is not in the spec!
-               *m++;
+               m++;
        if (*m == 'D')
                m++, r._min_visibility._tendency = SGMetarVisibility::DECREASING;
        else if (*m == 'N')
@@ -617,8 +527,8 @@ bool SGMetar::scanRwyVisRange()
 
 static const struct Token special[] = {
        { "NSW",  "no significant weather" },
-       { "VCSH", "showers in the vicinity" },
-       { "VCTS", "thunderstorm in the vicinity" },
+/*     { "VCSH", "showers in the vicinity" },
+       { "VCTS", "thunderstorm in the vicinity" }, */
        { 0, 0 }
 };
 
@@ -671,6 +581,7 @@ bool SGMetar::scanWeather()
        char *m = _m;
        string weather;
        const struct Token *a;
+
        if ((a = scanToken(&m, special))) {
                if (!scanBoundary(&m))
                        return false;
@@ -680,32 +591,35 @@ bool SGMetar::scanWeather()
        }
 
        string pre, post;
-       int intensity = 0;
+    struct Weather w;
        if (*m == '-')
-               m++, pre = "light ", intensity = 1;
+               m++, pre = "light ", w.intensity = LIGHT;
        else if (*m == '+')
-               m++, pre = "heavy ", intensity = 3;
+               m++, pre = "heavy ", w.intensity = HEAVY;
        else if (!strncmp(m, "VC", 2))
-               m += 2, post = "in the vicinity ";
+        m += 2, post = "in the vicinity ", w.vincinity=true;
        else
-               pre = "moderate ", intensity = 2;
+               pre = "moderate ", w.intensity = MODERATE;
 
        int i;
        for (i = 0; i < 3; i++) {
                if (!(a = scanToken(&m, description)))
                        break;
+               w.descriptions.push_back(a->id);
                weather += string(a->text) + " ";
        }
+
        for (i = 0; i < 3; i++) {
                if (!(a = scanToken(&m, phenomenon)))
                        break;
+        w.phenomena.push_back(a->id);
                weather += string(a->text) + " ";
                if (!strcmp(a->id, "RA"))
-                       _rain = intensity;
+                       _rain = w.intensity;
                else if (!strcmp(a->id, "HA"))
-                       _hail = intensity;
+                       _hail = w.intensity;
                else if (!strcmp(a->id, "SN"))
-                       _snow = intensity;
+                       _snow = w.intensity;
        }
        if (!weather.length())
                return false;
@@ -715,6 +629,8 @@ bool SGMetar::scanWeather()
        weather = pre + weather + post;
        weather.erase(weather.length() - 1);
        _weather.push_back(weather);
+    if( w.phenomena.size() > 0 )
+        _weather2.push_back( w );
        _grpcount++;
        return true;
 }
@@ -743,7 +659,7 @@ static const struct Token cloud_types[] = {
        { 0, 0 }
 };
 
-
+#include <iostream>
 // (FEW|SCT|BKN|OVC|SKC|CLR|CAVOK|VV)([0-9]{3}|///)?[:cloud_type:]?
 bool SGMetar::scanSkyCondition()
 {
@@ -761,6 +677,7 @@ bool SGMetar::scanSkyCondition()
 
        if (!strncmp(m, "CLR", i = 3)                           // clear
                        || !strncmp(m, "SKC", i = 3)            // sky clear
+                       || !strncmp(m, "NCD", i = 3)            // nil cloud detected
                        || !strncmp(m, "NSC", i = 3)            // no significant clouds
                        || !strncmp(m, "CAVOK", i = 5)) {       // ceiling and visibility OK (implies 9999)
                m += i;
@@ -768,7 +685,7 @@ bool SGMetar::scanSkyCondition()
                        return false;
 
                if (i == 3) {
-                       cl._coverage = 0;
+            cl._coverage = SGMetarCloud::COVERAGE_CLEAR;
                        _clouds.push_back(cl);
                } else {
                        _cavok = true;
@@ -780,13 +697,13 @@ bool SGMetar::scanSkyCondition()
        if (!strncmp(m, "VV", i = 2))                           // vertical visibility
                ;
        else if (!strncmp(m, "FEW", i = 3))
-               cl._coverage = 1;
+        cl._coverage = SGMetarCloud::COVERAGE_FEW;
        else if (!strncmp(m, "SCT", i = 3))
-               cl._coverage = 2;
+        cl._coverage = SGMetarCloud::COVERAGE_SCATTERED;
        else if (!strncmp(m, "BKN", i = 3))
-               cl._coverage = 3;
+        cl._coverage = SGMetarCloud::COVERAGE_BROKEN;
        else if (!strncmp(m, "OVC", i = 3))
-               cl._coverage = 4;
+        cl._coverage = SGMetarCloud::COVERAGE_OVERCAST;
        else
                return false;
        m += i;
@@ -799,7 +716,7 @@ bool SGMetar::scanSkyCondition()
        } else if (!scanNumber(&m, &i, 3))
                i = -1;
 
-       if (cl._coverage == -1) {
+    if (cl._coverage == SGMetarCloud::COVERAGE_NIL) {
                if (!scanBoundary(&m))
                        return false;
                if (i == -1)                    // 'VV///'
@@ -1199,13 +1116,29 @@ const struct Token *SGMetar::scanToken(char **str, const struct Token *list)
 }
 
 
-void SGMetarCloud::set(double alt, int cov)
+void SGMetarCloud::set(double alt, Coverage cov)
 {
        _altitude = alt;
        if (cov != -1)
                _coverage = cov;
 }
 
+SGMetarCloud::Coverage SGMetarCloud::getCoverage( const std::string & coverage ) 
+{
+       if( coverage == "clear" ) return COVERAGE_CLEAR;
+       if( coverage == "few" ) return COVERAGE_FEW;
+       if( coverage == "scattered" ) return COVERAGE_SCATTERED;
+       if( coverage == "broken" ) return COVERAGE_BROKEN;
+       if( coverage == "overcast" ) return COVERAGE_OVERCAST;
+       return COVERAGE_NIL;
+}
+
+const char * SGMetarCloud::COVERAGE_NIL_STRING = "nil";
+const char * SGMetarCloud::COVERAGE_CLEAR_STRING = "clear";
+const char * SGMetarCloud::COVERAGE_FEW_STRING = "few";
+const char * SGMetarCloud::COVERAGE_SCATTERED_STRING = "scattered";
+const char * SGMetarCloud::COVERAGE_BROKEN_STRING = "broken";
+const char * SGMetarCloud::COVERAGE_OVERCAST_STRING = "overcast";
 
 void SGMetarVisibility::set(double dist, int dir, int mod, int tend)
 {