/***************************************************************************
 *   Copyright (C) 2004 by Predrag Viceic                                  *
 *   viceic@net2000.ch                                             *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef MYMATH_H
#define MYMATH_H

#include <qobject.h>
#include <math.h>
#include <qpoint.h>
#include <splinepoint.h>
#include <sortablepoint.h>

/**
\class MyMath

\brief Some usefull functions

@author Predrag Viceic
*/
class MyMath : public QObject
{
Q_OBJECT
public:
    MyMath(QObject *parent = 0, const char *name = 0);

    ~MyMath();
    struct SPoint2D{
        long rx;
        float ry;
        long x(){
            return rx;
        }
        float y(){
            return ry;
        }
        void setX(long x){
            rx=x;
        }
        void setY(float y){
            ry=y;
        }
    };
    struct FPoint2D{
        float rx;
        float ry;
        float x(){
            return rx;
        }
        float y(){
            return ry;
        }
        void setX(float x){
            rx=x;
        }
        void setY(float y){
            ry=y;
        }
    };

    template <class T, class P> struct GenericPoint2D{
        T rx;
        P ry;
        T x(){
            return rx;
        }
        P y(){
            return ry;
        }
        void setX(T x){
            rx=x;
        }
        void setY(P y){
            ry=y;
        }
    };

    struct smartRoundSum{
        float val;
        float summedVal;
        int roundedVal;
        float summederror;
        float localerror;
        void init(float fval){
            val=fval;
            summedVal=0;
            roundedVal=0;
            summederror=0;
            localerror=0;
        }
        int myround(){
            summedVal+=val;
            roundedVal+=int(round(val));
            summederror+=roundedVal-summedVal;
            if(fabs(summederror)>1){
                localerror=int(summederror);
                summederror-=localerror;
                roundedVal-=int(localerror);
            }
            return roundedVal;
        }
        int rounded(){
            return roundedVal;
        }
    };

    static float standard_deviation(const float* data, int length);
    static void gaussian_window(float* data, int length, float alpha=2.5);
    static double linear_regression(double x1, double x2, double y1,double y2, double val);

    template <class T> static T PointOnCubicBezier( T a, T b,T c, T d, float t ){
        float   ax, bx, cx;
        float   ay, by, cy;
        float   tSquared, tCubed;
        T result;

        cx = 3.0 * (b.x() - a.x());
        bx = 3.0 * (c.x() - b.x()) - cx;
        ax = d.x() - a.x() - cx - bx;

        cy = 3.0 * (b.y() - a.y());
        by = 3.0 * (c.y() - b.y()) - cy;
        ay = d.y() - a.y() - cy - by;

        tSquared = t * t;
        tCubed = tSquared * t;

        result.setX((ax * tCubed) + (bx * tSquared) + (cx * t) + a.x());
        result.setY((ay * tCubed) + (by * tSquared) + (cy * t) + a.y());

        return result;
    }

    template <class T, class P> static float PointOnCubicBezierAt(T a, T b, T c, T d,float dt, P x){
        T returnP/*,responseP*/;
        returnP.setX(1);
        for (float i=0;i<1;i+=dt){
            T response=MyMath::PointOnCubicBezier(a,b,c,d,i);
            if(fabs(response.x()-x)<fabs(returnP.x()-x)) returnP=response;
            if (response.x()>x) break;
        }
        return float(returnP.y());
    }
};

#endif
