// -*- C++ -*-
#ifndef RISPECTRUM_H
#define RISPECTRUM_H
/* Copyright 1996 
 * Mon Jun 22 10:33:27 1998  Brian Edward Smits  (bes@phoenix.cs.utah.edu)
 * 
 * RiSpectrum.H
 * A piecewise-constant approximation to a spectral
 * curve.  The boundaries and number of steps is
 * controlled by CPP variables
 *
 * RI_SPECTRUM_MIN_LAMBDA
 * RI_SPECTRUM_MAX_LAMBDA
 * RI_SPECTRUM_N_LAMBDA* 
 *	
 * 
 * $Id: RiSpectrum.H,v 1.12 1999/10/01 18:22:10 bes Exp $ 
 * 
 */
#ifndef RICOMMON_H
#include <RiCommon.H>
#endif

#ifndef RIMATH_H
#include <RiMath.H>
#endif


#define RI_SPECTRUM_MIN_LAMBDA 380
#define RI_SPECTRUM_MAX_LAMBDA 720
#define RI_SPECTRUM_N_LAMBDA 10

class ostream;

/***************************************************************
CLASS
    RiSpectrum
     Representation of a spectrum with constant, non-overlapping
     box functions

DESCRIPTION
     Represents the spectrum as a set of constant basis functions.
     The value of a component of the spectrum represent the average
     value of the function over the basis function.  (ie integral of
     each of the basis functions is 1.0). This is important as it
     allows two RiSpectrum to be multiplied together and the result
     is a correct RiSpectrum (the averaging term for each bin is
     1.0, and the product of these terms is 1.0, simple multiplication
     would not be possible if the basis functions had a different
     integral).  
     

****************************************************************/

class RiSpectrum {
  public:
    // GROUP constructors
    ////				
    RiSpectrum();
    //// a spectrum with value v at all wavelengths				
    RiSpectrum(RiReal v);
    // GROUP simple access and parameter functions
    ////				
    static int 	GetNumComponents();
    ////				
    static RiReal GetMinLambda(); 
    ////				
    static RiReal GetMaxLambda(); 
    ////  Allow non uniform bin widths
    static RiReal GetBinWidth(int i); 
				////  Convert from rgb to spectrum "optimally"
    static RiSpectrum FromRGB(RiReal red, RiReal blue, RiReal green);
    ////				
    RiReal& operator[] (int i);      
    ////				
    RiReal operator[] (int i) const; 
    ////				
    RiReal GetValue( RiReal wavelength ) const;

    // GROUP: wavelength-related access and area functions
    ////				
    int GetIndexAtWavelength( RiReal lambda ) const;
    //// returns bin that includes lambda, and t is the 
    // position of lambda in the bin (between 0 and 1)
    void 	 GetIndexAtWavelength(RiReal lambda, int& i, RiReal& t) const;
    ////	L1 Norm of the RiSpectrum			
    RiReal GetArea() const;
    ////	L1 Norm of the restricted range
    RiReal GetArea(RiReal l1, RiReal l2) const;
    ////	
    RiReal GetMinValue() const;
    ////	LInf Norm (assuming RiSpectrum is positive, otherwise largest)			
    RiReal GetMaxValue() const;
    ////	Normalized L1 Norm			
    RiReal GetAvgValue() const;

    // GROUP: operators
    ////				
    const RiSpectrum &operator=( const RiSpectrum & ) ;
    ////				
    const RiSpectrum &operator-=( const RiSpectrum& ) ;
    ////				
    const RiSpectrum &operator+=( const RiSpectrum& ) ;
    ////				
    const RiSpectrum &operator*=( const RiSpectrum& ) ;
    ////				
    const RiSpectrum &operator/=( const RiSpectrum& ) ;
    ////				
    const RiSpectrum &operator*=( RiReal) ;
    ////				
    const RiSpectrum &operator/=( RiReal) ;
    ////				
    RiSpectrum operator-() const;
    ////				
    RiSpectrum operator+() const;
    ////				
    RiSpectrum operator+( const RiSpectrum& ) const;
    ////				
    RiSpectrum operator-( const RiSpectrum& ) const;
    ////				
    RiSpectrum operator*( const RiSpectrum& ) const;
    ////				
    RiSpectrum operator/( const RiSpectrum& ) const;
    ////				
    RiSpectrum operator*( RiReal d ) const;
    ////				
    RiSpectrum operator/( RiReal d ) const;
    ////				
    bool operator==( const RiSpectrum& ) const;
    ////				
    bool operator!=( const RiSpectrum& ) const;

  private:
    static RiReal GetBinWidth();
    
    RiReal data[RI_SPECTRUM_N_LAMBDA];

};

////  RiReal * RiSpectrum, for completeness				
inline RiSpectrum operator*( RiReal lhs,  const RiSpectrum& rhs)
{
    return rhs * lhs;
}

//// output operator (no formating other than space between elements)
ostream& operator<<(ostream&, const RiSpectrum&);


/**********************************************************
// Inlines
// 
// ********************************************************/

inline RiSpectrum::RiSpectrum() {
#ifdef NDEBUG
   for (int i = 0; i < RI_SPECTRUM_N_LAMBDA; i++)
      data[i] = RI_NAN;
#endif
}


inline RiSpectrum::RiSpectrum(RiReal v) {
   for (int i = 0; i < RI_SPECTRUM_N_LAMBDA; i++)
      data[i] = v;
}

inline int RiSpectrum::GetNumComponents() {
    return RI_SPECTRUM_N_LAMBDA;
}
   

inline RiReal& RiSpectrum::operator[] (int i) {
    assert( i >= 0 );
    assert( i < RI_SPECTRUM_N_LAMBDA );
    return data[i];
}


inline RiReal RiSpectrum::operator[] (int i) const {
    assert( i >= 0 );
    assert( i < RI_SPECTRUM_N_LAMBDA );
    return data[i];
}

inline RiSpectrum exp(const RiSpectrum &in)
{
    RiSpectrum out;
    for(int i = 0; i < RI_SPECTRUM_N_LAMBDA; i++)
      out[i] = exp(in[i]);
    return out;
}

#endif /* RISPECTRUM_H */

