#ifndef FUNC_H
#define FUNC_H

//
//  Mathmatical functions generalized in a C++ perspective.
//
  
/*!
\brief Mathematical function with one argument.
*/
#define funcA1(nm,fx,x,TYPEFX,TYPEX) \
class nm { \
public: \
  void operator()( TYPEX & val, TYPEX x ) { val = (fx); } \
  TYPEFX operator() ( TYPEX x ) { return (fx); } \
}

/*!
\brief Mathematical function with two arguments.

\parExample
\verbatim
  funcA2(sin2,sin((x*x-y*y)*0.25),x,y,double,doublec);
  sin2 f2;

  double z;
  f2(z,1.0,0.0);
\endverbatim
*/
#define funcA2(nm,fx,x0,x1,TYPEFX,TYPEX) \
class nm { \
public: \
  void operator()( TYPEFX & val, TYPEX x0, TYPEX x1 ) { val = (fx); } \
  TYPEFX operator()( TYPEX x0, TYPEX x1 ) { return (fx); } \
}

/*!
 \brief Mathematical function with three arguments.
*/
#define funcA3(nm,fx,x0,x1,x2,TYPEFX,TYPEX) \
class nm { \
public: \
  void operator()( TYPEFX & val, TYPEX x0, TYPEX x1, TYPEX x2 ) { val = (fx); } \
  TYPEFX operator()( TYPEX x0, TYPEX x1, TYPEX x2 ) { return (fx); } \
}

/*!
\brief Mathematical function of one argument and two variables.

The client uses the variable naming convention of v0 for the
 first variable, v1 for the second.

No explicit support for references, this class could be upgraded
 for their support in constructor initialization.

The variables were given the type of the function TYPEFX. 

\par Example
\verbatim
  pt2 y; // 2D point
  pt2 p0(1.0,2.0);
  pt2 p1(3.5,6.0);
  funcA1V2(finterp,v0+(v1-v0)*x,x,pt2,double) f(p0,p1));
  y = f(1.0);
  ...
  f(y,2.0);
\endverbatim
*/
#define funcA1V2(nm,fx,x,TYPEFX,TYPEX) \
class nm { public : \
  TYPEFX v0, v1; \
  nm(TYPEFX v0_, TYPEFX v1_) : v0(v0_), v1(v1_) {} \
  void operator()(TYPEFX & val, TYPEX x) { val = (fx); } \
  TYPEFX operator() ( TYPEX x ) { return (fx); } }

/*!
\brief Mathematical function of one argument and one variable.
*/
#define funcA1V1(nm,fx,x,TYPEFX,TYPEX) \
class nm { public : \
  TYPEFX v0; \
  nm(TYPEFX v0_) : v0(v0_) {} \
  void operator()(TYPEFX & val, TYPEX x) { val = (fx); } \
  TYPEFX operator() ( TYPEX x ) { return (fx); } }

/*!
\brief Mathematical function of one argument and three variables.
*/
#define funcA1V3(nm,fx,x,TYPEFX,TYPEX) \
class nm { public : \
  TYPEFX v0, v1, v2; \
  nm(TYPEFX v0_, TYPEFX v1_, TYPEFX v2_) : v0(v0_), v1(v1_), v2(v2_) {} \
  void operator()(TYPEFX & val, TYPEX x) { val = (fx); } \
  TYPEFX operator() ( TYPEX x ) { return (fx); } }


/*!
\brief Maths function of one argument, the output and 
       input are template parameters.

The naming convention for funcTA1.
 func is short for function.  T for template. A1 for
 one arguemnt.

\par Example
\verbatim
funcTA1(cubic2,1.0+x*(1.0+x*(1.0+x)),x);
function test()
{
  cubic2<double,double> f;
  double y = f(1.0);
  ...
\endverbatim
*/
#define funcTA1(nm,fx,x) \
template< typename FX, typename X > \
class nm { \
public: \
  void operator()( FX & val, X x ) { val = (fx); } \
  FX operator()( X x ) { return (fx); } \
}

/*!
\brief Maths function of two arguments, the output and 
       input are template parameters.

The naming convention for funcTA2.
 func is short for function.  T for template. A2 for
 two arguemnts.

\par Example
\verbatim
funcTA2(tri1,(1.0-u-v)*2.0+u*3.0+v*5.0,u,v);
function test()
{
  tri1<double,double> f;
  double y = f(0.2,0.3);
  ...
\endverbatim
*/
#define funcTA2(nm,fx,x0,x1) \
template< typename FX, typename X > \
class nm { \
public: \
  void operator()( FX & val, X x0, X x1 ) { val = (fx); } \
  FX operator()( X x0, X x1 ) { return (fx); } \
}

/*!
\brief Maths function of three arguments, the output and 
       input are template parameters.
*/
#define funcTA3(nm,fx,x0,x1,x2) \
template< typename FX, typename X > \
class nm { \
public: \
  void operator()( FX & val, X x0, X x1, X x2 ) { val = (fx); } \
  FX operator()( X x0, X x1, X x2 ) { return (fx); } \
}


#endif


