Logo Search packages:      
Sourcecode: kdetoys version File versions

metar_parser.cpp

/***************************************************************************
                  metar_parser.cpp  -  Metar Parser
                  Based on code originally in weatherlib.cpp.
                  -------------------
begin                : Wed June 7 2004
copyright            : (C) 2004 by John Ratke
email                : jratke@comcast.net
***************************************************************************/

/***************************************************************************
*                                                                         *
*   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.                                   *
*                                                                         *
***************************************************************************/

#include "config.h"

#include <qdatetime.h>
#include <kdebug.h>
#include <math.h>

#include "metar_parser.h"
#include "stationdatabase.h"
#include "sun.h"

// Temperature conversion macros
#define TEMP_C_TO_F(x) ( ((x) * 9/5) + 32 )
#define TEMP_F_TO_C(x) ( ((x) - 32) * 5/9 )

MetarParser::MetarParser(StationDatabase *stationDB,
                   KLocale::MeasureSystem units,
                   QDate date,
                   QTime time,
                   unsigned int localUTCOffset) : 
      m_stationDb(stationDB), m_units(units), m_date(date), m_time(time), m_localUTCOffset(localUTCOffset)
{
      CoverRegExp    = QRegExp("^(FEW|SCT|BKN|OVC|SKC|CLR|CAVOK)([0-9]{3})?(?:TCU|CB)?$");
      CurrentRegExp  = QRegExp("^(\\+|-|VC)?([A-Z]{2,4})$");
      WindRegExp     = QRegExp("^([0-9]{3}|VRB)([0-9]{2,3})(?:G([0-9]{2,3}))?(KT|KMH|MPS)$");
      VisRegExp      = QRegExp("^([0-9]{1,2})SM$");
      VisFracRegExp  = QRegExp("^1/(2|4)SM$");
      TempRegExp     = QRegExp("^(M)?([0-9]{2})/(?:(M)?([0-9]{2}))?$");
      TimeRegExp     = QRegExp("^([0-9]{2}:[0-9]{2})$");
      DateRegExp     = QRegExp("^([0-9]{4}/[0-9]{2}/[0-9]{2})$");
      PressRegExp    = QRegExp("^([AQ])([0-9]{4})$");
      TempTenRegExp  = QRegExp("^T([01][0-9]{3})([01][0-9]{3})$");
}

void MetarParser::reset()
{
      // Initialize the WeatherInfo structure
      weatherInfo.theWeather = QString::null;
      weatherInfo.clouds = 0;
      weatherInfo.windMPH = 0;
      weatherInfo.tempC = 0;
      weatherInfo.dewC  = 0;
      weatherInfo.heavy = false;
      weatherInfo.qsCoverList.clear();
      weatherInfo.qsCurrentList.clear();
      weatherInfo.qsDate = m_date;
      weatherInfo.qsTime = m_time;
      weatherInfo.qsPressure = QString::null;
      weatherInfo.qsTemperature = QString::null;
      weatherInfo.qsDewPoint = QString::null;
      weatherInfo.qsRelHumidity = QString::null;
      weatherInfo.qsVisibility = QString::null;
      weatherInfo.qsWindSpeed = QString::null;
      weatherInfo.qsWindChill = QString::null;
      weatherInfo.qsHeatIndex = QString::null;
      weatherInfo.qsWindDirection = QString::null;
      weatherInfo.stationNeedsMaintenance = false;
}

struct WeatherInfo MetarParser::processData(const QString &stationID, const QString &metar)
{
      reset();
      
      weatherInfo.reportLocation = stationID;
      
      kdDebug(12006) << "Processing data: " << metar << endl;

      // Split at whitespace into tokens
      QStringList dataList = QStringList::split(QRegExp("\\s+"), metar);
      bool found = false;
      bool beforeRemark = true;

      for (QStringList::ConstIterator it = dataList.begin();
           it != dataList.end(); ++it)
      {
            // Don't try to parse the ICAO location code
            if ((!found) && (*it == weatherInfo.reportLocation.upper().stripWhiteSpace()))
            {
                  found = true;
                  continue;
            }

            kdDebug(12006) << "Processing Token: " << *it << endl;
            
            if (*it == "RMK")
            {
                  beforeRemark = false;
                  continue;
            }
            
            if (beforeRemark)
            {
                  if (parseDate(*it))
                        continue;
                  if (parseTime(*it))
                        continue;
                  if (parseWindSpeed(*it))
                        continue;
                  if (parseVisibility(it))  // Note, pass in iterator.
                        continue;
                  if (parseTemperature(*it))
                        continue;
                  if (parsePressure(*it))
                        continue;
                  if (parseCover(*it))
                        continue;
                  if (parseCurrent(*it))
                        continue;
            }
            else
            {
                  if (parseTemperatureTenths(*it))
                        continue;
                  if (parseStationNeedsMaintenance(*it))
                        continue;
            }
      }

      if (!weatherInfo.stationNeedsMaintenance)
      {
            calcTemperatureVariables();
            calcWindChill();
            calcCurrentIcon();
      }
      
      return weatherInfo;
}

/** Parse the current cover type */
bool MetarParser::parseCover(const QString &s)
{
      if (CoverRegExp.search(s) > -1)
      {
            kdDebug(12006) << "Cover: " << CoverRegExp.capturedTexts().join("-")
                        << endl;

            QString sCode = CoverRegExp.cap(1);
            float height = CoverRegExp.cap(2).toFloat();  // initially in 100's of feet
            QString sClouds;
            QString skycondition;

            height *= 100;
            if (m_units == KLocale::Metric)
            {
                  height = height * 0.3048;
                  // using plural i18n form for proper translations
                  sClouds = i18n("1 meter", "%n meters", (int)height);
            }
            else
            {
                  // using plural i18n form for proper translations
                  sClouds = i18n("1 foot", "%n feet", (int)height);
            }

            if (sCode == "FEW")
            {
                  skycondition = i18n( "Few clouds at %1" ).arg(sClouds);
                  weatherInfo.clouds += 2;
            }
            else if (sCode == "SCT")
            {
                  skycondition = i18n( "Scattered clouds at %1" ).arg(sClouds);
                  weatherInfo.clouds += 4;
            }
            else if (sCode == "BKN")
            {
                  skycondition = i18n( "Broken clouds at %1" ).arg(sClouds);
                  weatherInfo.clouds += 8;
            }
            else if (sCode == "OVC")
            {
                  skycondition = i18n( "Overcast clouds at %1" ).arg(sClouds);
                  weatherInfo.clouds += 64;
            }
            else if ((sCode == "CLR") || (sCode == "SKC") || (sCode == "CAVOK"))
            {
                  skycondition = i18n("Clear skies");
                  weatherInfo.clouds = 0;
            }

            kdDebug(12006) << "*** Clouds: " << weatherInfo.clouds << endl;
            weatherInfo.qsCoverList << skycondition;

            return true;
      }
      return false;
}

/** Parse the current weather conditions */
bool MetarParser::parseCurrent(const QString &s)
{
      if (CurrentRegExp.search(s) > -1)
      {
            QString sIntensity = CurrentRegExp.cap(1);
            QString sCode = CurrentRegExp.cap(2);
            QString currentWeather = "";

            kdDebug(12006) << "Current: " << CurrentRegExp.capturedTexts().join("-") << endl;

            // Decode the intensity
            if (sIntensity == "+")
            {
                  currentWeather = i18n("Heavy");
                  weatherInfo.heavy = true;
            }
            else if (sIntensity == "-")
            {
                  currentWeather = i18n("Light");
                  weatherInfo.heavy = false;
            }

            // Decode the descriptor
            if (sCode.contains("MI"))
                  currentWeather += i18n(" Shallow");
            else if (sCode.contains("PR"))
                  currentWeather += i18n(" Partial");
            else if (sCode.contains("BC"))
                  currentWeather += i18n(" Patches");
            else if (sCode.contains("DR"))
                  currentWeather += i18n(" Low Drifting");
            else if (sCode.contains("BL"))
                  currentWeather += i18n(" Blowing");
            else if (sCode.contains("SH"))
            {
                  currentWeather += i18n(" Showers");
                  weatherInfo.theWeather = "shower";
            }
            else if (sCode.contains("TS"))
            {
                  currentWeather += i18n(" Thunder Storm");
                  weatherInfo.theWeather = "tstorm";
            }
            else if (sCode.contains("FZ"))
            {
                  currentWeather += i18n(" Freezing");
            }

            // Decode weather phenomena
            if (sCode.contains("DZ"))
            {
                  currentWeather += i18n(" Drizzle");
                  weatherInfo.theWeather = "light_rain";
            }
            else if (sCode.contains("RA"))
            {
                  currentWeather += i18n(" Rain");
                  weatherInfo.theWeather = "shower";
            }
            else if (sCode.contains("SN"))
            {
                  currentWeather += i18n(" Snow");
                  weatherInfo.theWeather = "snow";
            }
            else if (sCode.contains("SG"))
            {
                  currentWeather += i18n(" Snow Grains");
                  weatherInfo.theWeather = "snow4";
            }
            else if (sCode.contains("IC"))
            {
                  currentWeather += i18n(" Ice Crystals");
                  weatherInfo.theWeather = "hail";
            }
            else if (sCode.contains("PE"))
            {
                  currentWeather += i18n(" Ice Pellets");
                  weatherInfo.theWeather = "hail";
            }
            else if (s.contains("GR"))
            {
                  currentWeather += i18n(" Hail");
                  weatherInfo.theWeather = "hail";
            }
            else if (sCode.contains("GS"))
            {
                  currentWeather += i18n(" Small Hail Pellets");
                  weatherInfo.theWeather = "hail";
            }
            else if (s.contains("UP"))
            {
                  currentWeather += i18n(" Unknown Precipitation");
                  weatherInfo.theWeather = iconName("shower1");
            }
            else if (sCode.contains("BR"))
            {
                  currentWeather += i18n(" Mist");
                  // Mist has lower priority than say rain or snow
                  if ( weatherInfo.theWeather.isEmpty() )
                  {
                        weatherInfo.theWeather = "mist";
                  }
            }
            else if (sCode.contains("FG"))
            {
                  currentWeather += i18n(" Fog");
                  // Fog has lower priority than say rain or snow
                  if ( weatherInfo.theWeather.isEmpty() )
                  {
                        weatherInfo.theWeather = "fog";
                  }
            }
            else if (sCode.contains("FU"))
                  currentWeather += i18n(" Smoke");
            else if (sCode.contains("VA"))
                  currentWeather += i18n(" Volcanic Ash");
            else if (sCode.contains("DU"))
                  currentWeather += i18n(" Widespread Dust");
            else if (sCode.contains("SA"))
                  currentWeather += i18n(" Sand");
            else if (sCode.contains("HZ"))
                  currentWeather += i18n(" Haze");
            else if (sCode.contains("PY"))
                  currentWeather += i18n(" Spray");
            else if (sCode.contains("PO"))
                  currentWeather += i18n(" Dust/Sand Swirls");
            else if (sCode.contains("SQ"))
                  currentWeather += i18n(" Sudden Winds");
            else if (sCode.contains("FC"))
            {
                  if (sIntensity == "+")
                        currentWeather = i18n("Tornado");
                  else
                        currentWeather += i18n(" Funnel Cloud");
            }
            else if (sCode.contains("SS"))
                  currentWeather += i18n(" Sand Storm");
            else if (sCode.contains("DS"))
                  currentWeather += i18n("Dust Storm");

            if (!currentWeather.isEmpty())
                  weatherInfo.qsCurrentList << currentWeather;

            return true;
      }
      return false;
}

/** Parse out the current temperature */
bool MetarParser::parseTemperature(const QString &s)
{
      if (TempRegExp.search(s) > -1)
      {
            kdDebug(12006) << "Temp: " << TempRegExp.capturedTexts().join("-")
                        << endl;

            float fTemp = TempRegExp.cap(2).toFloat();
            if (TempRegExp.cap(1) == "M" && fTemp != 0 )
                  fTemp *= -1;
            float fDew = TempRegExp.cap(4).toFloat();
            if (TempRegExp.cap(3) == "M" && fDew != 0 )
                  fDew *= -1;
            
            weatherInfo.tempC = fTemp;
            weatherInfo.dewC = fDew;
            return true;
      }
      return false;
}

bool MetarParser::parseTemperatureTenths(const QString &s)
{
      if (TempTenRegExp.search(s) > -1)
      {
            kdDebug(12006) << "Temp Tenths: " << TempTenRegExp.capturedTexts().join("-")
                        << endl;
            
            float temperature = TempTenRegExp.cap( 1 ).toFloat() / 10;
            float dewPoint    = TempTenRegExp.cap( 2 ).toFloat() / 10;

            if ( temperature >= 100 )
            {
                  temperature -= 100;
                  temperature *= -1;
            }
            if ( dewPoint >= 100 )
            {
                  dewPoint -= 100;
                  dewPoint *= -1;
            }

            weatherInfo.tempC = temperature;
            weatherInfo.dewC = dewPoint;
            
            return true;
      }
      return false;
}

void MetarParser::calcTemperatureVariables()
{
#define E(t) ::pow(10, 7.5*t/(237.7+t))
      float fRelHumidity = E(weatherInfo.dewC)/E(weatherInfo.tempC) * 100;
      weatherInfo.qsRelHumidity.sprintf("%.1f", fRelHumidity);
      removeTrailingDotZero(weatherInfo.qsRelHumidity);
      weatherInfo.qsRelHumidity += "%";

      float fHeatIndex = 0;
      float tempF = TEMP_C_TO_F(weatherInfo.tempC);
      if (tempF >= 80)
      {
#define SQR(a)  ((a)*(a))
            fHeatIndex = -42.379 + (2.04901523*tempF)
                  + (10.14333127*fRelHumidity)
                  - (0.22475541*tempF*fRelHumidity)
                  - (0.00683783*SQR(tempF))
                  - (0.05481717*SQR(fRelHumidity))
                  + (0.00122874*SQR(tempF)*fRelHumidity)
                  + (0.00085282*tempF*SQR(fRelHumidity))
                  - (0.00000199*SQR(tempF)*SQR(fRelHumidity));

            if ( fHeatIndex <= tempF )
                  fHeatIndex = 0;
      }

      QString unit;
      if (m_units == KLocale::Metric)
      {
            unit = i18n("°C");
            weatherInfo.qsTemperature.sprintf("%.1f", weatherInfo.tempC);
            weatherInfo.qsDewPoint.sprintf("%.1f", weatherInfo.dewC);
            if (fHeatIndex >= 80)
                  weatherInfo.qsHeatIndex.sprintf("%.1f", TEMP_F_TO_C(fHeatIndex));
      }
      else
      {
            unit = i18n("°F");
            weatherInfo.qsTemperature.sprintf("%.1f", tempF);
            weatherInfo.qsDewPoint.sprintf("%.1f", TEMP_C_TO_F(weatherInfo.dewC));
            if (fHeatIndex >= 80)
                  weatherInfo.qsHeatIndex.sprintf("%.1f", (fHeatIndex));
      }
      
      removeTrailingDotZero(weatherInfo.qsTemperature);
      removeTrailingDotZero(weatherInfo.qsDewPoint);
      removeTrailingDotZero(weatherInfo.qsHeatIndex);
      
      weatherInfo.qsTemperature += unit;
      weatherInfo.qsDewPoint += unit;
      if (!weatherInfo.qsHeatIndex.isEmpty())
            weatherInfo.qsHeatIndex += unit;
}

void MetarParser::removeTrailingDotZero(QString &string)
{
      if ( string.right( 2 ) == ".0" )
      {
            string = string.left( string.length() - 2 );
      }
}

/** Parse out the current date. */
bool MetarParser::parseDate(const QString &s)
{
      if (DateRegExp.search(s) > -1)
      {
            kdDebug(12006) << "Date: " << DateRegExp.capturedTexts().join("-")
                        << endl;
            QString dateString = DateRegExp.cap(1);
            QString day, month, year;

            day = dateString.mid(8,2);
            month = dateString.mid(5,2);
            year = dateString.mid(0,4);

            QDate theDate(year.toInt(), month.toInt(), day.toInt());


            weatherInfo.qsDate = theDate;
            return true;
      }
      return false;
}

/** Parse out the current time. */
bool MetarParser::parseTime(const QString &s)
{
      if (TimeRegExp.search(s) > -1)
      {
            kdDebug(12006) << "Time: " << TimeRegExp.capturedTexts().join("-")
                        << endl;

            QString hour, minute, dateString;

            dateString = TimeRegExp.cap(1);
            hour = dateString.mid(0,2);
            minute = dateString.mid(3,2);
            QTime theTime(hour.toInt(), minute.toInt());

            weatherInfo.qsTime = theTime;
            return true;
      }
      return false;
}

/** Parse out the current visibility */
bool MetarParser::parseVisibility(QStringList::ConstIterator it)
{
      float fVisibility = 0;
      
      if (VisRegExp.search(*it) > -1)
      {
            fVisibility = VisRegExp.cap(1).toFloat();

            kdDebug(12006) << "Visibility: " << VisRegExp.capturedTexts().join("-")
                        << endl;

      }
      else if (VisFracRegExp.search(*it) > -1)
      {
            // got a fractional visibility, go back to previous string in the list
            // and get the whole part.
            fVisibility = (*(it--)).toFloat();
            // shouldn't be necessary?  
            //it++;
            fVisibility += ( 1 / VisFracRegExp.cap(1).toFloat() );
      }
      
      if (fVisibility > 0)
      {
            if (m_units == KLocale::Metric)
            {
                  fVisibility *= 1.6;
                  weatherInfo.qsVisibility.setNum(fVisibility);
                  weatherInfo.qsVisibility += i18n("km");
            }
            else
            {
                  weatherInfo.qsVisibility.setNum(fVisibility);
                  weatherInfo.qsVisibility += i18n("m");
            }
            return true;
      }
      else
      {
            return false;
      }
}

/** Parse out the current pressure. */
bool MetarParser::parsePressure( const QString &s)
{
      if (PressRegExp.search(s) > -1)
      {
            QString type = PressRegExp.cap(1);
            float fPressure = PressRegExp.cap(2).toFloat();

            kdDebug(12006) << "Pressure: " << PressRegExp.capturedTexts().join("-")
                        << endl;

            if (m_units == KLocale::Metric)
            {
                  if (type == "A")
                        fPressure *= (33.8639/100);
                  weatherInfo.qsPressure.setNum(fPressure, 'f', 0);
                  weatherInfo.qsPressure += i18n(" hPa");
            }
            else
            {
                  if (type == "Q")
                        fPressure /= 33.8639;
                  else
                        fPressure /= 100;
                  weatherInfo.qsPressure.setNum(fPressure, 'f', 2);
                  weatherInfo.qsPressure += i18n("\" Hg");
            }
            return true;
      }
      return false;
}

struct wind_info
{
      unsigned int   number;
      QString        name;
};

static const struct wind_info wind_direction[] = 
{
      { 0,   i18n("N")   },   // North is 0 to 11, and so on
      { 12,  i18n("NNE") },
      { 33,  i18n("NE")  },
      { 57,  i18n("ENE") },
      { 79,  i18n("E")   }, 
      { 102, i18n("ESE") },
      { 124, i18n("SE")  },
      { 147, i18n("SSE") },
      { 169, i18n("S")   },
      { 192, i18n("SSW") },
      { 214, i18n("SW")  },
      { 237, i18n("WSW") },
      { 259, i18n("W")   },
      { 282, i18n("WNW") },
      { 304, i18n("NW")  },
      { 327, i18n("NNW") },
      { 349, i18n("N")   },
      { 360, i18n("N")   }
};


QString MetarParser::parseWindDirection(const unsigned int direction)
{
      unsigned int i = 0;
      
      for (i = 0; i < (sizeof(wind_direction) / sizeof(wind_info)) - 1; i++)
      {
            if (direction >= wind_direction[i].number &&
                direction < wind_direction[i + 1].number)
            {
                  break;
            }
      }
      
      return wind_direction[i].name;
}

/** Parse the wind speed */
bool MetarParser::parseWindSpeed(const QString &s)
{
      if (WindRegExp.search(s) > -1)
      {
            unsigned int direction = WindRegExp.cap(1).toInt();
            float windSpeed = WindRegExp.cap(2).toFloat();
            float gustSpeed = WindRegExp.cap(3).toFloat();
            QString sWindUnit = WindRegExp.cap(4);

            kdDebug(12006) << "Wind: " << WindRegExp.capturedTexts().join("-")
                        << endl;

            if (m_units == KLocale::Metric)
            {
                  if (sWindUnit == "KT")
                  {
                        windSpeed = (windSpeed * 3.6 / 1.94);
                        gustSpeed = (gustSpeed * 3.6 / 1.94);
                  }
                  else if (sWindUnit == "MPS")
                  {
                        windSpeed = (windSpeed * 3.6);
                        gustSpeed = (gustSpeed * 3.6);
                  }
                  weatherInfo.windMPH = (windSpeed / 1.61);
                  weatherInfo.qsWindSpeed = i18n("1 km/h", "%n km/h", (int) windSpeed);
            }
            else
            {
                  if (sWindUnit == "KT")
                  {
                        windSpeed = (windSpeed * 2.24 / 1.94);
                        gustSpeed = (gustSpeed * 2.24 / 1.94);
                  }
                  else if (sWindUnit == "KMH")
                  {
                        windSpeed = (windSpeed / 1.61);
                        gustSpeed = (gustSpeed / 1.61);
                  }
                  else if (sWindUnit == "MPS")
                  {
                        windSpeed = (windSpeed * 2.24);
                        gustSpeed = (gustSpeed * 2.24);
                  }
                  weatherInfo.windMPH = windSpeed;
                  weatherInfo.qsWindSpeed = i18n("1 MPH", "%n MPH", (int) windSpeed);
            }

            if (gustSpeed >= 1)
            {
                  if (m_units == KLocale::Metric)
                  {
                        weatherInfo.qsCurrentList << i18n("Wind gusts up to 1 km/h", 
                       "Wind gusts up to %n km/h", (int) gustSpeed);
                  }
                  else
                  {
                        weatherInfo.qsCurrentList << i18n("Wind gusts up to 1 MPH", 
                       "Wind gusts up to %n MPH", (int) gustSpeed);
                  }
            }

            if ((WindRegExp.cap(1) != "VRB") && (windSpeed >= 1))
            {
                  weatherInfo.qsWindDirection = parseWindDirection(direction);
            }
            return true;
      }
      return false;
}

bool MetarParser::parseStationNeedsMaintenance(const QString &s)
{
      if (s == "$")
      {
            weatherInfo.stationNeedsMaintenance = true;
            kdDebug(12006) << "Station Needs Maintenance" << endl;
            return true;
      }
      
      return false;
}

void MetarParser::calcCurrentIcon()
{
      // Default to overcast clouds
      if ( weatherInfo.clouds == -1 )
            weatherInfo.clouds = 64;

      if (weatherInfo.theWeather.isEmpty())
      {
            if (weatherInfo.clouds == 0)
                  weatherInfo.theWeather = iconName("sunny");
            else if (weatherInfo.clouds > 0 && weatherInfo.clouds <= 2)
                  weatherInfo.theWeather = iconName("cloudy1");
            else if ( weatherInfo.clouds > 2 && weatherInfo.clouds <= 4)
                  weatherInfo.theWeather = iconName("cloudy2");
            else if ( weatherInfo.clouds > 4 && weatherInfo.clouds <= 8)
                  weatherInfo.theWeather = iconName("cloudy3");
            else if ( weatherInfo.clouds > 8 && weatherInfo.clouds < 63)
                  weatherInfo.theWeather = iconName( "cloudy4" );
            else
                  weatherInfo.theWeather = "cloudy5";
      }
      else if (weatherInfo.theWeather == "tstorm")
      {
            if ( weatherInfo.heavy )
                  weatherInfo.clouds = 30;

            if (weatherInfo.clouds >= 0 && weatherInfo.clouds <= 10)
                  weatherInfo.theWeather = iconName("tstorm1");
            else if ( weatherInfo.clouds > 10 && weatherInfo.clouds <= 20)
                  weatherInfo.theWeather = iconName("tstorm2");
            else
                  weatherInfo.theWeather = "tstorm3";
      }
      else if (weatherInfo.theWeather == "shower")
      {
            if ( weatherInfo.heavy )
                  weatherInfo.clouds = 30;

            if (weatherInfo.clouds >= 0 && weatherInfo.clouds <= 10)
                  weatherInfo.theWeather = iconName("shower1");
            else if ( weatherInfo.clouds > 10 && weatherInfo.clouds <= 20)
                  weatherInfo.theWeather = iconName("shower2");
            else
                  weatherInfo.theWeather = "shower3";
      }
      else if (weatherInfo.theWeather == "snow")
      {
            if ( weatherInfo.heavy )
                  weatherInfo.clouds = 30;

            if (weatherInfo.clouds >= 0 && weatherInfo.clouds <= 8)
                  weatherInfo.theWeather = iconName("snow1");
            else if ( weatherInfo.clouds > 8 && weatherInfo.clouds <= 16)
                  weatherInfo.theWeather = iconName("snow2");
            else if (weatherInfo.clouds > 16 && weatherInfo.clouds <= 24)
                  weatherInfo.theWeather = iconName("snow3");
            else
                  weatherInfo.theWeather = "snow5";
      }
      else if (isNight(weatherInfo.reportLocation) && weatherInfo.theWeather == "mist")
            weatherInfo.theWeather = "mist_night";
      else if (isNight(weatherInfo.reportLocation) && weatherInfo.theWeather == "fog")
            weatherInfo.theWeather = "fog_night";
      else if ( weatherInfo.theWeather == "mist" || weatherInfo.theWeather == "fog" )
      {
            if ( weatherInfo.clouds >= 63 )
                  weatherInfo.theWeather = "cloudy5";
      }

      kdDebug(12006) << "Clouds: " << weatherInfo.clouds << ", Icon: "
                  << weatherInfo.theWeather << endl;
}

void MetarParser::calcWindChill()
{
      float windChill = 35.74 + (0.6215 * TEMP_C_TO_F(weatherInfo.tempC))
                  - (35.75 * ::pow(weatherInfo.windMPH, 0.16))
                  + (0.4275 * TEMP_C_TO_F(weatherInfo.tempC) * ::pow(weatherInfo.windMPH, 0.16));

      kdDebug(12006) << "Wind Chill: " << windChill << endl;

      if (windChill < 48)
      {
            if (m_units == KLocale::Metric)
            {
                  weatherInfo.qsWindChill.setNum(TEMP_F_TO_C(windChill), 'f', 1);
                  removeTrailingDotZero(weatherInfo.qsWindChill);
                  weatherInfo.qsWindChill += i18n("°C");
            }
            else
            {
                  weatherInfo.qsWindChill.setNum(windChill, 'f', 1);
                  removeTrailingDotZero(weatherInfo.qsWindChill);
                  weatherInfo.qsWindChill += i18n("°F");
            }
      }
}

bool MetarParser::isNight(const QString &stationID) const
{
      QString upperStationID = stationID.upper();
      QString latitude  = m_stationDb->stationLatitudeFromID(upperStationID);
      QString longitude = m_stationDb->stationLongitudeFromID(upperStationID);

      if ( latitude.compare(  i18n("Unknown Station" ) ) == 0  ||
           longitude.compare( i18n("Unknown Station" ) ) == 0 )
      {
            return false;
      }
      else
      {
            Sun theSun( latitude, longitude , m_date, m_localUTCOffset );
            
            QTime currently = m_time;

            QTime civilStart = theSun.computeCivilTwilightStart();
            QTime civilEnd   = theSun.computeCivilTwilightEnd();

            kdDebug (12006) << "station, current, lat, lon, start, end, offset: " << 
                        upperStationID << " " << currently << " " << latitude << " " << 
                        longitude << " " << civilStart << " " << civilEnd << " " <<
                        m_localUTCOffset << endl;

            return (currently < civilStart || currently > civilEnd);
      }
}

QString MetarParser::iconName( const QString &icon ) const
{
      QString _iconName = icon;

      if ( isNight( weatherInfo.reportLocation ) )
            _iconName += "_night";

      return _iconName;
}


Generated by  Doxygen 1.6.0   Back to index