//#####################################################################
// Copyright 2010.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
#include <Core/Interpolation/INTERPOLATED_COLOR_MAP.h>
#include <Core/Interpolation/INTERPOLATION_CURVE.h>
#include <Core/Read_Write/READ_WRITE.h>
#include <Core/Vectors/VECTOR.h>
namespace PhysBAM{
//#####################################################################
// Constructor
//#####################################################################
template<class T> INTERPOLATED_COLOR_MAP<T>::
INTERPOLATED_COLOR_MAP()
    :mn(0),mx(1),use_log(false)
{
}
//#####################################################################
// Constructor
//#####################################################################
template<class T> template<class U> INTERPOLATED_COLOR_MAP<T>::
INTERPOLATED_COLOR_MAP(const INTERPOLATED_COLOR_MAP<U>& icm)
    :mn(icm.mn),mx(icm.mx),use_log(icm.use_log),
    colors(icm.colors)
{
}
//#####################################################################
// Function Initialize_Colors
//#####################################################################
template<class T> void INTERPOLATED_COLOR_MAP<T>::
Initialize_Colors(T min_value,T max_value,bool log_scale,bool reverse,bool two_sets)
{
    colors.control_points.Remove_All();
    mn=min_value;
    mx=max_value;
    use_log=log_scale;
    if(use_log){
        mn=log(abs(mn));
        mx=log(abs(mx));}
    PHYSBAM_ASSERT(mn<=mx);
    if(mn==mx){mx+=1;mn-=1;}
    T a=mn,d=(mx-mn)/(6*(1+two_sets));
    if(reverse){a=mx,d=-d;}
    colors.Add_Control_Point(a+0*d,COL(1,1,1));
    colors.Add_Control_Point(a+1*d,COL(1,0,0));
    colors.Add_Control_Point(a+2*d,COL(1,1,0));
    colors.Add_Control_Point(a+3*d,COL(0,1,0));
    colors.Add_Control_Point(a+4*d,COL(0,1,1));
    colors.Add_Control_Point(a+5*d,COL(0,0,1));
    if(two_sets){
        colors.Add_Control_Point(a+6*d,COL((T).3,(T)0,(T).3));
        colors.Add_Control_Point(a+7*d,COL((T).3,(T)0,(T)0));
        colors.Add_Control_Point(a+8*d,COL((T).3,(T).3,(T)0));
        colors.Add_Control_Point(a+9*d,COL((T)0,(T).3,(T)0));
        colors.Add_Control_Point(a+10*d,COL((T)0,(T).3,(T).3));
        colors.Add_Control_Point(a+11*d,COL((T)0,(T)0,(T).3));}
    colors.Add_Control_Point(a+(T)(6*(1+two_sets))*d,COL());
}
//#####################################################################
// Function Initialize_Matlab_Jet
//#####################################################################
template<class T> void INTERPOLATED_COLOR_MAP<T>::
Initialize_Matlab_Jet(T min_value,T max_value,bool log_scale,bool reverse)
{
    colors.control_points.Remove_All();
    mn=min_value;
    mx=max_value;
    use_log=log_scale;
    if(use_log){
        mn=log(abs(mn));
        mx=log(abs(mx));}
    PHYSBAM_ASSERT(mn<=mx);
    if(mn==mx){mx+=1;mn-=1;}
    T a=mn,d=mx-mn;
    if(reverse){a=mx,d=-d;}
    colors.Add_Control_Point(a+0*d,COL(0,0,(T)0.5608));
    colors.Add_Control_Point(a+(T)0.1406*d,COL(0,0,1));
    colors.Add_Control_Point(a+(T)0.3594*d,COL(0,1,1));
    colors.Add_Control_Point(a+(T)0.6094*d,COL(1,1,0));
    colors.Add_Control_Point(a+(T)0.8594*d,COL(1,0,0));
    colors.Add_Control_Point(a+d,COL((T)0.5,0,0));
}
//#####################################################################
// Function Initialize_Matlab_Jet
//#####################################################################
template<class T> void INTERPOLATED_COLOR_MAP<T>::
Initialize_Matlab_Hot(T min_value,T max_value,bool log_scale,bool reverse)
{
    colors.control_points.Remove_All();
    mn=min_value;
    mx=max_value;
    use_log=log_scale;
    if(use_log){
        mn=log(abs(mn));
        mx=log(abs(mx));}
    PHYSBAM_ASSERT(mn<=mx);
    if(mn==mx){mx+=1;mn-=1;}
    T a=mn,d=mx-mn;
    if(reverse){a=mx,d=-d;}
    colors.Add_Control_Point(a+0*d,COL(0,0,0));
    colors.Add_Control_Point(a+(T)0.3750*d,COL(1,0,0));
    colors.Add_Control_Point(a+(T)0.7656*d,COL(1,1,0));
    colors.Add_Control_Point(a+d,COL(1,1,1));
}
//#####################################################################
// Function operator ()
//#####################################################################
template<class T> auto INTERPOLATED_COLOR_MAP<T>::
operator()(T x) const -> COL
{
    if(use_log){if(x==0) x=mn;else x=log(abs(x));}
    return colors.Value(x);
}
//#####################################################################
// Function Read
//#####################################################################
template<class T> template<class RW> void INTERPOLATED_COLOR_MAP<T>::
Read(UNTYPED_ISTREAM<RW>& input)
{
    Read_Binary_Group(input,mn,mx,use_log,colors);
}
//#####################################################################
// Function Write
//#####################################################################
template<class T> template<class RW> void INTERPOLATED_COLOR_MAP<T>::
Write(UNTYPED_OSTREAM<RW>& output) const
{
    Write_Binary_Group(output,mn,mx,use_log,colors);
}
template class INTERPOLATED_COLOR_MAP<float>;
template class INTERPOLATED_COLOR_MAP<double>;
template INTERPOLATED_COLOR_MAP<double>::INTERPOLATED_COLOR_MAP(INTERPOLATED_COLOR_MAP<float> const&);
template INTERPOLATED_COLOR_MAP<float>::INTERPOLATED_COLOR_MAP(INTERPOLATED_COLOR_MAP<double> const&);
template void INTERPOLATED_COLOR_MAP<float>::Read(UNTYPED_ISTREAM<char>&);
template void INTERPOLATED_COLOR_MAP<float>::Read(UNTYPED_ISTREAM<float>&);
template void INTERPOLATED_COLOR_MAP<float>::Read(UNTYPED_ISTREAM<double>&);
template void INTERPOLATED_COLOR_MAP<float>::Write(UNTYPED_OSTREAM<char>&) const;
template void INTERPOLATED_COLOR_MAP<float>::Write(UNTYPED_OSTREAM<float>&) const;
template void INTERPOLATED_COLOR_MAP<float>::Write(UNTYPED_OSTREAM<double>&) const;
template void INTERPOLATED_COLOR_MAP<double>::Read(UNTYPED_ISTREAM<char>&);
template void INTERPOLATED_COLOR_MAP<double>::Read(UNTYPED_ISTREAM<float>&);
template void INTERPOLATED_COLOR_MAP<double>::Read(UNTYPED_ISTREAM<double>&);
template void INTERPOLATED_COLOR_MAP<double>::Write(UNTYPED_OSTREAM<char>&) const;
template void INTERPOLATED_COLOR_MAP<double>::Write(UNTYPED_OSTREAM<float>&) const;
template void INTERPOLATED_COLOR_MAP<double>::Write(UNTYPED_OSTREAM<double>&) const;
}
