// @(#)root/hist:$Id$
// Author: Federico Carminati   28/02/2000

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TSpline
#define ROOT_TSpline

#ifndef ROOT_TGraph
#include "TGraph.h"
#endif

class TH1;
class TF1;

class TSpline : public TNamed, public TAttLine,
                public TAttFill, public TAttMarker
{
protected:
   Double_t  fDelta;     // Distance between equidistant knots
   Double_t  fXmin;      // Minimum value of abscissa
   Double_t  fXmax;      // Maximum value of abscissa
   Int_t     fNp;        // Number of knots
   Bool_t    fKstep;     // True of equidistant knots
   TH1F     *fHistogram; // Temporary histogram
   TGraph   *fGraph;     // Graph for drawing the knots
   Int_t     fNpx;       // Number of points used for graphical representation

   TSpline(const TSpline&);
   TSpline& operator=(const TSpline&);
   virtual void     BuildCoeff()=0;

public:
   TSpline() : fDelta(-1), fXmin(0), fXmax(0),
      fNp(0), fKstep(kFALSE), fHistogram(0), fGraph(0), fNpx(100) {}
   TSpline(const char *title, Double_t delta, Double_t xmin,
      Double_t xmax, Int_t np, Bool_t step) :
      TNamed("Spline",title), TAttFill(0,1),
      fDelta(delta), fXmin(xmin),
      fXmax(xmax), fNp(np), fKstep(step),
      fHistogram(0), fGraph(0), fNpx(100) {}
   virtual ~TSpline();

   virtual void     GetKnot(Int_t i, Double_t &x, Double_t &y) const =0;
   virtual Int_t    DistancetoPrimitive(Int_t px, Int_t py);
   virtual void     Draw(Option_t *option="");
   virtual void     ExecuteEvent(Int_t event, Int_t px, Int_t py);
   virtual Double_t GetDelta() const {return fDelta;}
   TH1F            *GetHistogram() const {return fHistogram;}
   virtual Int_t    GetNp()    const {return fNp;}
   virtual Int_t    GetNpx()   const {return fNpx;}
   virtual Double_t GetXmin()  const {return fXmin;}
   virtual Double_t GetXmax()  const {return fXmax;}
   virtual void     Paint(Option_t *option="");
   virtual Double_t Eval(Double_t x) const=0;
   virtual void     SaveAs(const char * /*filename*/,Option_t * /*option*/) const {;}
   void             SetNpx(Int_t n) {fNpx=n;}

   ClassDef (TSpline,2) // Spline base class
};


//______________________________________________________________________________
class TSplinePoly : public TObject
{
protected:
   Double_t fX;     // abscissa
   Double_t fY;     // constant term

public:
   TSplinePoly() :
      fX(0), fY(0) {}
   TSplinePoly(Double_t x, Double_t y) :
      fX(x), fY(y) {}
   TSplinePoly(TSplinePoly const &other);
   TSplinePoly &operator=(TSplinePoly const &other);

   Double_t &X() {return fX;}
   Double_t &Y() {return fY;}
   void GetKnot(Double_t &x, Double_t &y) const {x=fX; y=fY;}

   virtual Double_t Eval(Double_t) const {return fY;}

   private:
   void CopyPoly(TSplinePoly const &other);

   ClassDef(TSplinePoly,2) // Spline polynomial terms
};

inline TSplinePoly::TSplinePoly(TSplinePoly const &other)
:
   TObject(other), fX(0), fY(0)
{
  CopyPoly(other);
}


//______________________________________________________________________________
class TSplinePoly3 : public TSplinePoly
{
private:
   Double_t fB; // first order expansion coefficient :  fB*1! is the first derivative at x
   Double_t fC; // second order expansion coefficient : fC*2! is the second derivative at x
   Double_t fD; // third order expansion coefficient :  fD*3! is the third derivative at x

public:
   TSplinePoly3() :
      fB(0), fC(0), fD(0) {}
   TSplinePoly3(Double_t x, Double_t y, Double_t b, Double_t c, Double_t d) :
      TSplinePoly(x,y), fB(b), fC(c), fD(d) {}
   TSplinePoly3(TSplinePoly3 const &other);
   TSplinePoly3 &operator=(TSplinePoly3 const &other);

   Double_t &B() {return fB;}
   Double_t &C() {return fC;}
   Double_t &D() {return fD;}
   Double_t Eval(Double_t x) const {
      Double_t dx=x-fX;
      return (fY+dx*(fB+dx*(fC+dx*fD)));
   }
   Double_t Derivative(Double_t x) const {
      Double_t dx=x-fX;
      return (fB+dx*(2*fC+3*fD*dx));      
   }

private:
   void CopyPoly(TSplinePoly3 const &other);

   ClassDef(TSplinePoly3,1)  // Third spline polynomial terms
};

inline TSplinePoly3::TSplinePoly3(TSplinePoly3 const &other)
   :
  TSplinePoly(other), fB(0), fC(0), fD(0)
{
   CopyPoly(other);
}

//______________________________________________________________________________
class TSplinePoly5 : public TSplinePoly
{
private:
   Double_t fB; // first order expansion coefficient :  fB*1! is the first derivative at x
   Double_t fC; // second order expansion coefficient : fC*2! is the second derivative at x
   Double_t fD; // third order expansion coefficient :  fD*3! is the third derivative at x
   Double_t fE; // fourth order expansion coefficient : fE*4! is the fourth derivative at x
   Double_t fF; // fifth order expansion coefficient :  fF*5! is the fifth derivative at x

public:
   TSplinePoly5() :
      fB(0), fC(0), fD(0), fE(0), fF(0) {}
   TSplinePoly5(Double_t x, Double_t y, Double_t b, Double_t c,
      Double_t d, Double_t e, Double_t f) :
      TSplinePoly(x,y), fB(b), fC(c), fD(d), fE(e), fF(f) {}
   TSplinePoly5(TSplinePoly5 const &other);
   TSplinePoly5 &operator=(TSplinePoly5 const &other);

   Double_t &B() {return fB;}
   Double_t &C() {return fC;}
   Double_t &D() {return fD;}
   Double_t &E() {return fE;}
   Double_t &F() {return fF;}
   Double_t Eval(Double_t x) const {
      Double_t dx=x-fX;
      return (fY+dx*(fB+dx*(fC+dx*(fD+dx*(fE+dx*fF)))));
   }
   Double_t Derivative(Double_t x) const{
      Double_t dx=x-fX;
      return (fB+dx*(2*fC+dx*(3*fD+dx*(4*fE+dx*(5*fF)))));
   }

private:
   void CopyPoly(TSplinePoly5 const &other);

   ClassDef(TSplinePoly5,1)  // Quintic spline polynomial terms
};

inline TSplinePoly5::TSplinePoly5(TSplinePoly5 const &other)
:
    TSplinePoly(other), fB(0), fC(0), fD(0), fE(0), fF(0)
{
  CopyPoly(other);
}


//______________________________________________________________________________
class TSpline3 : public TSpline
{
protected:
   TSplinePoly3  *fPoly;       //[fNp] Array of polynomial terms
   Double_t       fValBeg;     // Initial value of first or second derivative
   Double_t       fValEnd;     // End value of first or second derivative
   Int_t          fBegCond;    // 0=no beg cond, 1=first derivative, 2=second derivative
   Int_t          fEndCond;    // 0=no end cond, 1=first derivative, 2=second derivative

   void   BuildCoeff();
   void   SetCond(const char *opt);

public:
   TSpline3() : TSpline() , fPoly(0), fValBeg(0), fValEnd(0),
      fBegCond(-1), fEndCond(-1) {}
   TSpline3(const char *title,
            Double_t x[], Double_t y[], Int_t n, const char *opt=0,
            Double_t valbeg=0, Double_t valend=0);
   TSpline3(const char *title,
            Double_t xmin, Double_t xmax,
            Double_t y[], Int_t n, const char *opt=0,
            Double_t valbeg=0, Double_t valend=0);
   TSpline3(const char *title,
            Double_t x[], const TF1 *func, Int_t n, const char *opt=0,
            Double_t valbeg=0, Double_t valend=0);
   TSpline3(const char *title,
            Double_t xmin, Double_t xmax,
            const TF1 *func, Int_t n, const char *opt=0,
            Double_t valbeg=0, Double_t valend=0);
   TSpline3(const char *title,
            const TGraph *g, const char *opt=0,
            Double_t valbeg=0, Double_t valend=0);
   TSpline3(const TH1 *h, const char *opt=0,
            Double_t valbeg=0, Double_t valend=0);
   TSpline3(const TSpline3&);
   TSpline3& operator=(const TSpline3&);
   Int_t    FindX(Double_t x) const;
   Double_t Eval(Double_t x) const;
   Double_t Derivative(Double_t x) const;
   virtual ~TSpline3() {if (fPoly) delete [] fPoly;}
   void GetCoeff(Int_t i, Double_t &x, Double_t &y, Double_t &b,
                 Double_t &c, Double_t &d) {x=fPoly[i].X();y=fPoly[i].Y();
                  b=fPoly[i].B();c=fPoly[i].C();d=fPoly[i].D();}
   void GetKnot(Int_t i, Double_t &x, Double_t &y) const
      {x=fPoly[i].X(); y=fPoly[i].Y();}
   virtual  void     SaveAs(const char *filename,Option_t *option="") const;
   virtual  void     SavePrimitive(std::ostream &out, Option_t *option = "");
   virtual  void     SetPoint(Int_t i, Double_t x, Double_t y);
   virtual  void     SetPointCoeff(Int_t i, Double_t b, Double_t c, Double_t d);
   static void Test();

   ClassDef (TSpline3,2)  // Class to create third natural splines
};


//______________________________________________________________________________
class TSpline5 : public TSpline
{
protected:
   TSplinePoly5  *fPoly;     //[fNp] Array of polynomial terms

   void BuildCoeff();
   void BoundaryConditions(const char *opt, Int_t &beg, Int_t &end,
                           const char *&cb1, const char *&ce1, const char *&cb2,
                           const char *&ce2);
   void SetBoundaries(Double_t b1, Double_t e1, Double_t b2, Double_t e2,
                      const char *cb1, const char *ce1, const char *cb2,
                      const char *ce2);
public:
   TSpline5() : TSpline() , fPoly(0) {}
   TSpline5(const char *title,
            Double_t x[], Double_t y[], Int_t n,
            const char *opt=0, Double_t b1=0, Double_t e1=0,
            Double_t b2=0, Double_t e2=0);
   TSpline5(const char *title,
            Double_t xmin, Double_t xmax,
            Double_t y[], Int_t n,
            const char *opt=0, Double_t b1=0, Double_t e1=0,
            Double_t b2=0, Double_t e2=0);
   TSpline5(const char *title,
            Double_t x[], const TF1 *func, Int_t n,
            const char *opt=0, Double_t b1=0, Double_t e1=0,
            Double_t b2=0, Double_t e2=0);
   TSpline5(const char *title,
            Double_t xmin, Double_t xmax,
            const TF1 *func, Int_t n,
            const char *opt=0, Double_t b1=0, Double_t e1=0,
            Double_t b2=0, Double_t e2=0);
   TSpline5(const char *title,
            const TGraph *g,
            const char *opt=0, Double_t b1=0, Double_t e1=0,
            Double_t b2=0, Double_t e2=0);
   TSpline5(const TH1 *h,
            const char *opt=0, Double_t b1=0, Double_t e1=0,
            Double_t b2=0, Double_t e2=0);
   TSpline5(const TSpline5&);
   TSpline5& operator=(const TSpline5&);
   Int_t    FindX(Double_t x) const;
   Double_t Eval(Double_t x) const;
   Double_t Derivative(Double_t x) const;
   virtual ~TSpline5() {if (fPoly) delete [] fPoly;}
   void GetCoeff(Int_t i, Double_t &x, Double_t &y, Double_t &b,
                 Double_t &c, Double_t &d, Double_t &e, Double_t &f)
      {x=fPoly[i].X();y=fPoly[i].Y();b=fPoly[i].B();
      c=fPoly[i].C();d=fPoly[i].D();
      e=fPoly[i].E();f=fPoly[i].F();}
   void GetKnot(Int_t i, Double_t &x, Double_t &y) const
      {x=fPoly[i].X(); y=fPoly[i].Y();}
   virtual  void     SaveAs(const char *filename,Option_t *option="") const;
   virtual  void     SavePrimitive(std::ostream &out, Option_t *option = "");
   virtual  void     SetPoint(Int_t i, Double_t x, Double_t y);
   virtual  void     SetPointCoeff(Int_t i, Double_t b, Double_t c, Double_t d,
                                   Double_t e, Double_t f);
   static void Test();

   ClassDef (TSpline5,2) // Class to create quintic natural splines
};

#endif
 TSpline.h:1
 TSpline.h:2
 TSpline.h:3
 TSpline.h:4
 TSpline.h:5
 TSpline.h:6
 TSpline.h:7
 TSpline.h:8
 TSpline.h:9
 TSpline.h:10
 TSpline.h:11
 TSpline.h:12
 TSpline.h:13
 TSpline.h:14
 TSpline.h:15
 TSpline.h:16
 TSpline.h:17
 TSpline.h:18
 TSpline.h:19
 TSpline.h:20
 TSpline.h:21
 TSpline.h:22
 TSpline.h:23
 TSpline.h:24
 TSpline.h:25
 TSpline.h:26
 TSpline.h:27
 TSpline.h:28
 TSpline.h:29
 TSpline.h:30
 TSpline.h:31
 TSpline.h:32
 TSpline.h:33
 TSpline.h:34
 TSpline.h:35
 TSpline.h:36
 TSpline.h:37
 TSpline.h:38
 TSpline.h:39
 TSpline.h:40
 TSpline.h:41
 TSpline.h:42
 TSpline.h:43
 TSpline.h:44
 TSpline.h:45
 TSpline.h:46
 TSpline.h:47
 TSpline.h:48
 TSpline.h:49
 TSpline.h:50
 TSpline.h:51
 TSpline.h:52
 TSpline.h:53
 TSpline.h:54
 TSpline.h:55
 TSpline.h:56
 TSpline.h:57
 TSpline.h:58
 TSpline.h:59
 TSpline.h:60
 TSpline.h:61
 TSpline.h:62
 TSpline.h:63
 TSpline.h:64
 TSpline.h:65
 TSpline.h:66
 TSpline.h:67
 TSpline.h:68
 TSpline.h:69
 TSpline.h:70
 TSpline.h:71
 TSpline.h:72
 TSpline.h:73
 TSpline.h:74
 TSpline.h:75
 TSpline.h:76
 TSpline.h:77
 TSpline.h:78
 TSpline.h:79
 TSpline.h:80
 TSpline.h:81
 TSpline.h:82
 TSpline.h:83
 TSpline.h:84
 TSpline.h:85
 TSpline.h:86
 TSpline.h:87
 TSpline.h:88
 TSpline.h:89
 TSpline.h:90
 TSpline.h:91
 TSpline.h:92
 TSpline.h:93
 TSpline.h:94
 TSpline.h:95
 TSpline.h:96
 TSpline.h:97
 TSpline.h:98
 TSpline.h:99
 TSpline.h:100
 TSpline.h:101
 TSpline.h:102
 TSpline.h:103
 TSpline.h:104
 TSpline.h:105
 TSpline.h:106
 TSpline.h:107
 TSpline.h:108
 TSpline.h:109
 TSpline.h:110
 TSpline.h:111
 TSpline.h:112
 TSpline.h:113
 TSpline.h:114
 TSpline.h:115
 TSpline.h:116
 TSpline.h:117
 TSpline.h:118
 TSpline.h:119
 TSpline.h:120
 TSpline.h:121
 TSpline.h:122
 TSpline.h:123
 TSpline.h:124
 TSpline.h:125
 TSpline.h:126
 TSpline.h:127
 TSpline.h:128
 TSpline.h:129
 TSpline.h:130
 TSpline.h:131
 TSpline.h:132
 TSpline.h:133
 TSpline.h:134
 TSpline.h:135
 TSpline.h:136
 TSpline.h:137
 TSpline.h:138
 TSpline.h:139
 TSpline.h:140
 TSpline.h:141
 TSpline.h:142
 TSpline.h:143
 TSpline.h:144
 TSpline.h:145
 TSpline.h:146
 TSpline.h:147
 TSpline.h:148
 TSpline.h:149
 TSpline.h:150
 TSpline.h:151
 TSpline.h:152
 TSpline.h:153
 TSpline.h:154
 TSpline.h:155
 TSpline.h:156
 TSpline.h:157
 TSpline.h:158
 TSpline.h:159
 TSpline.h:160
 TSpline.h:161
 TSpline.h:162
 TSpline.h:163
 TSpline.h:164
 TSpline.h:165
 TSpline.h:166
 TSpline.h:167
 TSpline.h:168
 TSpline.h:169
 TSpline.h:170
 TSpline.h:171
 TSpline.h:172
 TSpline.h:173
 TSpline.h:174
 TSpline.h:175
 TSpline.h:176
 TSpline.h:177
 TSpline.h:178
 TSpline.h:179
 TSpline.h:180
 TSpline.h:181
 TSpline.h:182
 TSpline.h:183
 TSpline.h:184
 TSpline.h:185
 TSpline.h:186
 TSpline.h:187
 TSpline.h:188
 TSpline.h:189
 TSpline.h:190
 TSpline.h:191
 TSpline.h:192
 TSpline.h:193
 TSpline.h:194
 TSpline.h:195
 TSpline.h:196
 TSpline.h:197
 TSpline.h:198
 TSpline.h:199
 TSpline.h:200
 TSpline.h:201
 TSpline.h:202
 TSpline.h:203
 TSpline.h:204
 TSpline.h:205
 TSpline.h:206
 TSpline.h:207
 TSpline.h:208
 TSpline.h:209
 TSpline.h:210
 TSpline.h:211
 TSpline.h:212
 TSpline.h:213
 TSpline.h:214
 TSpline.h:215
 TSpline.h:216
 TSpline.h:217
 TSpline.h:218
 TSpline.h:219
 TSpline.h:220
 TSpline.h:221
 TSpline.h:222
 TSpline.h:223
 TSpline.h:224
 TSpline.h:225
 TSpline.h:226
 TSpline.h:227
 TSpline.h:228
 TSpline.h:229
 TSpline.h:230
 TSpline.h:231
 TSpline.h:232
 TSpline.h:233
 TSpline.h:234
 TSpline.h:235
 TSpline.h:236
 TSpline.h:237
 TSpline.h:238
 TSpline.h:239
 TSpline.h:240
 TSpline.h:241
 TSpline.h:242
 TSpline.h:243
 TSpline.h:244
 TSpline.h:245
 TSpline.h:246
 TSpline.h:247
 TSpline.h:248
 TSpline.h:249
 TSpline.h:250
 TSpline.h:251
 TSpline.h:252
 TSpline.h:253
 TSpline.h:254
 TSpline.h:255
 TSpline.h:256
 TSpline.h:257
 TSpline.h:258
 TSpline.h:259
 TSpline.h:260
 TSpline.h:261
 TSpline.h:262
 TSpline.h:263
 TSpline.h:264
 TSpline.h:265
 TSpline.h:266
 TSpline.h:267
 TSpline.h:268
 TSpline.h:269
 TSpline.h:270
 TSpline.h:271
 TSpline.h:272
 TSpline.h:273
 TSpline.h:274
 TSpline.h:275
 TSpline.h:276
 TSpline.h:277
 TSpline.h:278
 TSpline.h:279
 TSpline.h:280
 TSpline.h:281
 TSpline.h:282
 TSpline.h:283
 TSpline.h:284
 TSpline.h:285
 TSpline.h:286
 TSpline.h:287
 TSpline.h:288
 TSpline.h:289
 TSpline.h:290
 TSpline.h:291
 TSpline.h:292
 TSpline.h:293
 TSpline.h:294
 TSpline.h:295
 TSpline.h:296
 TSpline.h:297
 TSpline.h:298
 TSpline.h:299
 TSpline.h:300
 TSpline.h:301
 TSpline.h:302
 TSpline.h:303
 TSpline.h:304
 TSpline.h:305
 TSpline.h:306
 TSpline.h:307
 TSpline.h:308
 TSpline.h:309
 TSpline.h:310
 TSpline.h:311