]> git.mxchange.org Git - simgear.git/blobdiff - simgear/environment/metar.cxx
Merge branch 'next' of git://gitorious.org/fg/simgear into next
[simgear.git] / simgear / environment / metar.cxx
index 79401e39419d3680ae0495f1d68b34da42cfb987..c15c4a7286074115f2598aee51703be58b2de24e 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <string>
 #include <time.h>
+#include <cstring>
 
 #include <simgear/io/sg_socket.hxx>
 #include <simgear/debug/logstream.hxx>
@@ -189,11 +190,12 @@ char *SGMetar::loadData(const char *id, const string& proxy, const string& port,
        const int buflen = 512;
        char buf[2 * buflen];
 
-       string host = proxy.empty() ? "weather.noaa.gov" : proxy;
+       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://weather.noaa.gov" + path;
+       _url = "http://" + metar_server + path;
 
        SGSocket *sock = new SGSocket(host, port.empty() ? "80" : port, "tcp");
        sock->set_timeout(10000);
@@ -204,10 +206,11 @@ char *SGMetar::loadData(const char *id, const string& proxy, const string& port,
 
        string get = "GET ";
        if (!proxy.empty())
-               get += "http://weather.noaa.gov";
+               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";
@@ -465,11 +468,13 @@ bool SGMetar::scanVisibility()
        int modifier = SGMetarVisibility::EQUALS;
 // \d{4}(N|NE|E|SE|S|SW|W|NW)?
        if (scanNumber(&m, &i, 4)) {
-               if (*m == 'E')
+               if( strncmp( m, "NDV",3 ) == 0 ) {
+                       m+=3; // tolerate NDV (no directional validation)
+               } else if (*m == 'E') {
                        m++, dir = 90;
-               else if (*m == 'W')
+               } else if (*m == 'W') {
                        m++, dir = 270;
-               else if (*m == 'N') {
+               else if (*m == 'N') {
                        m++;
                        if (*m == 'E')
                                m++, dir = 45;
@@ -485,7 +490,7 @@ bool SGMetar::scanVisibility()
                                m++, dir = 225;
                        else
                                dir = 180;
-               }
+                }
                if (i == 0)
                        i = 50, modifier = SGMetarVisibility::LESS_THAN;
                else if (i == 9999)
@@ -591,7 +596,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')
@@ -612,8 +617,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 }
 };
 
@@ -666,6 +671,7 @@ bool SGMetar::scanWeather()
        char *m = _m;
        string weather;
        const struct Token *a;
+
        if ((a = scanToken(&m, special))) {
                if (!scanBoundary(&m))
                        return false;
@@ -675,32 +681,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;
@@ -710,6 +719,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;
 }
@@ -738,7 +749,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()
 {
@@ -756,6 +767,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;
@@ -763,7 +775,7 @@ bool SGMetar::scanSkyCondition()
                        return false;
 
                if (i == 3) {
-                       cl._coverage = 0;
+            cl._coverage = SGMetarCloud::COVERAGE_CLEAR;
                        _clouds.push_back(cl);
                } else {
                        _cavok = true;
@@ -775,13 +787,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;
@@ -794,7 +806,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///'
@@ -1194,13 +1206,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)
 {