// Classe Look-Up-Table  pour convertir image en entree ds
// une table de couleur.
//       Classe LUT              R. Ansari  05/95
// LAL (Orsay) / IN2P3-CNRS  DAPNIA/SPP (Saclay) / CEA

#include "sopnamsp.h"
#include "machdefs.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#include "lut.h"

//++
// Class	LUT
// Lib		PI
// include	lut.h
//
//	Classe Look-Up table : transformation de valeurs (intensite/RGB) en index de couleur
//--
//++
// Links	Voir aussi
// PIColorMap
// PIPixmap
// PIImage
//--
/* --Methode-- */

LUT::LUT(double min, double max, unsigned short ncol, int typ) 
{
int nlev = ncol-2;
if (nlev < 1)  nlev = 1;
bornes = new double[nlev+1];

if (bornes == NULL)  return;
type = typ;  nLevel = nlev;
int qqq = 1;
quantum = 1;
for(quantum=2; quantum<=42; quantum++) {
  qqq = quantum*quantum*quantum;
  if (qqq > NCol())  break;
}
quantum--;

table = NULL;  
tablenbin = 0;
SetLut(min, max, typ);
return;
}

/* --Methode-- */
LUT::~LUT()
{
if (type<0)  return;
delete[] bornes;
delete[] table;
}
/* --Methode-- */
void LUT::SetNCol(unsigned short ncol)
{
if (ncol == NCol())  return;
double min = Min();
double max = Max();
if (bornes) delete[] bornes;
int nlev = ncol-2;
if (nlev < 1)  nlev = 1;
bornes = new double[nlev+1];
nLevel = nlev;
int qqq = 1;
quantum = 1;
for(quantum=2; quantum<=42; quantum++) {
  qqq = quantum*quantum*quantum;
  if (qqq > NCol())  break;
}
quantum--;
// printf("*DBG*LUT* quantum= %d \n", (int)quantum);
SetLut(min, max, Type());
}

/* --Methode-- */
void LUT::SetLut(double min, double max, int typ)
{

if(  (typ != kLutType_Lin)  && (typ != kLutType_Log)
  && (typ != kLutType_Sqrt) && (typ != kLutType_Square)  
  && (typ != kLutType_RGB) )  typ = kLutType_Lin;
type = typ;
if (max <= min)  max = min+1.;
mMin = min;  mMax = max;
mMinI = (int)(min+0.1);  mMaxI = (int)(max+0.1);
if (nLevel > 0)
  {
  int i;
  double dx, dlx, fmx;
  switch (typ)
    {
    case kLutType_Lin :
    case kLutType_RGB :
      dx = (max-min)/(double)nLevel;
      for(i=0; i<nLevel; i++)
        bornes[i] = min+(double)i*dx;
      break;
    case kLutType_Log :
      fmx = (max-min)/(exp(1.)-1.);
      dlx = 1./(double)nLevel;
      for(i=0; i<nLevel; i++)
        bornes[i] = min+((double)exp((double)i*dlx)-1.)*fmx;
      break;
    case kLutType_Exp :
      dlx = (exp(1.)-1.)/(double)nLevel;
      for(i=0; i<nLevel; i++)
        bornes[i] = min+(double)log(1.+(double)i*dlx)*(max-min);
      break;
    case kLutType_Sqrt :
      dlx = sqrt(max-min) / (double)nLevel;
      for(i=0; i<nLevel; i++)
        bornes[i] = min+((double)i*dlx)*((double)i*dlx);
      break;
    case kLutType_Square :
      dlx = (max-min)*(max-min) / (double)nLevel;
      for(i=0; i<nLevel; i++)
        bornes[i] = min+(double)sqrt((double)i*dlx);
      break;
    default:
      for(i=0; i<nLevel; i++)
        bornes[i] = min;
      break;
    }
  bornes[nLevel] = max; 
  }
else  bornes[0] = 0.5*(min+max);
// ComputeTable((ntable > nLevel) ? ntable : tablenbin);
if (type != kLutType_RGB) ComputeTable(0);
return; 
}

/* --Methode-- */
void LUT::Print()
{
int i;

printf("LUT_Info: Type= %d NLevel= %d Min,Max= %g %g \n",
       type, nLevel, bornes[0], bornes[nLevel]);
for(i=0; i<=nLevel; i++)
  printf("..Bornes[%d] = %g \n", i, bornes[i]);
return;
}

/* --Methode-- */
unsigned short LUT::ApplyI(double x)
{
int i;
for(i=0;i<=nLevel;i++)  
  if (x < bornes[i])  return(i);
return(nLevel+1);
}

/* --Methode-- */
unsigned short LUT::ApplyRGB(double x)
{
  long lv = x+0.3;
  int r = (lv%256);
  lv /= 256;
  int g = (lv%256);
  lv /= 256;
  int b = (lv%256);
  return (unsigned short)((Contraste(b)*quantum+Contraste(g))*quantum+Contraste(r));
}

/* --Methode-- */
void LUT::ComputeTable(int nt)
{
if (nt <= 0) { 
  int fm = 16;
  if ((nLevel+2)>4096) fm = 1;
  else if ((nLevel+2)>2048) fm = 2;
  else if ((nLevel+2)>1024) fm = 4;
  else if ((nLevel+2)>512) fm = 8;
  nt = fm*(nLevel+2);
}
else if (nt < (nLevel+2))  nt = (nLevel+2);
tablenbin = nt;
if (table) delete[] table;
table = new unsigned short [nt-2];
tablebinwidth = (Max()-Min())/(nt-2);
double x = Min()+0.5*tablebinwidth;
for(int i=0; i<nt-2; i++)  { table[i] = ApplyI(x); x += tablebinwidth; }
}
