diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ae2a03c2941bf92573f89b88ef73f8aa842bea0a (patch) | |
tree | 3566563f3fb6ac3cb3496669d8f233062d3091bc /kweather/metar_parser.cpp | |
download | tdetoys-ae2a03c2941bf92573f89b88ef73f8aa842bea0a.tar.gz tdetoys-ae2a03c2941bf92573f89b88ef73f8aa842bea0a.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdetoys@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kweather/metar_parser.cpp')
-rw-r--r-- | kweather/metar_parser.cpp | 871 |
1 files changed, 871 insertions, 0 deletions
diff --git a/kweather/metar_parser.cpp b/kweather/metar_parser.cpp new file mode 100644 index 0000000..771d4d7 --- /dev/null +++ b/kweather/metar_parser.cpp @@ -0,0 +1,871 @@ +/*************************************************************************** + metar_parser.cpp - Metar Parser + Based on code originally in weatherlib.cpp. + ------------------- +begin : Wed June 7 2004 +copyright : (C) 2004 by John Ratke + : (C) 2002-2004 Nadeem Hasan <nhasan@kde.org> + : (C) 2002-2004 Ian Geiser <geiseri@kde.org> +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; + } + } + + 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 intensity, descriptor, phenomena, currentWeather; + + kdDebug(12006) << "Current: " << CurrentRegExp.capturedTexts().join("-") << endl; + + // Decode the intensity + if (sIntensity == "+") + { + intensity = i18n("Heavy"); + weatherInfo.heavy = true; + } + else if (sIntensity == "-") + { + intensity = i18n("Light"); + weatherInfo.heavy = false; + } + + // Decode the descriptor + if (sCode.contains("MI")) + descriptor = i18n("Shallow"); + else if (sCode.contains("PR")) + descriptor = i18n("Partial"); + else if (sCode.contains("BC")) + descriptor = i18n("Patches"); + else if (sCode.contains("DR")) + descriptor = i18n("Low Drifting"); + else if (sCode.contains("BL")) + descriptor = i18n("Blowing"); + else if (sCode.contains("SH")) + { + descriptor = i18n("Showers"); + weatherInfo.theWeather = "shower"; + } + else if (sCode.contains("TS")) + { + descriptor = i18n("Thunder Storm"); + weatherInfo.theWeather = "tstorm"; + } + else if (sCode.contains("FZ")) + { + descriptor = i18n("Freezing"); + } + + // Decode weather phenomena + if (sCode.contains("DZ")) + { + phenomena = i18n("Drizzle"); + weatherInfo.theWeather = "light_rain"; + } + else if (sCode.contains("RA")) + { + phenomena = i18n("Rain"); + weatherInfo.theWeather = "shower"; + } + else if (sCode.contains("SN")) + { + phenomena = i18n("Snow"); + weatherInfo.theWeather = "snow"; + } + else if (sCode.contains("SG")) + { + phenomena = i18n("Snow Grains"); + weatherInfo.theWeather = "snow4"; + } + else if (sCode.contains("IC")) + { + phenomena = i18n("Ice Crystals"); + weatherInfo.theWeather = "hail"; + } + else if (sCode.contains("PE")) + { + phenomena = i18n("Ice Pellets"); + weatherInfo.theWeather = "hail"; + } + else if (s.contains("GR")) + { + phenomena = i18n("Hail"); + weatherInfo.theWeather = "hail"; + } + else if (sCode.contains("GS")) + { + phenomena = i18n("Small Hail Pellets"); + weatherInfo.theWeather = "hail"; + } + else if (s.contains("UP")) + { + phenomena = i18n("Unknown Precipitation"); + weatherInfo.theWeather = iconName("shower1"); + } + else if (sCode.contains("BR")) + { + phenomena = i18n("Mist"); + // Mist has lower priority than say rain or snow + if ( weatherInfo.theWeather.isEmpty() ) + { + weatherInfo.theWeather = "mist"; + } + } + else if (sCode.contains("FG")) + { + phenomena = i18n("Fog"); + // Fog has lower priority than say rain or snow + if ( weatherInfo.theWeather.isEmpty() ) + { + weatherInfo.theWeather = "fog"; + } + } + else if (sCode.contains("FU")) + phenomena = i18n("Smoke"); + else if (sCode.contains("VA")) + phenomena = i18n("Volcanic Ash"); + else if (sCode.contains("DU")) + phenomena = i18n("Widespread Dust"); + else if (sCode.contains("SA")) + phenomena = i18n("Sand"); + else if (sCode.contains("HZ")) + phenomena = i18n("Haze"); + else if (sCode.contains("PY")) + phenomena = i18n("Spray"); + else if (sCode.contains("PO")) + phenomena = i18n("Dust/Sand Swirls"); + else if (sCode.contains("SQ")) + phenomena = i18n("Sudden Winds"); + else if (sCode.contains("FC")) + { + if (sIntensity == "+") + currentWeather = i18n("Tornado"); + else + phenomena = i18n("Funnel Cloud"); + } + else if (sCode.contains("SS")) + phenomena = i18n("Sand Storm"); + else if (sCode.contains("DS")) + phenomena = i18n("Dust Storm"); + + if (currentWeather.isEmpty()) currentWeather = i18n("%1 is the intensity, %2 is the descriptor and %3 is the phenomena", "%1 %2 %3").arg(intensity).arg(descriptor).arg(phenomena); + + 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; + if (fRelHumidity > 100.0) fRelHumidity = 100.0; + + 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; + + if (civilStart != civilEnd) + { + if (civilEnd < civilStart) + /* Handle daylight past midnight in local time */ + /* for weather stations located at other timezones */ + return (currently < civilStart && currently > civilEnd); + else + return (currently < civilStart || currently > civilEnd); + } + else + { + // Midnight Sun & Polar Night - In summer, the Sun is always + // over the horizon line ... so use latitude & today date to + // set isNight() value. + return ((m_date.daysInYear() >= 80 || m_date.daysInYear() <= 264) && latitude.contains("S")); + } + } +} + +QString MetarParser::iconName( const QString &icon ) const +{ + QString _iconName = icon; + + if ( isNight( weatherInfo.reportLocation ) ) + _iconName += "_night"; + + return _iconName; +} + |