/**********************************************************************
** Copyright (C) 2000 Trolltech AS.  All rights reserved.
**
** This file is part of Qtopia Environment.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/

#include <math.h>
#include <float.h>
#include "qmath.h"

#ifdef QT_QWS_CASSIOPEIA

double qFabs( double a )
{
    if ( a < 0.0 )
	return -a;
    return a;
}

double qSqrt( double value )
{
    const double tol = 0.000005; // relative error tolerance
    double old_app, new_app;
    if (value == 0.0)
	return 0.0;
    old_app = value; // take value as first approximation
    new_app = (old_app + value/old_app)/2;
    while (qFabs((new_app-old_app)/new_app) > tol)
    {
	old_app = new_app;
	new_app = (old_app + value/old_app)/2;
    }

    return new_app;
}

const double Q_PI   = 3.14159265358979323846;   // pi
const double Q_2PI  = 6.28318530717958647693;   // 2*pi
const double Q_PI2  = 1.57079632679489661923;   // pi/2

static double qsincos( double a, int calcCos )
{
    int sign;
    double a2;
    double a3;
    double a5;
    double a7;
    double a9;
    double a11;

    if ( calcCos )                              // calculate cosine
	a -= Q_PI2;
    if ( a >= Q_2PI || a <= -Q_2PI ) {          // fix range: -2*pi < a < 2*pi
	int m = (int)(a/Q_2PI);
	a -= Q_2PI*m;
    }
    if ( a < 0.0 )                              // 0 <= a < 2*pi
	a += Q_2PI;
    sign = a > Q_PI ? -1 : 1;
    if ( a >= Q_PI )
	a = Q_2PI - a;
    if ( a >= Q_PI2 )
	a = Q_PI - a;
    if ( calcCos )
	sign = -sign;
    a2  = a*a;                           // here: 0 <= a < pi/4
    a3  = a2*a;                          // make taylor sin sum
    a5  = a3*a2;
    a7  = a5*a2;
    a9  = a7*a2;
    a11 = a9*a2;
    return (a-a3/6+a5/120-a7/5040+a9/362880-a11/39916800)*sign;
}

double qSin( double a ) { return qsincos(a,0); }
double qCos( double a ) { return qsincos(a,1); }

//atan2 returns values from -PI to PI, so we have to do the same
double qATan2( double y, double x )
{
    double r;
    if ( x != 0.0 ) {
	double a = qFabs(y/x);
	if ( a <= 1 )
	    r = a/(1+ 0.28*a*a);
	else
	    r = Q_PI2 - a/(a*a + 0.28);
    } else {
	r = Q_PI2;
    }

    if ( y >= 0.0 ) {
	if ( x >= 0.0 )
	    return r;
	else
	    return Q_PI - r;
    } else {
	if ( x >= 0.0 )
	    return 0.0 - r;
	else
	    return -Q_PI + r;
    }
}

double qATan( double a )
{
    return qATan2( a, 1.0 );
}

double qASin( double a )
{
    return qATan2( a, qSqrt(1-a*a) );
}

double qTan( double a )
{
    double ca = qCos(a);
    if ( ca != 0.0 )
	return qSin( a ) / ca;

    return MAXDOUBLE;
}

double qFloor( double a )
{
    long i = (long) a;
    return (double) i;
}

#else

double qSqrt( double value ) { return sqrt( value ); }
double qSin( double a ) { return sin(a); }
double qCos( double a ) { return cos(a); }
double qATan2( double y, double x ) { return atan2(y,x); }
double qATan( double a ) { return atan(a); }
double qASin( double a ) { return asin(a); }
double qTan( double a ) { return tan(a); }
double qFloor( double a ) { return floor(a); }
double qFabs( double a ) { return fabs(a); }

#endif