[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-panel-devel
Subject:    [Panel-devel] WindFinder ion (for weather engine)
From:       Shawn Starr <shawn.starr () rogers ! com>
Date:       2007-11-27 1:45:10
Message-ID: 200711262045.11312.shawn.starr () rogers ! com
[Download RAW message or body]

From Hans Bakker:

Subject: WindFinder ion
Date: Monday 26 November 2007
From: "Hans Bakker" <hansmbakker@gmail.com>
To: shawn.starr@rogers.com, panel-devel-request@kde.org

Hi Shawn and others,

(for the ones not knowing yet what I was busy with: I'm trying to make
a WindFinder.com plugin for the KDE4 weather engine)
here's everything I coded today. I added a few functions at the end of
the weather formula files for converting wind speeds from knots.
The conversion formulas were based upon the formulas in the google
gadget windfinder ion, but are fairly trivial (look on wikipedia for
the conversion constants http://en.wikipedia.org/wiki/Knot_%28speed%29
)

In the WindFinder ion i have parsing the stations list now in that way
that it only looks at stations, and ignores the other information
about country and continent.

It only looks at the current observation, parsing forecasts would
require parsing an additional xml file (xmlforecast.xml instead of
xmlreport.xml); I believe the format is the same so we could try to
reuse parseWeatherBlock for that later.

The updateWeather method must still be implemented.

Kind regards,

Hans Bakker

PS sorry for annoying everybody with accidentally sending the message
before it was finished (A)

-------------------------------------------------------

["ion_windfinder.cpp" (text/x-c++src)]

/***************************************************************************
 *   Copyright (C) 2007 by Shawn Starr <shawn.starr@rogers.com>            *
 *                                                                         *
 *   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, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
 ***************************************************************************/

/* Ion for WindFinder XML data */

#include "ion_windfinder.h"

class WindFinderIon::Private : public QObject
{
public:
    Private() {}
    ~Private() {}

private:
    struct XMLMapInfo {
        QString stationName;
        QString countryName;
	QString continentName;
        QString stationID;
    };

public:
    // Key dicts
    QHash<QString, WindFinderIon::Private::XMLMapInfo> m_place;
    QHash<QString, QString> m_locations;
    QString m_id;
    QString m_country;
    QString m_stationName;

    // Weather information
    QHash<QString, WeatherData> m_weatherData;

    // Store KIO jobs
    QMap<KJob *, QXmlStreamReader*> m_jobXml;
    QMap<KJob *, QString> m_jobList;
    QXmlStreamReader m_xmlSetup;
    KUrl *m_url;
    KIO::TransferJob *m_job;

    bool m_useUTC;  // Ion option: Timezone may be local time or UTC time
    bool m_useMetric; // Ion option: Units may be Metric or Imperial
    bool m_windInMeters; // Ion option: Display wind format in meters per second only

    WeatherFormula m_formula;
};


// ctor, dtor
WindFinderIon::WindFinderIon(QObject *parent, const QVariantList &args)
        : IonInterface(parent), d(new Private())
{
    Q_UNUSED(args)
}

WindFinderIon::~WindFinderIon()
{
    // Destroy each warning stored in a QVector
    foreach(WeatherData item, d->m_weatherData) {
        foreach(WeatherData::WarningInfo *warning, item.warnings) {
            if (warning) {
                delete warning;
            }
        }
        foreach(WeatherData::ForecastInfo *forecast, item.forecasts) {
            if (forecast) {
                delete forecast;
            }
        }
    }

    // Destroy dptr
    delete d;
}

// Get the master list of locations to be parsed
void WindFinderIon::init()
{
    // Get the real city XML URL so we can parse this
    getXMLSetup();
}

QStringList WindFinderIon::validate(const QString& source) const
{
    QStringList placeList;
    QHash<QString, QString>::const_iterator it = d->m_locations.constBegin();
    while (it != d->m_locations.constEnd()) {
        if (it.value().toLower().contains(source.toLower())) {
            placeList.append(it.value().split(":")[1]);
        }
        ++it;
    }
   
    // Check if placeList is empty if so, return nothing.
    if (placeList.isEmpty()) {
        return QStringList();
    }
    placeList.sort();
    return placeList;
}

// Get a specific Ion's data
bool WindFinderIon::updateIonSource(const QString& source)
{
    kDebug() << "updateIonSource() SOURCE: " << source;
    // We expect the applet to send the source in the following tokenization:
    // ionname:validate:place_name - Triggers validation of place
    // ionname:weather:place_name - Triggers receiving weather of place
   
    QStringList sourceAction = source.split(':');
    if (sourceAction[1] == QString("validate")) {
        kDebug() << "Initiate Validating of place: " << sourceAction[2];
    
        QStringList result = \
this->validate(QString("%1:%2").arg(sourceAction[0]).arg(sourceAction[2]));

        if (result.size() == 1) {
            setData(source, "validate", \
QString("envcan:valid:single:%1").arg(result.join(":")));  return true;
        } else if (result.size() > 1) {
            setData(source, "validate", \
QString("envcan:valid:multiple:%1").arg(result.join(":")));  return true;
        } else if (result.size() == 0) {
            setData(source, "validate", \
QString("envcan:invalid:single:%1").arg(sourceAction[2]));  return true;
        }

     } else if (sourceAction[1] == QString("weather")) {
        getXMLData(QString("%1:%2").arg(sourceAction[0]).arg(sourceAction[2]));
        return true;
     }
     return false;
}

// Parses station list and gets the correct station based on ID number
void WindFinderIon::getXMLSetup()
{

    d->m_url = new KUrl("http://www.windfinder.com/wind-cgi/xmlstations.pl");

    KIO::TransferJob *job = KIO::get(d->m_url->url(), KIO::NoReload, \
KIO::HideProgressInfo);

    if (job) {
        connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
                SLOT(setup_slotDataArrived(KIO::Job *, const QByteArray &)));
        connect(job, SIGNAL(result(KJob *)), this, SLOT(setup_slotJobFinished(KJob \
*)));  }
}

// Gets specific station XML data
void WindFinderIon::getXMLData(const QString& source)
{
    KUrl url;
    url = "http://www.windfinder.com/wind-cgi/xmlreport.pl?CUSTOMER=macos&STATIONS=" \
+ d->m_place[source].stationID;

    kDebug() << "URL Location: " << url.url();

    d->m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo);
    d->m_jobXml.insert(d->m_job, new QXmlStreamReader);
    d->m_jobList.insert(d->m_job, source);

    if (d->m_job) {
        connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
                SLOT(slotDataArrived(KIO::Job *, const QByteArray &)));
        connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(slotJobFinished(KJob \
*)));  }
}

void WindFinderIon::setup_slotDataArrived(KIO::Job *job, const QByteArray &data)
{
    Q_UNUSED(job)

    if (data.isEmpty()) {
        return;
    }

    // Send to xml.
    d->m_xmlSetup.addData(data.data());
}

void WindFinderIon::slotDataArrived(KIO::Job *job, const QByteArray &data)
{

    if (data.isEmpty() || !d->m_jobXml.contains(job)) {
        return;
    }

    // Send to xml.
    d->m_jobXml[job]->addData(data.data());
}

void WindFinderIon::slotJobFinished(KJob *job)
{
    // Dual use method, if we're fetching location data to parse we need to do this \
first  readXMLData(d->m_jobList[job], *d->m_jobXml[job]);
    d->m_jobList.remove(job);
    delete d->m_jobXml[job];
    d->m_jobXml.remove(job);
}

void WindFinderIon::setup_slotJobFinished(KJob *job)
{
    Q_UNUSED(job)
    readXMLSetup();
    this->setInitialized(true);
}

// Parse the station list and store into a QMap
bool WindFinderIon::readXMLSetup()
{
    while (!d->m_xmlSetup.atEnd()) {
        d->m_xmlSetup.readNext();

        if (d->m_xmlSetup.isStartElement()) {
            if (d->m_xmlSetup.name() == "stations") {
                parseStations();
            }
        }
    }
    return !d->m_xmlSetup.error();
}

void WindFinderIon::parseStations()
{
    QString tmp;
    while (!d->m_xmlSetup.atEnd()) {
        d->m_xmlSetup.readNext();

        if (d->m_xmlSetup.isEndElement() && d->m_xmlSetup.name() == "station") {
            break;
        }

        if (d->m_xmlSetup.isStartElement()) {
            if (d->m_xmlSetup.name() == "station") {
		d->m_id = d->m_xmlSetup.attributes().value("id").toString();
		d->m_stationName = d->m_xmlSetup.attributes().value("name").toString();

                tmp = "windfinder:" + d->m_station_name; // Build the key name.
                d->m_place[tmp].stationID = d->m_id;
                d->m_place[tmp].stationName = d->m_station_name;

                d->m_locations[tmp] = tmp;
            } else {
                parseUnknownElement(d->m_xmlSetup);
            }
        }
    }
}

// handle when no XML tag is found
void WindFinderIon::parseUnknownElement(QXmlStreamReader& xml)
{

    while (!xml.atEnd()) {
        xml.readNext();

        if (xml.isEndElement()) {
            break;
        }

        if (xml.isStartElement()) {
            parseUnknownElement(xml);
        }
    }
}

// User toggleable values set from the dataengine <-> Plasma Applet
void WindFinderIon::option(int option, const QVariant& value)
{
    switch (option) {
    case IonInterface::UNITS:
        // Set the Units used (Depends on Ion)
        if (value.toInt() == KLocale::Metric) {
            d->m_useMetric = true;
        }
        if (value.toInt() == KLocale::Imperial) {
            d->m_useMetric = false;
        }
        break;
    case IonInterface::TIMEFORMAT:
        if (value.toBool()) {
            d->m_useUTC = true;
        }
        break;
    case IonInterface::WINDFORMAT:
        if (value.toBool()) {
           d->m_windInMeters = true;
        } else {
           d->m_windInMeters = false;
        }
        break;
    }
}

WeatherData WindFinderIon::parseWeatherBlock(WeatherData& data, QXmlStreamReader& \
xml) {
    while (!xml.atEnd()) {
        xml.readNext();

        if (xml.isStartElement()) {
            if (xml.name() == "station") {
                data.stationName=xml.attributes().value("name").toString();
		data.stationID=xml.attributes().value("id").toString();
            }
            else if (xml.name() == "date") {
                data.obsDate=xml.readElementText();
            }
            else if (xml.name() == "time") {
                data.obsTimestamp=xml.readElementText();
            }
            else if (xml.name() == "air_temperature") {
		data.air_temperature=xml.readElementText();
            }
	    else if (xml.name() == "water_temperature") {
                data.water_temperature=xml.readElementText();
            }
	    else if (xml.name() == "wind_direction") {
                data.windDirection=xml.readElementText();
            }
	    else if (xml.name() == "wind_speed") {
                data.windSpeed=xml.readElementText();
            }
	    else if (xml.name() == "wind_gusts") {
                data.windGust=xml.readElementText();
            }
/*
	    else if (xml.name() == "weather") {
                
            }
*/
	    else if (xml.name() == "precipitation") {
                data.precipitation=xml.readElementText();
            }
	    else if (xml.name() == "wave_height") {
                data.waveHeight=xml.readElementText();
            }
	    else if (xml.name() == "wave_direction") {
                data.waveDirection=xml.readElementText();
            }
	    else if (xml.name() == "wave_period") {
                data.wavePeriod=xml.readElementText();
            }
	    else {
                parseUnknownElement(xml);
            }
        }
    }
    return data;
}

// Parse Weather data main loop, from here we have to decend into each tag pair
bool WindFinderIon::readXMLData(const QString& source, QXmlStreamReader& xml)
{
    WeatherData data;
    data.comforttemp = "N/A";
    data.recordHigh = 0.0;
    data.recordLow = 0.0;

    while (!xml.atEnd()) {
        xml.readNext();

        if (xml.isEndElement()) {
            break;
        }

        if (xml.isStartElement()) {
            if (xml.name() == "report") {
                data = parseWeatherSiteBlock(data, xml);
            } else {
                parseUnknownElement(xml);
            }
        }
    }

    d->m_weatherData[source] = data;
    updateWeather(source);
    return !xml.error();
}

QString WindFinderIon::country(const QString& source)
{
    return "N/A";//d->m_weatherData[source].countryName;
}
QString WindFinderIon::continent(const QString& source)
{
    return "N/A";//d->m_weatherData[source].shortTerritoryName;
}
QString WindFinderIon::city(const QString& source)
{
    return d->m_weatherData[source].stationName;
}
QString WindFinderIon::region(const QString& source)
{
    return "N/A";d->m_weatherData[source].regionName;
}
QString WindFinderIon::station(const QString& source)
{
    if (!d->m_weatherData[source].stationID.isEmpty()) {
         return d->m_weatherData[source].stationID.toUpper();
    }
    
    return QString("N/A");
}
QString EnvCanadaIon::observationTime(const QString& source)
{
    return d->m_weatherData[source].obsTimestamp;
}
QString EnvCanadaIon::observationDate(const QString& source)
{
    return d->m_weatherData[source].obsDate;
}

QMap<QString, QString> WindFinderIon::air_temperature(const QString& source)
{
    QMap<QString, QString> air_temperatureInfo;
    if (d->m_useMetric) {
        if (!d->m_weatherData[source].air_temperature.isEmpty()) {
            air_temperatureInfo.insert("air temperature", \
QString("%1").arg(QString::number(d->m_weatherData[source].air_temperature.toFloat(), \
'f', 1)));  }
        air_temperatureInfo.insert("temperatureUnit", \
QString("%1C").arg(QChar(176)));  }
    else {
        if (!d->m_weatherData[source].air_temperature.isEmpty()) {
            air_temperatureInfo.insert("air temperature", \
QString("%1").arg(QString::number(d->m_formula.celsiusToF(d->m_weatherData[source].air_temperature.toFloat()), \
'f', 1)));  } else {
            air_temperatureInfo.insert("air temperature", "N/A");
        }
	air_temperatureInfo.insert("temperatureUnit", QString("%1F").arg(QChar(176)));
    }
    return air_temperatureInfo;
}

QMap<QString, QString> WindFinderIon::water_temperature(const QString& source)
{
    QMap<QString, QString> water_temperatureInfo;
    if (d->m_useMetric) {
        if (!d->m_weatherData[source].water_temperature.isEmpty()) {
            water_temperatureInfo.insert("water temperature", \
QString("%1").arg(QString::number(d->m_weatherData[source].water_temperature.toFloat(), \
'f', 1)));  }
        water_temperatureInfo.insert("temperatureUnit", \
QString("%1C").arg(QChar(176)));  }
    else {
        if (!d->m_weatherData[source].water_temperature.isEmpty()) {
            water_temperatureInfo.insert("water temperature", \
QString("%1").arg(QString::number(d->m_formula.celsiusToF(d->m_weatherData[source].water_temperature.toFloat()), \
'f', 1)));  } else {
            water_temperatureInfo.insert("water temperature", "N/A");
        }
	water_temperatureInfo.insert("temperatureUnit", QString("%1F").arg(QChar(176)));
    }
    return water_temperatureInfo;
}

QMap<QString, QString> WindFinderIon::wind(const QString& source)
{
    QMap<QString, QString> windInfo;

    // May not have any winds
    if (d->m_weatherData[source].windSpeed.isEmpty()) {
        windInfo.insert("windSpeed", "N/A");
        windInfo.insert("windUnit", "N/A");
    } else if (d->m_weatherData[source].windSpeed.toInt() == 0) {
        windInfo.insert("windSpeed", "Calm");
        windInfo.insert("windUnit", "N/A");
    } else {
        if (d->m_useMetric) {
            if (d->m_windInMeters) {
                windInfo.insert("windSpeed", \
QString("%1").arg(QString::number(d->m_formula.knotsToMS(d->m_weatherData[source].windSpeed.toInt()), \
'f', 2)));  windInfo.insert("windUnit", "m/s");
            } else {
                windInfo.insert("windSpeed", \
QString("%1").arg(QString::number(d->m_formula.knotsToKM(d->m_weatherData[source].windSpeed.toInt()), \
'f', 2)));  windInfo.insert("windUnit", "km/h");
            }
        } else {
            windInfo.insert("windSpeed", \
QString("%1").arg(QString::number(d->m_weatherData[source].windSpeed.toInt())));  \
windInfo.insert("windUnit", "kts");  }
    }

    // May not always have gusty winds
    if (d->m_weatherData[source].windGust.isEmpty()) {
        windInfo.insert("windGust", "N/A");
        windInfo.insert("windGustUnit", "N/A");
    } else {
        if (d->m_useMetric) {
            if (d->m_windInMeters) { 
                windInfo.insert("windGust", \
QString("%1").arg(QString::number(d->m_formula.knotsToMS(d->m_weatherData[source].windGust.toInt()), \
'f', 2)));  windInfo.insert("windGustUnit", "m/s");
            } else { 
                windInfo.insert("windGust", \
QString("%1").arg(QString::number(d->m_formula.knotsToKM(d->m_weatherData[source].windGust.toInt()), \
'f', 2)));  windInfo.insert("windGustUnit", "km/h");
            }
        } else {
            windInfo.insert("windGust", \
QString("%1").arg(QString::number(d->m_weatherData[source].windGust.toInt())));  \
windInfo.insert("windGustUnit", "kts");  }
    }

    if (d->m_weatherData[source].windDirection.isEmpty() && \
d->m_weatherData[source].windSpeed.isEmpty()) {  windInfo.insert("windDirection", \
"N/A");  } else if (d->m_weatherData[source].windSpeed.toInt() == 0) {
        windInfo.insert("windDirection", "VR");
    } else {
        windInfo.insert("windDirection", d->m_weatherData[source].windDirection);
    }
    return windInfo;
}


#include "ion_windfinder.moc"


["ion_windfinder.h" (text/x-chdr)]

/***************************************************************************
 *   Copyright (C) 2007 by Shawn Starr <shawn.starr@rogers.com>            *
 *                                                                         *
 *   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, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
 ***************************************************************************/

/* Ion for WindFinder XML data */

#ifndef _ION_WINDFINDER_H_
#define _ION_WINDFINDER_H_

#include <QtXml/QXmlStreamReader>
#include <QtCore/QStringList>
#include <QDebug>
#include <kurl.h>
#include <kio/job.h>
#include <kio/scheduler.h>
#include <kdemacros.h>
#include <plasma/dataengine.h>
#include "ion.h"
#include "weather_formula.h"

class WeatherData
{

public:
    QString stationName;
    QString countryName;
    QString continentName;
    QString stationID;

    // Current observation information.
    QString obsTimestamp;
    QString obsDate;
    QString air_temperature;
    QString water_temperature;
    QString windSpeed;
    QString windGust;
    QString windDirection;
    QString precipitation;
    QString waveHeight;
    QString waveDirection;
    QString wavePeriod;
};

class KDE_EXPORT WindFinderIon : public IonInterface
{
    Q_OBJECT

public:
    WindFinderIon(QObject *parent, const QVariantList &args);
    ~WindFinderIon();
    void init();  // Setup the city location, fetching the correct URL name.
    bool updateIonSource(const QString& source); // Sync data source with Applet
    void option(int option, const QVariant& value);
    void updateWeather(const QString& source);

protected slots:
    void setup_slotDataArrived(KIO::Job *, const QByteArray &);
    void setup_slotJobFinished(KJob *);

    void slotDataArrived(KIO::Job *, const QByteArray &);
    void slotJobFinished(KJob *);

private:
    /* WindFinder Methods - Internal for Ion */

    // Place information
    QString country(const QString& source);
    QString continent(const QString& source);
    QString city(const QString& source);
    QString region(const QString& source);
    QString station(const QString& source);

    // Current Conditions Weather info
    QString observationTime(const QString& source);    
    QString observationDate(const QString& source);

    QMap<QString, QString> air_temperature(const QString& source);
    QMap<QString, QString> water_temperature(const QString& source);
    QMap<QString, QString> wind(const QString& source);

    // Load and Parse the place XML listing
    void getXMLSetup(void);
    bool readXMLSetup(void);

    // Load and parse the specific place(s)
    void getXMLData(const QString& source);
    bool readXMLData(const QString& source, QXmlStreamReader& xml);

    // Check if place specified is valid or not
    QStringList validate(const QString& source) const;

    // Catchall for unknown XML tags
    void parseUnknownElement(QXmlStreamReader& xml);

    // Parse weather XML data
    WeatherData parseWeatherBlock(WeatherData& data, QXmlStreamReader& xml);

private:
    class Private;
    Private *const d;
};

K_EXPORT_PLASMA_ION(envcan, EnvCanadaIon)

#endif

["weather_formula.cpp" (text/x-c++src)]

/***************************************************************************
 *   Copyright (C) 2007 by Shawn Starr <shawn.starr@rogers.com>            *
 *                                                                         *
 *   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, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
 ***************************************************************************/

#include "weather_formula.h"
#include <math.h>

WeatherFormula::WeatherFormula()
{
}

WeatherFormula::~WeatherFormula()
{
}

float WeatherFormula::celsiusToF(float temperature) const
{
    return (temperature * 9 / 5 + 32);
}

float WeatherFormula::fahrenheitToC(float temperature) const
{
    return (temperature - 32) * 5 / 9;
}

float WeatherFormula::milesToKM(float miles) const
{
    return (1.609344 * miles);
}

float WeatherFormula::kilometersToMI(float km) const
{
    return (0.621371192 * km);
}

float WeatherFormula::kilopascalsToInches(float kpa) const
{
    return ((0.02952997 * kpa) * 10);
}

float WeatherFormula::inchesToKilopascals(float inches) const
{
    return (inches * 3.386389);
}

float WeatherFormula::centimetersToIN(float cm) const 
{
    return (cm * 0.393700787);
}

float WeatherFormula::inchesToCM(float inch) const
{
    return (inch * 2.54);
}

float WeatherFormula::millimetersToIN(float mm) const
{
    return (mm * 0.0393700787);
}

float WeatherFormula::inchesToMM(float inch) const
{
    return (inch * 25.4);
}

float WeatherFormula::kilometersToMS(float km) const
{
    return (km * 0.277778);
}

float WeatherFormula::milesToMS(float miles) const
{
    return (miles * 0.44704);
}

float WeatherFormula::knotsToMS(float knots) const
{
    return (knots * 1.9438);
}

float WeatherFormula::knotsToKM(float knots) const
{
    return Math.floor(knots * 1.852 + 0.5);
}

["weather_formula.h" (text/x-chdr)]

/***************************************************************************
 *   Copyright (C) 2007 by Shawn Starr <shawn.starr@rogers.com>            *
 *                                                                         *
 *   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, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
 ***************************************************************************/

/* Meteorological formula class */

#ifndef _WEATHERFORMULA_H
#define _WEATHERFORMULA_H

#include <kdemacros.h>

class KDE_EXPORT WeatherFormula
{
public:
    WeatherFormula();
    ~WeatherFormula();
    // Convert Temperatures, pressures
    float celsiusToF(float temperature) const;
    float fahrenheitToC(float temperature) const;
    float milesToKM(float miles) const;
    float kilometersToMI(float km) const;
    float kilopascalsToInches(float kpa) const;
    float inchesToKilopascals(float inches) const;
    float centimetersToIN(float cm) const;
    float inchesToCM(float inch) const;
    float millimetersToIN(float mm) const;
    float inchesToMM(float inch) const;

    // Winds measured in meters per second
    float kilometersToMS(float km) const;
    float milesToMS(float miles) const;
    float knotsToMS(float knots) const;
    float knotsToKM(float knots) const;

};

#endif

["ion-windfinder.desktop" (application/x-desktop)]

_______________________________________________
Panel-devel mailing list
Panel-devel@kde.org
https://mail.kde.org/mailman/listinfo/panel-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic