// @(#)root/graf:$Name:  $:$Id: TGraphBentErrors.cxx,v 1.4 2004/07/06 14:55:04 brun Exp $
// Author: Dave Morrison  30/06/2003

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

#include <string.h>

#include "Riostream.h"
#include "TROOT.h"
#include "TGraphBentErrors.h"
#include "TStyle.h"
#include "TMath.h"
#include "TArrow.h"
#include "TVirtualPad.h"
#include "TF1.h"

ClassImp(TGraphBentErrors)

//______________________________________________________________________________
//
//   A TGraphBentErrors is a TGraph with bent, assymetric error bars.
//   The various format options to draw a TGraphBentErrors are explained in
//     TGraphBentErrors::Paint.
//
//  The picture below has been generated by the following macro:
//------------------------------------------------------------------------
//{
//   gROOT->Reset();
//
//   Int_t n = 10;
//   Double_t x[n]  = {-0.22, 0.05, 0.25, 0.35, 0.5, 0.61,0.7,0.85,0.89,0.95};
//   Double_t y[n]  = {1,2.9,5.6,7.4,9,9.6,8.7,6.3,4.5,1};
//   Double_t exl[n] = {.05,.1,.07,.07,.04,.05,.06,.07,.08,.05};
//   Double_t eyl[n] = {.8,.7,.6,.5,.4,.4,.5,.6,.7,.8};
//   Double_t exh[n] = {.02,.08,.05,.05,.03,.03,.04,.05,.06,.03};
//   Double_t eyh[n] = {.6,.5,.4,.3,.2,.2,.3,.4,.5,.6};
//   Double_t exld[n] = {.0,.0,.0,.0,.0,.0,.0,.0,.0,.0};
//   Double_t eyld[n] = {.0,.0,.0,.0,.0,.0,.0,.0,.0,.0};
//   Double_t exhd[n] = {.0,.0,.0,.0,.0,.0,.0,.0,.0,.0};
//   Double_t eyhd[n] = {.0,.0,.0,.0,.0,.0,.0,.0,.05,.0};
//   gr = new TGraphBentErrors(n,x,y,exl,exh,eyl,eyh,exld,exhd,eyld,eyhd);
//   gr->SetTitle("TGraphBentErrors Example");
//   gr->SetMarkerColor(4);
//   gr->SetMarkerStyle(21);
//   gr->Draw("ALP");
//}
//Begin_Html
/*
<img src="gif/benterrors.gif">
*/
//End_Html
//

//_____________________________________________________________________________
TGraphBentErrors::TGraphBentErrors(): TGraph()
{
//*-*-*-*-*-*-*-*-*-*-*TGraphBentErrors default constructor*-*-*-*-*-*-*-*-*-*
//*-*                  =====================================
   fEXlow       = 0;
   fEYlow       = 0;
   fEXhigh      = 0;
   fEYhigh      = 0;

   fEXlowd       = 0;
   fEYlowd       = 0;
   fEXhighd      = 0;
   fEYhighd      = 0;
}



//______________________________________________________________________________
TGraphBentErrors::TGraphBentErrors(const TGraphBentErrors &gr)
       : TGraph(gr)
{
// TGraphBentErrors copy constructor 
   
   fEXlow  = fEYlow  = fEXhigh  = fEYhigh = 0;
   fEXlowd = fEYlowd = fEXhighd = fEYhighd = 0;
   if (fNpoints == 0) return;
   fEXlow   = new Double_t[fNpoints];
   fEYlow   = new Double_t[fNpoints];
   fEXhigh  = new Double_t[fNpoints];
   fEYhigh  = new Double_t[fNpoints];
   fEXlowd  = new Double_t[fNpoints];
   fEYlowd  = new Double_t[fNpoints];
   fEXhighd = new Double_t[fNpoints];
   fEYhighd = new Double_t[fNpoints];
   for (Int_t i=0;i<fNpoints;i++) {
      fEXlow[i]   = gr.fEXlow[i];
      fEYlow[i]   = gr.fEYlow[i];
      fEXhigh[i]  = gr.fEXhigh[i];
      fEYhigh[i]  = gr.fEYhigh[i];
      fEXlowd[i]  = gr.fEXlowd[i];
      fEYlowd[i]  = gr.fEYlowd[i];
      fEXhighd[i] = gr.fEXhighd[i];
      fEYhighd[i] = gr.fEYhighd[i];
   }
}

//_____________________________________________________________________________
TGraphBentErrors::TGraphBentErrors(Int_t n)
       : TGraph(n)
{
//*-*-*-*-*-*-*-*-*-*-*TGraphBentErrors normal constructor*-*-*-*-*-*-*-*-*-*-*
//*-*                  ====================================
//
//  the arrays are preset to zero

   if (n <= 0) {
      Error("TGraphBentErrors", "illegal number of points (%d)", n);
      return;
   }

   fEXlow       = new Double_t[n];
   fEYlow       = new Double_t[n];
   fEXhigh      = new Double_t[n];
   fEYhigh      = new Double_t[n];

   fEXlowd       = new Double_t[n];
   fEYlowd       = new Double_t[n];
   fEXhighd      = new Double_t[n];
   fEYhighd      = new Double_t[n];

   for (Int_t i=0;i<n;i++) {
      fEXlow[i]  = 0;
      fEXhigh[i] = 0;
      fEYlow[i]  = 0;
      fEYhigh[i] = 0;

      fEXlowd[i]  = 0;
      fEXhighd[i] = 0;
      fEYlowd[i]  = 0;
      fEYhighd[i] = 0;
   }
}


//_____________________________________________________________________________
TGraphBentErrors::TGraphBentErrors(Int_t n,
				   const Float_t *x, const Float_t *y,
				   const Float_t *exl, const Float_t *exh,
				   const Float_t *eyl, const Float_t *eyh,
				   const Float_t *exld, const Float_t *exhd,
				   const Float_t *eyld, const Float_t *eyhd)
  : TGraph(n,x,y)
{
//*-*-*-*-*-*-*-*-*-*-*TGraphBentErrors normal constructor*-*-*-*-*-*-*-*-*-*-*
//*-*                  ====================================
//
//  if exl,h or eyl,h are null, the corresponding arrays are preset to zero

   if (n <= 0) {
      Error("TGraphBentErrors", "illegal number of points (%d)", n);
      return;
   }

   fEXlow       = new Double_t[n];
   fEYlow       = new Double_t[n];
   fEXhigh      = new Double_t[n];
   fEYhigh      = new Double_t[n];

   fEXlowd       = new Double_t[n];
   fEYlowd       = new Double_t[n];
   fEXhighd      = new Double_t[n];
   fEYhighd      = new Double_t[n];

   for (Int_t i=0;i<n;i++) {
      if (exl) fEXlow[i]  = exl[i];
      else     fEXlow[i]  = 0;
      if (exh) fEXhigh[i] = exh[i];
      else     fEXhigh[i] = 0;
      if (eyl) fEYlow[i]  = eyl[i];
      else     fEYlow[i]  = 0;
      if (eyh) fEYhigh[i] = eyh[i];
      else     fEYhigh[i] = 0;

      if (exld) fEXlowd[i]  = exld[i];
      else     fEXlowd[i]  = 0;
      if (exhd) fEXhighd[i] = exhd[i];
      else     fEXhighd[i] = 0;
      if (eyld) fEYlowd[i]  = eyld[i];
      else     fEYlowd[i]  = 0;
      if (eyhd) fEYhighd[i] = eyhd[i];
      else     fEYhighd[i] = 0;
   }
}

//_____________________________________________________________________________
TGraphBentErrors::TGraphBentErrors(Int_t n,
				   const Double_t *x, const Double_t *y,
				   const Double_t *exl, const Double_t *exh,
				   const Double_t *eyl, const Double_t *eyh,
				   const Double_t *exld, const Double_t *exhd,
				   const Double_t *eyld, const Double_t *eyhd)
  : TGraph(n,x,y)
{
//*-*-*-*-*-*-*-*-*-*-*TGraphBentErrors normal constructor*-*-*-*-*-*-*-*-*-*-*
//*-*                  ====================================
//
//  if exl,h or eyl,h are null, the corresponding arrays are preset to zero

   if (n <= 0) {
      Error("TGraphBentErrors", "illegal number of points (%d)", n);
      return;
   }

   fEXlow       = new Double_t[n];
   fEYlow       = new Double_t[n];
   fEXhigh      = new Double_t[n];
   fEYhigh      = new Double_t[n];

   fEXlowd       = new Double_t[n];
   fEYlowd       = new Double_t[n];
   fEXhighd      = new Double_t[n];
   fEYhighd      = new Double_t[n];

   for (Int_t i=0;i<n;i++) {
      if (exl) fEXlow[i]  = exl[i];
      else     fEXlow[i]  = 0;
      if (exh) fEXhigh[i] = exh[i];
      else     fEXhigh[i] = 0;
      if (eyl) fEYlow[i]  = eyl[i];
      else     fEYlow[i]  = 0;
      if (eyh) fEYhigh[i] = eyh[i];
      else     fEYhigh[i] = 0;

      if (exld) fEXlowd[i]  = exld[i];
      else     fEXlowd[i]  = 0;
      if (exhd) fEXhighd[i] = exhd[i];
      else     fEXhighd[i] = 0;
      if (eyld) fEYlowd[i]  = eyld[i];
      else     fEYlowd[i]  = 0;
      if (eyhd) fEYhighd[i] = eyhd[i];
      else     fEYhighd[i] = 0;
   }
}

//_____________________________________________________________________________
TGraphBentErrors::~TGraphBentErrors()
{
//*-*-*-*-*-*-*-*-*-*-*TGraphBentErrors default destructor*-*-*-*-*-*-*-*-*-*-*
//*-*                  ===============================

   delete [] fEXlow;
   delete [] fEXhigh;
   delete [] fEYlow;
   delete [] fEYhigh;

   delete [] fEXlowd;
   delete [] fEXhighd;
   delete [] fEYlowd;
   delete [] fEYhighd;
}

//_____________________________________________________________________________
void TGraphBentErrors::Apply(TF1 *f)
{
  // apply a function to all data points
  // y = f(x,y)
  //
  // Errors are calculated as eyh = f(x,y+eyh)-f(x,y) and
  // eyl = f(x,y)-f(x,y-eyl)
  //
  // Special treatment has to be applied for the functions where the
  // role of "up" and "down" is reversed.
  // function suggested/implemented by Miroslav Helbich <helbich@mail.desy.de>

  Double_t x,y,exl,exh,eyl,eyh,eyl_new,eyh_new,fxy;

  for (Int_t i=0;i<GetN();i++) {
     GetPoint(i,x,y);
     exl=GetEXlow()[i];
     exh=GetEXhigh()[i];
     eyl=GetEYlow()[i];
     eyh=GetEYhigh()[i];

     fxy = f->Eval(x,y);
     SetPoint(i,x,fxy);

     // in the case of the functions like y-> -1*y the roles of the
     // upper and lower error bars is reversed
     if (f->Eval(x,y-eyl)<f->Eval(x,y+eyh)) {
        eyl_new = TMath::Abs(fxy - f->Eval(x,y-eyl));
        eyh_new = TMath::Abs(f->Eval(x,y+eyh) - fxy);
     }
     else {
        eyh_new = TMath::Abs(fxy - f->Eval(x,y-eyl));
        eyl_new = TMath::Abs(f->Eval(x,y+eyh) - fxy);
     }

     //error on x doesn't change
     SetPointError(i,exl,exh,eyl_new,eyh_new);
   }
}

//_____________________________________________________________________________
void TGraphBentErrors::ComputeRange(Double_t &xmin, Double_t &ymin, Double_t &xmax, Double_t &ymax) const
{
  for (Int_t i=0;i<fNpoints;i++) {
     if (fX[i] -fEXlow[i] < xmin) {
        if (gPad && gPad->GetLogx()) {
           if (fEXlow[i] < fX[i]) xmin = fX[i]-fEXlow[i];
           else                   xmin = fX[i]/3;
        } else {
          xmin = fX[i]-fEXlow[i];
        }
     }
     if (fX[i] +fEXhigh[i] > xmax) xmax = fX[i]+fEXhigh[i];
     if (fY[i] -fEYlow[i] < ymin) {
        if (gPad && gPad->GetLogy()) {
           if (fEYlow[i] < fY[i]) ymin = fY[i]-fEYlow[i];
           else                   ymin = fY[i]/3;
        } else {
          ymin = fY[i]-fEYlow[i];
        }
     }
     if (fY[i] +fEYhigh[i] > ymax) ymax = fY[i]+fEYhigh[i];
  }
}

//_____________________________________________________________________________
Double_t TGraphBentErrors::GetErrorX(Int_t i) const
{
//    This function is called by GraphFitChisquare.
//    It returns the error along X at point i.

   if (i < 0 || i >= fNpoints) return -1;
   if (!fEXlow && !fEXhigh) return -1;
   Double_t elow=0, ehigh=0;
   if (fEXlow)  elow  = fEXlow[i];
   if (fEXhigh) ehigh = fEXhigh[i];
   return TMath::Sqrt(0.5*(elow*elow + ehigh*ehigh));
}

//_____________________________________________________________________________
Double_t TGraphBentErrors::GetErrorY(Int_t i) const
{
//    This function is called by GraphFitChisquare.
//    It returns the error along Y at point i.

   if (i < 0 || i >= fNpoints) return -1;
   if (!fEYlow && !fEYhigh) return -1;
   Double_t elow=0, ehigh=0;
   if (fEYlow)  elow  = fEYlow[i];
   if (fEYhigh) ehigh = fEYhigh[i];
   return TMath::Sqrt(0.5*(elow*elow + ehigh*ehigh));
}

//_____________________________________________________________________________
Int_t TGraphBentErrors::InsertPoint()
{
// Insert a new point at the mouse position

   Int_t ipoint = TGraph::InsertPoint();

   Double_t *newEXlow  = new Double_t[fNpoints];
   Double_t *newEYlow  = new Double_t[fNpoints];
   Double_t *newEXhigh = new Double_t[fNpoints];
   Double_t *newEYhigh = new Double_t[fNpoints];

   Double_t *newEXlowd  = new Double_t[fNpoints];
   Double_t *newEYlowd  = new Double_t[fNpoints];
   Double_t *newEXhighd = new Double_t[fNpoints];
   Double_t *newEYhighd = new Double_t[fNpoints];

   Int_t i;
   for (i=0;i<ipoint;i++) {
      newEXlow[i]  = fEXlow[i];
      newEYlow[i]  = fEYlow[i];
      newEXhigh[i] = fEXhigh[i];
      newEYhigh[i] = fEYhigh[i];

      newEXlowd[i]  = fEXlowd[i];
      newEYlowd[i]  = fEYlowd[i];
      newEXhighd[i] = fEXhighd[i];
      newEYhighd[i] = fEYhighd[i];
  }
   newEXlow[ipoint]  = 0;
   newEYlow[ipoint]  = 0;
   newEXhigh[ipoint] = 0;
   newEYhigh[ipoint] = 0;

   newEXlowd[ipoint]  = 0;
   newEYlowd[ipoint]  = 0;
   newEXhighd[ipoint] = 0;
   newEYhighd[ipoint] = 0;

   for (i=ipoint+1;i<fNpoints;i++) {
      newEXlow[i]  = fEXlow[i-1];
      newEYlow[i]  = fEYlow[i-1];
      newEXhigh[i] = fEXhigh[i-1];
      newEYhigh[i] = fEYhigh[i-1];

      newEXlowd[i]  = fEXlowd[i-1];
      newEYlowd[i]  = fEYlowd[i-1];
      newEXhighd[i] = fEXhighd[i-1];
      newEYhighd[i] = fEYhighd[i-1];
   }
   delete [] fEXlow;
   delete [] fEYlow;
   delete [] fEXhigh;
   delete [] fEYhigh;

   delete [] fEXlowd;
   delete [] fEYlowd;
   delete [] fEXhighd;
   delete [] fEYhighd;

   fEXlow  = newEXlow;
   fEYlow  = newEYlow;
   fEXhigh = newEXhigh;
   fEYhigh = newEYhigh;

   fEXlowd  = newEXlowd;
   fEYlowd  = newEYlowd;
   fEXhighd = newEXhighd;
   fEYhighd = newEYhighd;

   return ipoint;
}

//_____________________________________________________________________________
void TGraphBentErrors::Paint(Option_t *option)
{
   // Paint this TGraphBentErrors with its current attributes
   //
   // by default horizonthal and vertical small lines are drawn at
   // the end of the error bars. if option "z" or "Z" is specified,
   // these lines are not drawn.
   //
   // if option contains ">" an arrow is drawn at the end of the error bars
   // if option contains "|>" a full arrow is drawn at the end of the error bars
   // the size of the arrow is set to 2/3 of the marker size.
   //
   // By default, error bars are drawn. If option "X" is specified,
   // the errors are not drawn (TGraph::Paint equivalent).
   //
   // if option "[]" is specified only the end vertical/horizonthal lines
   // of the error bars are drawn. This option is interesting to superimpose
   // systematic errors on top of a graph with statistical errors.

   const Int_t BASEMARKER=8;
   Double_t s2x, s2y, symbolsize, sbase;
   Double_t x, y, xl1, xl2, xr1, xr2, yup1, yup2, ylow1, ylow2, tx, ty;
   Double_t bxl, bxh, byl, byh;
   static Float_t cxx[11] = {1,1,0.6,0.6,1,1,0.6,0.5,1,0.6,0.6};
   static Float_t cyy[11] = {1,1,1,1,1,1,1,1,1,0.5,0.6};

   if (strchr(option,'X') || strchr(option,'x')) {TGraph::Paint(option); return;}
   Bool_t brackets = kFALSE;
   if (strstr(option,"[]")) brackets = kTRUE;
   Bool_t endLines = kTRUE;
   if (strchr(option,'z')) endLines = kFALSE;
   if (strchr(option,'Z')) endLines = kFALSE;
   const char *arrowOpt = 0;
   if (strchr(option,'>'))  arrowOpt = ">";
   if (strstr(option,"|>")) arrowOpt = "|>";

   Bool_t axis = kFALSE;
   if (strchr(option,'a')) axis = kTRUE;
   if (strchr(option,'A')) axis = kTRUE;
   if (axis) TGraph::Paint(option);

   TAttLine::Modify();

   TArrow arrow;
   arrow.SetLineWidth(GetLineWidth());
   arrow.SetLineColor(GetLineColor());
   arrow.SetFillColor(GetFillColor());

   symbolsize  = GetMarkerSize();
   sbase       = symbolsize*BASEMARKER;
   Int_t mark  = GetMarkerStyle();
   Double_t cx  = 0;
   Double_t cy  = 0;
   if (mark >= 20 && mark < 31) {
      cx = cxx[mark-20];
      cy = cyy[mark-20];
   }

//*-*-      define the offset of the error bars due to the symbol size
   s2x  = gPad->PixeltoX(Int_t(0.5*sbase)) - gPad->PixeltoX(0);
   s2y  =-gPad->PixeltoY(Int_t(0.5*sbase)) + gPad->PixeltoY(0);
   tx   = 0.50*s2x;
   ty   = 0.50*s2y;
   Float_t asize = 0.6*symbolsize*BASEMARKER/gPad->GetWh();

   gPad->SetBit(kClipFrame, TestBit(kClipFrame));
   for (Int_t i=0;i<fNpoints;i++) {
      x  = gPad->XtoPad(fX[i]);
      y  = gPad->YtoPad(fY[i]);
      bxl = gPad->YtoPad(fY[i]+fEXlowd[i]);
      bxh = gPad->YtoPad(fY[i]+fEXhighd[i]);
      byl = gPad->XtoPad(fX[i]+fEYlowd[i]);
      byh = gPad->XtoPad(fX[i]+fEYhighd[i]);
      if (x < gPad->GetUxmin()) continue;
      if (x > gPad->GetUxmax()) continue;
      if (y < gPad->GetUymin()) continue;
      if (y > gPad->GetUymax()) continue;
      xl1 = x - s2x*cx;
      xl2 = gPad->XtoPad(fX[i] - fEXlow[i]);
      if (xl1 > xl2) {
         if (arrowOpt) {
            arrow.PaintArrow(xl1,y,xl2,bxl,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(xl1,y,xl2,bxl);
            if (endLines)  gPad->PaintLine(xl2,bxl-ty,xl2,bxl+ty);
         }
      }
      xr1 = x + s2x*cx;
      xr2 = gPad->XtoPad(fX[i] + fEXhigh[i]);
      if (xr1 < xr2) {
         if (arrowOpt) {
            arrow.PaintArrow(xr1,y,xr2,bxh,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(xr1,y,xr2,bxh);
            if (endLines)  gPad->PaintLine(xr2,bxh-ty,xr2,bxh+ty);
         }
      }
      yup1 = y + s2y*cy;
      yup2 = gPad->YtoPad(fY[i] + fEYhigh[i]);
      if (yup2 > gPad->GetUymax()) yup2 =  gPad->GetUymax();
      if (yup2 > yup1) {
         if (arrowOpt) {
            arrow.PaintArrow(x,yup1,byh,yup2,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(x,yup1,byh,yup2);
            if (endLines)  gPad->PaintLine(byh-tx,yup2,byh+tx,yup2);
         }
      }
      ylow1 = y - s2y*cy;
      ylow2 = gPad->YtoPad(fY[i] - fEYlow[i]);
      if (ylow2 < gPad->GetUymin()) ylow2 =  gPad->GetUymin();
      if (ylow2 < ylow1) {
         if (arrowOpt) {
            arrow.PaintArrow(x,ylow1,byl,ylow2,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(x,ylow1,byl,ylow2);
            if (endLines)  gPad->PaintLine(byl-tx,ylow2,byl+tx,ylow2);
         }
      }
   }
   if (!brackets && !axis) TGraph::Paint(option);
   gPad->ResetBit(kClipFrame);
}


//______________________________________________________________________________
void TGraphBentErrors::Print(Option_t *) const
{
//*-*-*-*-*-*-*-*-*-*-*Print graph and errors values*-*-*-*-*-*-*-*-*-*-*-*
//*-*                  =============================
//

   for (Int_t i=0;i<fNpoints;i++) {
      printf("x[%d]=%g, y[%d]=%g, exl[%d]=%g, exh[%d]=%g, eyl[%d]=%g, eyh[%d]=%g\n"
         ,i,fX[i],i,fY[i],i,fEXlow[i],i,fEXhigh[i],i,fEYlow[i],i,fEYhigh[i]);
   }
}

//______________________________________________________________________________
Int_t TGraphBentErrors::RemovePoint()
{
// Delete point close to the mouse position

   Int_t ipoint = TGraph::RemovePoint();
   if (ipoint < 0) return ipoint;

   Double_t *newEXlow  = new Double_t[fNpoints];
   Double_t *newEYlow  = new Double_t[fNpoints];
   Double_t *newEXhigh = new Double_t[fNpoints];
   Double_t *newEYhigh = new Double_t[fNpoints];
   Int_t i, j = -1;
   for (i=0;i<fNpoints+1;i++) {
      if (i == ipoint) continue;
      j++;
      newEXlow[j]  = fEXlow[i];
      newEYlow[j]  = fEYlow[i];
      newEXhigh[j] = fEXhigh[i];
      newEYhigh[j] = fEYhigh[i];
   }
   delete [] fEXlow;
   delete [] fEYlow;
   delete [] fEXhigh;
   delete [] fEYhigh;
   fEXlow  = newEXlow;
   fEYlow  = newEYlow;
   fEXhigh = newEXhigh;
   fEYhigh = newEYhigh;
   return ipoint;
}

//______________________________________________________________________________
Int_t TGraphBentErrors::RemovePoint(Int_t ipnt)
{
// Delete point number ipnt

   Int_t ipoint = TGraph::RemovePoint(ipnt);
   if (ipoint < 0) return ipoint;

   Double_t *newEXlow  = new Double_t[fNpoints];
   Double_t *newEYlow  = new Double_t[fNpoints];
   Double_t *newEXhigh = new Double_t[fNpoints];
   Double_t *newEYhigh = new Double_t[fNpoints];
   Int_t i, j = -1;
   for (i=0;i<fNpoints+1;i++) {
      if (i == ipoint) continue;
      j++;
      newEXlow[j]  = fEXlow[i];
      newEYlow[j]  = fEYlow[i];
      newEXhigh[j] = fEXhigh[i];
      newEYhigh[j] = fEYhigh[i];
   }
   delete [] fEXlow;
   delete [] fEYlow;
   delete [] fEXhigh;
   delete [] fEYhigh;
   fEXlow  = newEXlow;
   fEYlow  = newEYlow;
   fEXhigh = newEXhigh;
   fEYhigh = newEYhigh;
   return ipoint;
}

//______________________________________________________________________________
void TGraphBentErrors::SavePrimitive(ofstream &out, Option_t *option)
{
    // Save primitive as a C++ statement(s) on output stream out

   char quote = '"';
   out<<"   "<<endl;
   if (gROOT->ClassSaved(TGraphBentErrors::Class())) {
       out<<"   ";
   } else {
       out<<"   TGraphBentErrors *";
   }
   out<<"grae = new TGraphBentErrors("<<fNpoints<<");"<<endl;
   out<<"   grae->SetName("<<quote<<GetName()<<quote<<");"<<endl;
   out<<"   grae->SetTitle("<<quote<<GetTitle()<<quote<<");"<<endl;

   SaveFillAttributes(out,"grae",0,1001);
   SaveLineAttributes(out,"grae",1,1,1);
   SaveMarkerAttributes(out,"grae",1,1,1);

   for (Int_t i=0;i<fNpoints;i++) {
      out<<"   grae->SetPoint("<<i<<","<<fX[i]<<","<<fY[i]<<");"<<endl;
      out<<"   grae->SetPointError("<<i<<","<<fEXlow[i]<<","<<fEXhigh[i]<<","<<fEYlow[i]<<","<<fEYhigh[i]<<");"<<endl;
   }

   static Int_t frameNumber = 0;
   if (fHistogram) {
      frameNumber++;
      TString hname = fHistogram->GetName();
      hname += frameNumber;
      fHistogram->SetName(hname.Data());
      fHistogram->SavePrimitive(out,"nodraw");
      out<<"   grae->SetHistogram("<<fHistogram->GetName()<<");"<<endl;
      out<<"   "<<endl;
   }

   // save list of functions
   TIter next(fFunctions);
   TObject *obj;
   while ((obj=next())) {
      obj->SavePrimitive(out,"nodraw");
      out<<"   grae->GetListOfFunctions()->Add("<<obj->GetName()<<");"<<endl;
      if (obj->InheritsFrom("TPaveStats")) {
         out<<"   ptstats->SetParent(grae->GetListOfFunctions());"<<endl;
      }
   }

   if (strstr(option,"multigraph")) {
      out<<"   multigraph->Add(grae);"<<endl;
      return;
   }
   out<<"   grae->Draw("
      <<quote<<option<<quote<<");"<<endl;
}

//______________________________________________________________________________
void TGraphBentErrors::Set(Int_t n)
{
// Set number of points in the graph
// Existing coordinates are preserved
// New coordinates and errors above fNpoints are preset to 0.
  if (n < 0) n = 0;
  if (n == fNpoints) return;

  TGraph::Set(n);

  Double_t *exh=0, *exl=0, *eyh=0, *eyl=0;
  if (n > 0) {
          exh = new Double_t[n];
          exl = new Double_t[n];
          eyh = new Double_t[n];
          eyl = new Double_t[n];
  }
  Int_t i;
  for (i=0; i<fNpoints && i<n;i++) {
     if (fEXlow)  exl[i] = fEXlow[i];
     if (fEXhigh) exh[i] = fEXhigh[i];
     if (fEYlow)  eyl[i] = fEYlow[i];
     if (fEYhigh) eyh[i] = fEYhigh[i];
  }
  for (i=fNpoints; i<n;i++) {
     exh[i] = 0;
     exl[i] = 0;
     eyh[i] = 0;
     eyl[i] = 0;
  }
  delete [] fEXlow;
  delete [] fEXhigh;
  delete [] fEYlow;
  delete [] fEYhigh;

  fEXhigh = exh;
  fEXlow  = exl;
  fEYhigh = eyh;
  fEYlow  = eyl;
}

//______________________________________________________________________________
void TGraphBentErrors::SetPoint(Int_t i, Double_t x, Double_t y)
{
//*-*-*-*-*-*-*-*-*-*-*Set x and y values for point number i*-*-*-*-*-*-*-*-*
//*-*                  =====================================

   if (i < 0) return;
   if (i >= fNpoints) {
   // re-allocate the object
      Double_t *savex   = new Double_t[i+1];
      Double_t *savey   = new Double_t[i+1];
      Double_t *saveexl = new Double_t[i+1];
      Double_t *saveeyl = new Double_t[i+1];
      Double_t *saveexh = new Double_t[i+1];
      Double_t *saveeyh = new Double_t[i+1];
      if (fNpoints > 0) {
         memcpy(savex,  fX,     fNpoints*sizeof(Double_t));
         memcpy(savey,  fY,     fNpoints*sizeof(Double_t));
         memcpy(saveexl,fEXlow, fNpoints*sizeof(Double_t));
         memcpy(saveeyl,fEYlow, fNpoints*sizeof(Double_t));
         memcpy(saveexh,fEXhigh,fNpoints*sizeof(Double_t));
         memcpy(saveeyh,fEYhigh,fNpoints*sizeof(Double_t));
      }
      if (fX)      delete [] fX;
      if (fY)      delete [] fY;
      if (fEXlow)  delete [] fEXlow;
      if (fEYlow)  delete [] fEYlow;
      if (fEXhigh) delete [] fEXhigh;
      if (fEYhigh) delete [] fEYhigh;
      fX  = savex;
      fY  = savey;
      fEXlow  = saveexl;
      fEYlow  = saveeyl;
      fEXhigh = saveexh;
      fEYhigh = saveeyh;
      fNpoints = i+1;
   }
   fX[i] = x;
   fY[i] = y;
   if (fHistogram) {
      delete fHistogram;
      fHistogram = 0;
   }
}

//______________________________________________________________________________
void TGraphBentErrors::SetPointError(Double_t exl, Double_t exh, Double_t eyl, Double_t eyh)
{
//*-*-*-*-*-*-*Set ex and ey values for point pointed by the mouse*-*-*-*
//*-*          ===================================================

   Int_t px = gPad->GetEventX();
   Int_t py = gPad->GetEventY();

   //localize point to be deleted
   Int_t ipoint = -2;
   Int_t i;
   // start with a small window (in case the mouse is very close to one point)
   for (i=0;i<fNpoints;i++) {
      Int_t dpx = px - gPad->XtoAbsPixel(gPad->XtoPad(fX[i]));
      Int_t dpy = py - gPad->YtoAbsPixel(gPad->YtoPad(fY[i]));
      if (dpx*dpx+dpy*dpy < 25) {ipoint = i; break;}
   }
   if (ipoint == -2) return;

   fEXlow[ipoint]  = exl;
   fEYlow[ipoint]  = eyl;
   fEXhigh[ipoint] = exh;
   fEYhigh[ipoint] = eyh;
   gPad->Modified();
}

//______________________________________________________________________________
void TGraphBentErrors::SetPointError(Int_t i, Double_t exl, Double_t exh, Double_t eyl, Double_t eyh)
{
//*-*-*-*-*-*-*-*-*-*-*Set ex and ey values for point number i*-*-*-*-*-*-*-*
//*-*                  =======================================

   if (i < 0) return;
   if (i >= fNpoints) {
   // re-allocate the object
      TGraphBentErrors::SetPoint(i,0,0);
   }
   fEXlow[i]  = exl;
   fEYlow[i]  = eyl;
   fEXhigh[i] = exh;
   fEYhigh[i] = eyh;
}

//_____________________________________________________________________________
void TGraphBentErrors::SwapPoints(Int_t pos1, Int_t pos2)
{
  SwapValues(fEXlow,  pos1, pos2);
  SwapValues(fEXhigh, pos1, pos2);
  SwapValues(fEYlow,  pos1, pos2);
  SwapValues(fEYhigh, pos1, pos2);

  SwapValues(fEXlowd,  pos1, pos2);
  SwapValues(fEXhighd, pos1, pos2);
  SwapValues(fEYlowd,  pos1, pos2);
  SwapValues(fEYhighd, pos1, pos2);

  TGraph::SwapPoints(pos1, pos2);
}
