// Created on: 1995-08-28
// Created by: Laurent BOURESCHE
// Copyright (c) 1995-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

#ifndef _PLib_HeaderFile
#define _PLib_HeaderFile

#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
#include <Standard_Handle.hxx>

#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array2OfReal.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <Standard_Boolean.hxx>
#include <TColgp_Array2OfPnt.hxx>
#include <GeomAbs_Shape.hxx>
class math_Matrix;

//! PLib means Polynomial  functions library.  This pk
//! provides  basic       computation    functions for
//! polynomial functions.
//! Note: weight arrays can be passed by pointer for
//! some functions so that NULL pointer is valid.
//! That means no weights passed.
class PLib
{
public:
  DEFINE_STANDARD_ALLOC

  //! Used as argument for a non rational functions
  inline static TColStd_Array1OfReal* NoWeights() { return NULL; }

  //! Used as argument for a non rational functions
  inline static TColStd_Array2OfReal* NoWeights2() { return NULL; }

  //! Copy in FP the coordinates of the poles.
  Standard_EXPORT static void SetPoles(const TColgp_Array1OfPnt& Poles, TColStd_Array1OfReal& FP);

  //! Copy in FP the coordinates of the poles.
  Standard_EXPORT static void SetPoles(const TColgp_Array1OfPnt&   Poles,
                                       const TColStd_Array1OfReal& Weights,
                                       TColStd_Array1OfReal&       FP);

  //! Get from FP the coordinates of the poles.
  Standard_EXPORT static void GetPoles(const TColStd_Array1OfReal& FP, TColgp_Array1OfPnt& Poles);

  //! Get from FP the coordinates of the poles.
  Standard_EXPORT static void GetPoles(const TColStd_Array1OfReal& FP,
                                       TColgp_Array1OfPnt&         Poles,
                                       TColStd_Array1OfReal&       Weights);

  //! Copy in FP the coordinates of the poles.
  Standard_EXPORT static void SetPoles(const TColgp_Array1OfPnt2d& Poles, TColStd_Array1OfReal& FP);

  //! Copy in FP the coordinates of the poles.
  Standard_EXPORT static void SetPoles(const TColgp_Array1OfPnt2d& Poles,
                                       const TColStd_Array1OfReal& Weights,
                                       TColStd_Array1OfReal&       FP);

  //! Get from FP the coordinates of the poles.
  Standard_EXPORT static void GetPoles(const TColStd_Array1OfReal& FP, TColgp_Array1OfPnt2d& Poles);

  //! Get from FP the coordinates of the poles.
  Standard_EXPORT static void GetPoles(const TColStd_Array1OfReal& FP,
                                       TColgp_Array1OfPnt2d&       Poles,
                                       TColStd_Array1OfReal&       Weights);

  //! Returns the Binomial Cnp. N should be <= BSplCLib::MaxDegree().
  Standard_EXPORT static Standard_Real Bin(const Standard_Integer N, const Standard_Integer P);

  //! Computes the derivatives of a ratio at order
  //! <N> in dimension <Dimension>.
  //!
  //! <Ders> is an  array containing the  values  of the
  //! input   derivatives from  0 to  Min(<N>,<Degree>).
  //! For   orders   higher  than <Degree>    the  inputcd /s2d1/BMDL/
  //! derivatives   are assumed to be  0.
  //!
  //! Content of <Ders> :
  //!
  //! x(1),x(2),...,x(Dimension),w
  //! x'(1),x'(2),...,x'(Dimension),w'
  //! x''(1),x''(2),...,x''(Dimension),w''
  //!
  //! If  <All> is false, only the   derivative at order
  //! <N> is computed.  <RDers>  is an array   of length
  //! Dimension which will contain the result :
  //!
  //! x(1)/w , x(2)/w ,  ... derivated <N> times
  //!
  //! If <All> is  true all the  derivatives up to order
  //! <N> are computed.   <RDers> is an array of  length
  //! Dimension * (N+1) which will contains :
  //!
  //! x(1)/w , x(2)/w ,  ...
  //! x(1)/w , x(2)/w ,  ... derivated <1> times
  //! x(1)/w , x(2)/w ,  ... derivated <2> times
  //! ...
  //! x(1)/w , x(2)/w ,  ... derivated <N> times
  //!
  //! Warning: <RDers> must be dimensioned properly.
  Standard_EXPORT static void RationalDerivative(const Standard_Integer Degree,
                                                 const Standard_Integer N,
                                                 const Standard_Integer Dimension,
                                                 Standard_Real&         Ders,
                                                 Standard_Real&         RDers,
                                                 const Standard_Boolean All = Standard_True);

  //! Computes DerivativesRequest derivatives of a ratio at
  //! of a BSpline function of degree <Degree>
  //! dimension <Dimension>.
  //!
  //! <PolesDerivatives> is an  array containing the  values
  //! of the input   derivatives from  0 to  <DerivativeRequest>
  //! For   orders   higher  than <Degree>    the  input
  //! derivatives   are assumed to be  0.
  //!
  //! Content of <PoleasDerivatives> :
  //!
  //! x(1),x(2),...,x(Dimension)
  //! x'(1),x'(2),...,x'(Dimension)
  //! x''(1),x''(2),...,x''(Dimension)
  //!
  //! WeightsDerivatives is an array that contains derivatives
  //! from 0 to  <DerivativeRequest>
  //! After returning from the routine the array
  //! RationalDerivatives contains the following
  //! x(1)/w , x(2)/w ,  ...
  //! x(1)/w , x(2)/w ,  ...   derivated once
  //! x(1)/w , x(2)/w ,  ...   twice
  //! x(1)/w , x(2)/w ,  ... derivated <DerivativeRequest> times
  //!
  //! The array RationalDerivatives and PolesDerivatives
  //! can be same since the overwrite is non destructive within
  //! the algorithm
  //!
  //! Warning: <RationalDerivates> must be dimensioned properly.
  Standard_EXPORT static void RationalDerivatives(const Standard_Integer DerivativesRequest,
                                                  const Standard_Integer Dimension,
                                                  Standard_Real&         PolesDerivatives,
                                                  Standard_Real&         WeightsDerivatives,
                                                  Standard_Real&         RationalDerivates);

  //! Performs Horner method with synthetic division for derivatives
  //! parameter <U>, with <Degree> and <Dimension>.
  //! PolynomialCoeff are stored in the following fashion
  //! @code
  //! c0(1)      c0(2) ....       c0(Dimension)
  //! c1(1)      c1(2) ....       c1(Dimension)
  //!
  //! cDegree(1) cDegree(2) ....  cDegree(Dimension)
  //! @endcode
  //! where the polynomial is defined as :
  //! @code
  //! 2                     Degree
  //! c0 + c1 X + c2 X  +  ....   cDegree X
  //! @endcode
  //! Results stores the result in the following format
  //! @code
  //! f(1)             f(2)  ....     f(Dimension)
  //! (1)           (1)              (1)
  //! f  (1)        f   (2) ....     f   (Dimension)
  //!
  //! (DerivativeRequest)            (DerivativeRequest)
  //! f  (1)                         f   (Dimension)
  //! @endcode
  //! this just evaluates the point at parameter U
  //!
  //! Warning: <Results> and <PolynomialCoeff> must be dimensioned properly
  Standard_EXPORT static void EvalPolynomial(const Standard_Real    U,
                                             const Standard_Integer DerivativeOrder,
                                             const Standard_Integer Degree,
                                             const Standard_Integer Dimension,
                                             Standard_Real&         PolynomialCoeff,
                                             Standard_Real&         Results);

  //! Same as above with DerivativeOrder = 0;
  Standard_EXPORT static void NoDerivativeEvalPolynomial(const Standard_Real    U,
                                                         const Standard_Integer Degree,
                                                         const Standard_Integer Dimension,
                                                         const Standard_Integer DegreeDimension,
                                                         Standard_Real&         PolynomialCoeff,
                                                         Standard_Real&         Results);

  //! Applies EvalPolynomial twice to evaluate the derivative
  //! of orders UDerivativeOrder in U, VDerivativeOrder in V
  //! at parameters U,V
  //!
  //! PolynomialCoeff are stored in the following fashion
  //! @code
  //! c00(1)  ....       c00(Dimension)
  //! c10(1)  ....       c10(Dimension)
  //! ....
  //! cm0(1)  ....       cm0(Dimension)
  //! ....
  //! c01(1)  ....       c01(Dimension)
  //! c11(1)  ....       c11(Dimension)
  //! ....
  //! cm1(1)  ....       cm1(Dimension)
  //! ....
  //! c0n(1)  ....       c0n(Dimension)
  //! c1n(1)  ....       c1n(Dimension)
  //! ....
  //! cmn(1)  ....       cmn(Dimension)
  //! @endcode
  //! where the polynomial is defined as :
  //! @code
  //! 2                 m
  //! c00 + c10 U + c20 U  +  ....  + cm0 U
  //! 2                   m
  //! + c01 V + c11 UV + c21 U V  +  ....  + cm1 U  V
  //! n               m n
  //! + .... + c0n V +  ....  + cmn U V
  //! @endcode
  //! with m = UDegree and n = VDegree
  //!
  //! Results stores the result in the following format
  //! @code
  //! f(1)             f(2)  ....     f(Dimension)
  //! @endcode
  //! Warning: <Results> and <PolynomialCoeff> must be dimensioned properly
  Standard_EXPORT static void EvalPoly2Var(const Standard_Real    U,
                                           const Standard_Real    V,
                                           const Standard_Integer UDerivativeOrder,
                                           const Standard_Integer VDerivativeOrder,
                                           const Standard_Integer UDegree,
                                           const Standard_Integer VDegree,
                                           const Standard_Integer Dimension,
                                           Standard_Real&         PolynomialCoeff,
                                           Standard_Real&         Results);

  //! Performs the Lagrange Interpolation of
  //! given series of points with given parameters
  //! with the requested derivative order
  //! Results will store things in the following format
  //! with d = DerivativeOrder
  //! @code
  //! [0],             [Dimension-1]              : value
  //! [Dimension],     [Dimension  + Dimension-1] : first derivative
  //!
  //! [d *Dimension],  [d*Dimension + Dimension-1]: dth   derivative
  //! @endcode
  Standard_EXPORT static Standard_Integer EvalLagrange(const Standard_Real    U,
                                                       const Standard_Integer DerivativeOrder,
                                                       const Standard_Integer Degree,
                                                       const Standard_Integer Dimension,
                                                       Standard_Real&         ValueArray,
                                                       Standard_Real&         ParameterArray,
                                                       Standard_Real&         Results);

  //! Performs the Cubic Hermite Interpolation of
  //! given series of points with given parameters
  //! with the requested derivative order.
  //! ValueArray stores the value at the first and
  //! last parameter. It has the following format :
  //! @code
  //! [0],             [Dimension-1]              : value at first param
  //! [Dimension],     [Dimension  + Dimension-1] : value at last param
  //! @endcode
  //! Derivative array stores the value of the derivatives
  //! at the first parameter and at the last parameter
  //! in the following format
  //! @code
  //! [0],             [Dimension-1]              : derivative at
  //! @endcode
  //! first param
  //! @code
  //! [Dimension],     [Dimension  + Dimension-1] : derivative at
  //! @endcode
  //! last param
  //!
  //! ParameterArray  stores the first and last parameter
  //! in the following format :
  //! @code
  //! [0] : first parameter
  //! [1] : last  parameter
  //! @endcode
  //!
  //! Results will store things in the following format
  //! with d = DerivativeOrder
  //! @code
  //! [0],             [Dimension-1]              : value
  //! [Dimension],     [Dimension  + Dimension-1] : first derivative
  //!
  //! [d *Dimension],  [d*Dimension + Dimension-1]: dth   derivative
  //! @endcode
  Standard_EXPORT static Standard_Integer EvalCubicHermite(const Standard_Real    U,
                                                           const Standard_Integer DerivativeOrder,
                                                           const Standard_Integer Dimension,
                                                           Standard_Real&         ValueArray,
                                                           Standard_Real&         DerivativeArray,
                                                           Standard_Real&         ParameterArray,
                                                           Standard_Real&         Results);

  //! This build the coefficient of Hermite's polynomes on
  //! [FirstParameter, LastParameter]
  //!
  //! if j <= FirstOrder+1 then
  //!
  //! MatrixCoefs[i, j] = ith coefficient of the polynome H0,j-1
  //!
  //! else
  //!
  //! MatrixCoefs[i, j] = ith coefficient of the polynome H1,k
  //! with k = j - FirstOrder - 2
  //!
  //! return false if
  //! - |FirstParameter| > 100
  //! - |LastParameter| > 100
  //! - |FirstParameter| +|LastParameter| < 1/100
  //! -   |LastParameter - FirstParameter|
  //! / (|FirstParameter| +|LastParameter|)  < 1/100
  Standard_EXPORT static Standard_Boolean HermiteCoefficients(const Standard_Real    FirstParameter,
                                                              const Standard_Real    LastParameter,
                                                              const Standard_Integer FirstOrder,
                                                              const Standard_Integer LastOrder,
                                                              math_Matrix&           MatrixCoefs);

  Standard_EXPORT static void CoefficientsPoles(const TColgp_Array1OfPnt&   Coefs,
                                                const TColStd_Array1OfReal* WCoefs,
                                                TColgp_Array1OfPnt&         Poles,
                                                TColStd_Array1OfReal*       WPoles);

  Standard_EXPORT static void CoefficientsPoles(const TColgp_Array1OfPnt2d& Coefs,
                                                const TColStd_Array1OfReal* WCoefs,
                                                TColgp_Array1OfPnt2d&       Poles,
                                                TColStd_Array1OfReal*       WPoles);

  Standard_EXPORT static void CoefficientsPoles(const TColStd_Array1OfReal& Coefs,
                                                const TColStd_Array1OfReal* WCoefs,
                                                TColStd_Array1OfReal&       Poles,
                                                TColStd_Array1OfReal*       WPoles);

  Standard_EXPORT static void CoefficientsPoles(const Standard_Integer      dim,
                                                const TColStd_Array1OfReal& Coefs,
                                                const TColStd_Array1OfReal* WCoefs,
                                                TColStd_Array1OfReal&       Poles,
                                                TColStd_Array1OfReal*       WPoles);

  Standard_EXPORT static void Trimming(const Standard_Real   U1,
                                       const Standard_Real   U2,
                                       TColgp_Array1OfPnt&   Coeffs,
                                       TColStd_Array1OfReal* WCoeffs);

  Standard_EXPORT static void Trimming(const Standard_Real   U1,
                                       const Standard_Real   U2,
                                       TColgp_Array1OfPnt2d& Coeffs,
                                       TColStd_Array1OfReal* WCoeffs);

  Standard_EXPORT static void Trimming(const Standard_Real   U1,
                                       const Standard_Real   U2,
                                       TColStd_Array1OfReal& Coeffs,
                                       TColStd_Array1OfReal* WCoeffs);

  Standard_EXPORT static void Trimming(const Standard_Real    U1,
                                       const Standard_Real    U2,
                                       const Standard_Integer dim,
                                       TColStd_Array1OfReal&  Coeffs,
                                       TColStd_Array1OfReal*  WCoeffs);

  Standard_EXPORT static void CoefficientsPoles(const TColgp_Array2OfPnt&   Coefs,
                                                const TColStd_Array2OfReal* WCoefs,
                                                TColgp_Array2OfPnt&         Poles,
                                                TColStd_Array2OfReal*       WPoles);

  Standard_EXPORT static void UTrimming(const Standard_Real   U1,
                                        const Standard_Real   U2,
                                        TColgp_Array2OfPnt&   Coeffs,
                                        TColStd_Array2OfReal* WCoeffs);

  Standard_EXPORT static void VTrimming(const Standard_Real   V1,
                                        const Standard_Real   V2,
                                        TColgp_Array2OfPnt&   Coeffs,
                                        TColStd_Array2OfReal* WCoeffs);

  //! Compute the coefficients in the canonical base of the
  //! polynomial satisfying the given constraints
  //! at the given parameters
  //! The array FirstContr(i,j) i=1,Dimension j=0,FirstOrder
  //! contains the values of the constraint at parameter FirstParameter
  //! idem for LastConstr
  Standard_EXPORT static Standard_Boolean HermiteInterpolate(
    const Standard_Integer      Dimension,
    const Standard_Real         FirstParameter,
    const Standard_Real         LastParameter,
    const Standard_Integer      FirstOrder,
    const Standard_Integer      LastOrder,
    const TColStd_Array2OfReal& FirstConstr,
    const TColStd_Array2OfReal& LastConstr,
    TColStd_Array1OfReal&       Coefficients);

  //! Compute the number of points used for integral
  //! computations (NbGaussPoints) and the degree of Jacobi
  //! Polynomial (WorkDegree).
  //! ConstraintOrder has to be GeomAbs_C0, GeomAbs_C1 or GeomAbs_C2
  //! Code: Code d' init. des parametres de discretisation.
  //! = -5
  //! = -4
  //! = -3
  //! = -2
  //! = -1
  //! =  1 calcul rapide avec precision moyenne.
  //! =  2 calcul rapide avec meilleure precision.
  //! =  3 calcul un peu plus lent avec bonne precision.
  //! =  4 calcul lent avec la meilleure precision possible.
  Standard_EXPORT static void JacobiParameters(const GeomAbs_Shape    ConstraintOrder,
                                               const Standard_Integer MaxDegree,
                                               const Standard_Integer Code,
                                               Standard_Integer&      NbGaussPoints,
                                               Standard_Integer&      WorkDegree);

  //! translates from GeomAbs_Shape to Integer
  Standard_EXPORT static Standard_Integer NivConstr(const GeomAbs_Shape ConstraintOrder);

  //! translates from Integer to GeomAbs_Shape
  Standard_EXPORT static GeomAbs_Shape ConstraintOrder(const Standard_Integer NivConstr);

  Standard_EXPORT static void EvalLength(const Standard_Integer Degree,
                                         const Standard_Integer Dimension,
                                         Standard_Real&         PolynomialCoeff,
                                         const Standard_Real    U1,
                                         const Standard_Real    U2,
                                         Standard_Real&         Length);

  Standard_EXPORT static void EvalLength(const Standard_Integer Degree,
                                         const Standard_Integer Dimension,
                                         Standard_Real&         PolynomialCoeff,
                                         const Standard_Real    U1,
                                         const Standard_Real    U2,
                                         const Standard_Real    Tol,
                                         Standard_Real&         Length,
                                         Standard_Real&         Error);
};

#endif // _PLib_HeaderFile
