Subversion Repositories public iLand

Rev

Rev 671 | Rev 779 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/********************************************************************************************
**    iLand - an individual based forest landscape and disturbance model
**    http://iland.boku.ac.at
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
**
**    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 3 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, see <http://www.gnu.org/licenses/>.
********************************************************************************************/


#ifndef HELPER_H
#define HELPER_H

#include <QtCore>
#include <QtCore/QRect>
#include <QtCore/QString>
#include <limits>
#include "ticktack.h"
#include <limits>
#define QUIETDEBUG(x) if (!Helper::quiet()) { qDebug() << x; }

/** Helper contains a bunch of (static) helper functions.
  * including simplifed functions to read/write plain text files (loadTextFile(), saveToTextFile()),
  * funcitons to show message dialogs (msg(), question()), and functions to control the amount of
  * debug outputs (quiet(), debugEnabled()).
  */

class Helper
{
public:
    Helper();
    static QString loadTextFile(const QString& fileName);
    static void saveToTextFile(const QString& fileName, const QString& text);
    static QByteArray loadFile(const QString &fileName);
    static void saveToFile(const QString &fileName, const QByteArray &data);
    static void msg(const QString &message, QWidget *parent=0);
    static bool question(const QString &message, QWidget *parent=0);
    static QString userValue(const QString &message, const QString defaultValue, QWidget *parent=0); ///< ask the user for a input value
    /// open a File Dialog and let the user choose a file.
    /// @return the filename selected by the user, an empty string if user cancels.
    static QString fileDialog(const QString &title, const QString &start_directory="",const QString &filter="");
    static bool quiet() { return m_NoDebug || m_quiet; }
    static bool debugEnabled() { return !m_NoDebug; }
    static void setQuiet(bool quiet) { m_quiet = quiet; }
    static void setDebugEnabled(bool enable) { m_NoDebug = !enable; }
    static void openHelp(const QString& topic);
    static QString stripHtml(const QString &source);

    static QColor colorFromValue(const float value, const float min_value=0.f, const float max_value=1.f, const bool reverse=false, const bool black_white=false);

    static QString currentRevision(); ///< svn revision number

private:
    static bool m_quiet;
    static bool m_NoDebug;
};

/** StatData.
* Helper class for statistics. This class calculates
* from a double-vector relevant information used
* for BoxPlots. */

class StatData
{
public:
    StatData() { calculate(); }
    StatData(QVector<double> &data);
    void setData(QVector<double> &data) { mData=data; calculate(); }
    void calculate();
    // getters
    double sum() const { return mSum; } ///< sum of values
    double mean() const { return mMean; } ///< arithmetic mean
    double min() const { return mMin; } ///< minimum value
    double max() const { return mMax; } ///< maximum value
    double median() const { if (mP25==std::numeric_limits<double>::max()) calculatePercentiles(); return mMedian; } ///< 2nd quartil = median
    double percentile25() const { if (mP25==std::numeric_limits<double>::max()) calculatePercentiles(); return mP25; } ///< 1st quartil
    double percentile75() const { if (mP25==std::numeric_limits<double>::max()) calculatePercentiles(); return mP75; } ///< 3rd quartil
    double percentile(const int perc) const; ///< get value of a given percentile (0..100)
    double standardDev() const { if (mSD==std::numeric_limits<double>::max()) calculateSD(); return mSD; } ///< get the standard deviation (of the population)
    // additional functions
    static QVector<int> calculateRanks(const QVector<double> &data, bool descending=false); ///< rank data.
    static void normalize(QVector<double> &data, double targetSum); ///< normalize, i.e. the sum of all items after processing is targetSum
private:
    double calculateSD() const;
    mutable QVector<double> mData; // mutable to allow late calculation of percentiles (e.g. a call to "median()".)
    double mSum;
    double mMean;
    double mMin;
    double mMax;
    mutable double mP25;
    mutable double mP75;
    mutable double mMedian;
    mutable double mSD; // standard deviation
    void calculatePercentiles() const;
};

/** Timer class that writes timings to the Debug-Output-Channel

The class writes the elapsed time to qDebug() when either destructed, or when explicitely showElapsed() is called.
  elapsed() queries the elapsed time in milliseconds since construction or start() is called. Using interval() one can
  write a message with the time elapsed up the calling time, and the clock is reset afterwards. The name of the timer is
  set during construction. This message is printed when showElapsed() is called or durig destruction.
  Additionally, elapsed times of timers sharing the same caption are aggregated. Use clearAllTimers() to reset and printAllTimers()
  print the sums to the debug console. "Silent" DebugOutputs (setSilent() don't print timings for each iteration, but are still
    counted in the sums. If setAsWarning() is issued, the debug messages are print as warning, thus also visible
  when debug messages are disabled.
  @code void foo() {
     DebugTimer t("foo took [ms]:");
     <some lengthy operation>
 } // will e.g. print "foo took [ms]: 123" to debug console

 void bar() {
    DebugTimer::clearAllTimers(); // set all timers to 0
    for (i=0;i<1000;i++)
       foo();
    DebugTimer::printAllTimers(); // print the sum of the timings.
 }
 @endcode
 For Windows, the "TickTack"-backend is used.

*/

class DebugTimer
{
public:
    DebugTimer() { m_hideShort=false; m_silent=false; start(); }
    DebugTimer(const QString &caption, bool silent=false);
    void setSilent() { m_silent=true; }
    void setHideShort(bool hide_short_messages) { m_hideShort = hide_short_messages; }
    ~DebugTimer();
    void showElapsed();
    double elapsed(); // elapsed time in milliseconds
    void start();
    void interval(const QString &text);
    static void clearAllTimers();
    static void printAllTimers();
private:
    static QHash<QString, double> mTimingList;
    TickTack t;
    bool m_hideShort; // if true, hide messages for short operations (except an explicit call to showElapsed())
    bool m_shown;
    bool m_silent;
    QString m_caption;
};

/** UpdateState details missing.
  */

class UpdateState
{
public:
    // available states
    UpdateState(): mCurrentVal(0), mVal(0) {}
    bool needsUpdate(); // needs local state-object an update?
    void update(); // update with master
    int value() const { return mVal; } // return current value
    void invalidate(bool self=false); // master object enters a new state
    void addChild(UpdateState* state) { mChilds.push_back(state); }
    void saveState(UpdateState* state);
    bool hasChanged(UpdateState* state);
private:
    int mCurrentVal; // state of last explicit "update"
    int mVal; // current state
    QVector<UpdateState*> mChilds;
    QMap<UpdateState*, int> mSavedStates;
};

class Viewport
{
public:
    Viewport(): m_viewAll(true), m_scale_worldtoscreen(1.) {}
    Viewport(const QRectF worldrect, const QRect screenrect) { setWorldRect(worldrect); setScreenRect(screenrect); zoomToAll(); }
    // coordinate transformations
    const QPointF toWorld(const QPoint pixel);
    const QPoint toScreen(const QPointF p);
    const QRect toScreen(const QRectF world) { QPoint p1=toScreen(world.topLeft()); QPoint p2=toScreen(world.bottomRight()); QRect r(p1, QSize(p2.x()-p1.x(), p2.y()-p1.y())); return r; }
    // getters
    const QRectF viewRect() const { return m_viewport; }
    bool isVisible(const QPointF &world_coord) const;
    bool isVisible(const QRectF &world_rect) const;
    // zoom
    void zoomToAll();
    void zoomTo(const QPoint &screen_point, const double factor);
    void moveTo(const QPoint &screen_from, const QPoint &screen_to);
    // move
    void setViewPoint(const QPointF &world_center, const double px_per_meter);
    // conversion of length
    double pixelToMeter(const int pixel) { return pixel/m_scale_worldtoscreen; }
    int meterToPixel(const double meter) { return qRound(meter * m_scale_worldtoscreen);}
    // setters...
    void setViewRect(const QRectF &viewrect) { m_viewport = viewrect; }
    void setWorldRect(const QRectF &worldrect) { m_world = worldrect; }
    void setScreenRect(const QRect &viewrect);
private:
    bool m_viewAll;
    QRect m_screen;
    QRectF m_world;
    QRectF m_viewport;
    QPointF m_delta_worldtoscreen;
    double m_scale_worldtoscreen;
};

#endif // HELPER_H