// Peida Interactive   -   PI            R. Ansari 97-99
// Traceur3D (Drawer) pour NTupleInterface  
// LAL (Orsay) / IN2P3-CNRS  DAPNIA/SPP (Saclay) / CEA

#include <stdio.h>
#include "pintup3d.h"

//++
// Class	PINTuple3D
// Lib		PIext
// include	pintup3d.h
//
//	Classe de traceur 3D à partir des données
//	d'un objet implémentant l'interface *NTupleInterface*.
//	Les objets "PINTuple3D" peuvent tracer des signes (markers)
//	éventuellement avec des barres d'erreur et une étiquette
//	pour chaque point. Si un attribut de ligne, autre que
//	"PI_NotDefLineAtt" est spécifié, les points sont connectés
//	par une ligne.
//--
//++
// Links	Parents
// PIDrawer3D
//--
//++
// Links	Voir aussi
// NTupleInterface
// PINTuple
//--

//++
// Titre	Constructeur
//--
//++
// PINTuple3D(NTupleInterface* nt, bool ad=false)
//	Constructeur. Si "ad == true", l'objet "nt" est détruit par 
//	le destructeur de l'objet "PINTuple".
//	Note : nt doit être créé par new
//--

 
/* --Methode-- */
PINTuple3D::PINTuple3D(NTupleInterface* nt, bool ad)
: PIDrawer3D()
{
  mNT = nt;
  mAdDO = ad; 
  SelectXYZ(NULL, NULL, NULL);
  SelectWt(NULL, 1);
  SelectErrBar();
  SelectLabel(NULL);
}

PINTuple3D::~PINTuple3D()
{
  if (mAdDO && mNT)  delete mNT;
}

//++
// Titre	Méthodes
//--
//++
// void  SelectXYZ(const char* px, const char* py, const char* pz)
//	Choix des noms de colonnes X,Y,Z définissant les coordonnées des points. 
//	Ces trois colonnes doivent être spécifiées pour obtenir un tracé.
// void  SelectErrBar(const char* erbx=NULL, const char* erby=NULL, const char* erbz=NULL)
//	Choix des noms de colonnes pour le tracé des barres d'erreur.
// void  SelectWt(const char* pw=NULL, int nbins=10)
//	Choix du nom de colonne poids. Dans ce cas, la taille du signe
//	(marker) sera proportionnel à la valeur de cette colonne pour 
//	chaque point.
// void  SelectLabel(const char* plabel)
//	Choix du nom de colonne correspondant à l'étiquette.
//--

/* --Methode-- */
void  PINTuple3D::SelectXYZ(const char* px, const char* py, const char* pz)
{
string name;
if (mNT == NULL)  xK = yK = zK = -1;
if (px == NULL) xK = -1;
else { name = px; xK = mNT->ColumnIndex(name); }
if (py == NULL) yK = -1;
else { name = py; yK = mNT->ColumnIndex(name); }
if (pz == NULL) zK = -1;
else { name = pz; zK = mNT->ColumnIndex(name); }
}

/* --Methode-- */
void  PINTuple3D::SelectWt(const char* pw, int nbins)
{
nWbins = (nbins > 0) ? nbins : 10;
if (pw == NULL) wK = -1;  
else { string name = pw;   wK = mNT->ColumnIndex(name);  }
 
if (wK >= 0) mNT->GetMinMax(wK, wMin, wMax);
else  { wMin = 0.; wMax = 1.; }
}

/* --Methode-- */
void  PINTuple3D::SelectLabel(const char* plabel)
{
if (plabel == NULL) lK = -1;
else {  string name = plabel;  lK = mNT->ColumnIndex(name);  }
}

/* --Methode-- */
void  PINTuple3D::SelectErrBar(const char* erbx, const char* erby, const char* erbz)
{
string name;
if (mNT == NULL)  xebK = yebK = zebK = -1;
if (erbx == NULL) xebK = -1;
else { name = erbx;  xebK = mNT->ColumnIndex(name); }
if (erby == NULL) yebK = -1;
else { name = erby;  yebK = mNT->ColumnIndex(name); }
if (erbz == NULL) zebK = -1;
else { name = erbz;  zebK = mNT->ColumnIndex(name); }
}


/* --Methode-- */
void PINTuple3D::UpdateLimits()
{
  if (!mNT) return; 
  if (mNT->NbLines() <= 0)  return;
  if ( (xK < 0) || (yK < 0)  || (zK < 0) )   return;

  // Commencer par trouver nos limites
  double xmin, xmax, ymin, ymax, zmin, zmax;
  xmin = ymin = 9.e19;
  xmax = ymax = -9.e19;
  zmax = zmax = -9.e19;
  mNT->GetMinMax(xK, xmin, xmax);
  mNT->GetMinMax(yK, ymin, ymax);
  mNT->GetMinMax(zK, zmin, zmax);

// Centre du champ en C = (xmin+xmax)/2., (ymin+ymax)/2  (zmin+zmax)*0.5
// Distance D = Max(xmax-xmin,ymin-ymax)*2
// Observateur en O = X+D, Yc+2*D 
  double D = xmax-xmin;
  if (D < (ymax-ymin))  D = ymax-ymin;
  D *= 1.4;
  
  Set3DView((xmin+xmax)/2., (ymin+ymax)/2, (zmin+zmax)/2., 
            (xmin+xmax)/2.+D , (ymin+ymax)/2.-2.5*D , zmin+(zmax-zmin)*0.85, 0.25, 0.25);  

  x3Min = xmin;  // - 0.05*(xmax-xmin);
  x3Max = xmax;  // + 0.05*(xmax-xmin);
  y3Min = ymin;  // - 0.05*(ymax-ymin);
  y3Max = ymax;  // + 0.05*(ymax-ymin);
  z3Min = zmin;  // - 0.05*(zmax-zmin);
  z3Max = zmax;  // + 0.05*(zmax-zmin);

//  printf("PINTuple3D::UpdateLimits() : %g .. %g  %g .. %g  %g .. %g (%g) \n", xmin,xmax,ymin,ymax,zmin,zmax,D);
//  printf("PINTuple3D::UpdateLimits() :  %g %g %g << %g %g %g \n", 
//         (xmin+xmax)/2., (ymin+ymax)/2, (zmin+zmax)*0.5, 
//         (xmin+xmax)/2.+D , (ymin+ymax)/2.+2.*D , zmin+(zmax-zmin)*0.1);
}


/* --Methode-- */
void PINTuple3D::Draw(PIGraphicUC* g, double xmin, double ymin, double xmax, double ymax)
{
double xp,yp,zp,wp,xer,yer,zer;
double xl,yl,zl;
int nok;

// On trace les axes - En attendant de faire mieux - Reza 8/12/98
if (axesFlags != kAxesNone)  DrawAxes(g);

if (!mNT) return;
if ( (xK < 0) || (yK < 0) || (zK < 0) )  return;

#if defined(CC_HAS_RTTI_SUPPORT)
PIGraphic3D* g3 = dynamic_cast<PIGraphic3D*>(g);
#else
PIGraphic3D* g3 = (PIGraphic3D*)(g);
#endif

if (mLAtt == PI_NotDefLineAtt)  g3->SelLine(PI_ThinLine);

//  Pour tracer des markers avec taille fonction de Wt (poids)
double dw = (wMax-wMin)/nWbins;
if (dw < 1.e-19) dw = 1.e19;
int msz,sz;

PIMarker mrk;
if (wK >= 0)  mrk = (mMrk != PI_NotDefMarker) ? mMrk : PI_CircleMarker;
else   mrk = (mMrk != PI_NotDefMarker) ? mMrk : PI_DotMarker;
msz = mMSz;
if (msz < 1) msz = 1;
g->SelMarker(msz, mrk);

nok = 0;  
xp = yp = zp = xl = yl = zl = 0;
for (int i=0; i<mNT->NbLines(); i++) {
  xl = xp;  yl = yp;  zl = zp;
  xp = mNT->GetCell(i, xK);
  yp = mNT->GetCell(i, yK);
  zp = mNT->GetCell(i, zK);
  if ( (i > 0) && (mLAtt != PI_NotDefLineAtt) )   // On relie les points ...
    g3->DrawLine3D(xl, yl, zl, xp, yp, zp);
  nok++;
  if ( xebK >= 0 ) {
    xer = mNT->GetCell(i, xebK);
    g3->DrawLine3D(xp-xer, yp, zp, xp+xer, yp, zp);
  }
  if ( yebK >= 0 ) {
    yer = mNT->GetCell(i, yebK);
    g3->DrawLine3D(xp, yp-yer, zp, xp, yp+yer, zp);
  }
  if ( zebK >= 0 ) {
    zer = mNT->GetCell(i, zebK);
    g3->DrawLine3D(xp, yp, zp-zer, xp, yp, zp+zer);
  }
  if (wK >= 0) { // Taille de marker en fonction du poids
    wp = mNT->GetCell(i, wK);
    sz = (int)((wp-wMin)/dw);
    if (sz < 0) sz = 0;
    if (sz > nWbins)  sz = nWbins;
    sz += msz;
    if (sz < 2)  g->SelMarker(sz, PI_DotMarker);
    else g->SelMarker(sz, mrk);
  }
  // Trace du marker
  if ((wK >= 0)||(lK < 0)||(mMrk != PI_NotDefMarker))  g3->DrawMarker3D(xp, yp, zp); 
  // Trace eventuel du label
  if (lK >= 0) g3->DrawString3D(xp, yp, zp, mNT->GetCelltoString(i, lK).c_str());
}

return;
}

