/*===========================================================================
  Copyright (C) 1993-2009 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/******************************************************************************
**              Copyright (C) 1993 by European Southern Observatory
*******************************************************************************
**
**    UNIT
**
**    Version: 19.1
**
**    Author: Jean-Luc Starck
**
**    Date:  03/02/25
**    
**    File:  filter_cf.c
**
.VERSION
 090804		last modif

*******************************************************************************
**
**    DESCRIPTION   routines concerting filters used by the wavelet 
**    -----------   transform which need the FFT   
**
******************************************************************************
**
** float pyr_2d_cf_scaling_function (u, v, Freq_Coup, Nl, Nc)
** float u,v;
** float Freq_Coup;
** int Nl, Nc;
**
**    Computes the theorical transfert function of an instrument
**    which has a  cut off frequency Freq_Coup (0 <Freq_Coup <= 0.5)
**    The assumption is that the transfert function is a b3-spline
**
**    u,v = INPUT frequency point
**    Freq_Coup = INPUT cut off frequency  
**    Nl,Nc = INPUT image size
**
**    Return the value in u,v
**    u and v must verify : - Nl /2 < u and v < Nl / 2
**
******************************************************************************* 
**
** float pyr_2d_cf_filter_h (Freq_u, Freq_v, Freq_Coup, Nl, Nc)
** float Freq_u, Freq_v;
** float Freq_Coup;
** int Nl, Nc;
**
**   computes the coefficients which allow to go from a resolution to
**   the next one.
**
**   Freq_u, Freq_v = INPUT frequency point
**   Freq_Coup = INPUT cut-off frequency
**   Nl,Nc = INPUT image size
**
**   Return the value of the filter h in Freq_u, Freq_v 
**   Freq_u and Freq_v must verify : - Nl /2 < Freq_u and Freq_v < Nl / 2
**
******************************************************************************* 
**
** float pyr_2d_cf_filter_h_tilde (Freq_u, Freq_v, Freq_Coup, 
**                                 Nl, Nc, Type_Wavelet)
** float Freq_u, Freq_v;
** float Freq_Coup;
** int Nl, Nc;
** int Type_Wavelet;
**
**  computes the coefficients which allow to go from a resolution to
**   the previous  one.
**   Freq_u, Freq_v = INPUT frequency point
**   Freq_Coup = INPUT cut-off frequency
**   Nl,Nc = INPUT image size
**
**   Return the value of the filter h_tilde in Freq_u, Freq_v 
**   Freq_u and Freq_v must verify : - Nl /2 < Freq_u and Freq_v < Nl / 2
**
******************************************************************************* 
**
** float pyr_2d_cf_filter_g (Freq_u, Freq_v, Freq_Coup, Nl, Nc, Type_Wavelet)
** float Freq_u, Freq_v;
** float Freq_Coup;
** int Nl, Nc, Type_Wavelet;
**
**   computes the coefficients which allow to go from a resolution to
**   the next one.
**
**   Freq_u, Freq_v = INPUT frequency point
**   Freq_Coup = INPUT cut-off frequency
**   Nl,Nc = INPUT image size
**
**   Return the value of the filter g in Freq_u, Freq_v 
**   Freq_u and Freq_v must verify : - Nl /2 < Freq_u and Freq_v < Nl / 2
**  Type_Wavelet =   TO_PYR_FFT_DIFF_RESOL
**             or    TO_PYR_FFT_DIFF_SQUARE_RESOL
**             or    TO_PAVE_BSPLINE_FFT
**
******************************************************************************* 
**
** float pyr_2d_cf_filter_g_tilde (Freq_u, Freq_v, Freq_Coup, 
**                                 Nl, Nc, Type_Wavelet)
** float Freq_u, Freq_v;
** float Freq_Coup;
** int Nl, Nc, Type_Wavelet;
**
**   computes the coefficients which allow to go from a resolution to
**   the prevuois one.
**
**   Freq_u, Freq_v = INPUT frequency point
**   Freq_Coup = INPUT cut-off frequency
**   Nl,Nc = INPUT image size
**
**   Return the value of the filter g_tilde in Freq_u, Freq_v 
**   Freq_u and Freq_v must verify : - Nl /2 < Freq_u and Freq_v < Nl / 2
**  Type_Wavelet =   TO_PYR_FFT_DIFF_RESOL
**             or    TO_PYR_FFT_DIFF_SQUARE_RESOL
**             or    TO_PAVE_BSPLINE_FFT
**
******************************************************************************* 
**
** float pyr_2d_cf_filter_wavelet (Freq_u, Freq_v, Freq_Coup, 
**                                 Nl, Nc, Type_Wavelet)
** float Freq_u, Freq_v;
** float Freq_Coup;
** int Nl, Nc, Type_Wavelet;
**
**   computes the wavelet in Freq_u, Freq_v
**
**   Freq_u, Freq_v = INPUT frequency point
**   Freq_Coup = INPUT cut-off frequency
**   Nl,Nc = INPUT image size
**
**   Return the value of the wavelet in Freq_u, Freq_v 
**   Freq_u and Freq_v must verify : - Nl /2 < Freq_u and Freq_v < Nl / 2
**  Type_Wavelet =   TO_PYR_FFT_DIFF_RESOL
**             or    TO_PYR_FFT_DIFF_SQUARE_RESOL
**             or    TO_PAVE_BSPLINE_FFT
**
******************************************************************************* 
**
**  float pyr_2d_cf_filter(Which_Filter,Freq_u,Freq_v,Fc, Nl, Nc, Type_Wavelet)
**  int Which_Filter;
**  float Freq_u, Freq_v;
**  float Fc;
**  int Nl, Nc;
**  int Type_Wavelet;
**
**   computes the value in Freq_u, Freq_v of the filter defined by Which_Filter  
**   Which_Filter  = INPUT type filter 
**                Which_Filter =  SCALING_FUNCTION
**                             or FILTER_H
**                             or FILTER_H_TILDE
**                             or FILTER_G
**                             or FILTER_G_TILDE
**                             or WAVELET
**   Freq_u, Freq_v = INPUT frequency point
**   Freq_Coup = INPUT cut-off frequency
**   Nl,Nc = INPUT image size
**
**   Return the value of the wavelet in Freq_u, Freq_v 
**   Freq_u and Freq_v must verify : - Nl /2 < Freq_u and Freq_v < Nl / 2
**
**  Type_Wavelet =   TO_PYR_FFT_DIFF_RESOL
**             or    TO_PYR_FFT_DIFF_SQUARE_RESOL
**             or    TO_PAVE_BSPLINE_FFT
**
******************************************************************************* 
**
**  pyr_2d_cf_create_filter (Fc, Nl, Nc, Filter, Which, Type_Wavelet)
**  float Fc;
**  int Nl, Nc;
**  float *Filter;
**  int Which, Type_Wavelet;
**
**  computes the  filter defined by Which_Filter  
**
**   Which_Filter  = INPUT type filter 
**                Which_Filter =  SCALING_FUNCTION
**                             or FILTER_H
**                             or FILTER_H_TILDE
**                             or FILTER_G
**                             or FILTER_G_TILDE
**                             or WAVELET
**   Freq_Coup = INPUT cut-off frequency
**   Nl,Nc = INPUT image size
**
**   Filter = OUTPUT filter
**
**  Type_Wavelet =   TO_PYR_FFT_DIFF_RESOL
**             or    TO_PYR_FFT_DIFF_SQUARE_RESOL
**             or    TO_PAVE_BSPLINE_FFT
**
******************************************************************************/ 


#include <stdio.h>
#include <math.h>
#include <string.h>

#include "Def_Math.h"
#include "Def_Wavelet.h"

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

float pyr_2d_cf_scaling_function (u, v, Freq_Coup, Nl, Nc)
float u,v;
float Freq_Coup;
int Nl, Nc;
{
    float F, Fc, Scaling_Function;
    double lib_math_b3_spline ();

    /* we fixe the cut-off frequency to N / 2 */
    Fc = Freq_Coup * (float) Nl;

    F = sqrt ((float)(u * u + v * v));
    /*  . we multiply by 3/2 in order that: T(0) = 1
        . we multiply F by 2./Fc (b3_spline(2) = 0) 
          in order that: T(Fc) = 0
    */
    Scaling_Function = 3. / 2. * lib_math_b3_spline ((2. * F / Fc));
    return (Scaling_Function);
}

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

float pyr_2d_cf_filter_h (Freq_u, Freq_v, Freq_Coup, Nl, Nc)
float Freq_u, Freq_v;
float Freq_Coup;
int Nl, Nc;
{
    float Filter_H;
    int Nl_2, Nc_2;
    float u2,v2;
    float Freq1,Freq2;
    float pyr_2d_cf_scaling_function();

    Nl_2 = Nl / 2.;
    Nc_2 = Nc / 2.;
    u2 = 2. * Freq_u;
    v2 = 2. * Freq_v;

    if ((u2 < - Nl_2 ) || (u2 >= Nl_2) || (v2 < - Nc_2) || (v2 >= Nc_2))
    {
         Filter_H = 0.;
    }
    else
    {
         Freq1 = pyr_2d_cf_scaling_function (Freq_u, Freq_v, Freq_Coup, Nl, Nc);
         Freq2 = pyr_2d_cf_scaling_function (u2, v2, Freq_Coup, Nl, Nc);  

         if (fabs(Freq1) < FLOAT_EPSILON)
         {
             Filter_H = 0.;
         }
         else 
         {
             Filter_H = Freq2 / Freq1;
         }
    }
    return (Filter_H);
}

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

float pyr_2d_cf_filter_h_tilde (Freq_u, Freq_v, Freq_Coup, Nl, Nc, Type_Wavelet)
float Freq_u, Freq_v;
float Freq_Coup;
int Nl, Nc;
int Type_Wavelet;
{
    float Filter_H_Tilde, Filter_H, Filter_G, Den;
    float pyr_2d_cf_filter_h(), pyr_2d_cf_filter_g();


Filter_H_Tilde = 0.0;

    switch (Type_Wavelet)
    {
        case TO_PYR_FFT_DIFF_RESOL: 
        case TO_PAVE_BSPLINE_FFT:
                Filter_H = pyr_2d_cf_filter_h(Freq_u, Freq_v, Freq_Coup, 
                                              Nl, Nc);
                Filter_G = pyr_2d_cf_filter_g(Freq_u, Freq_v, Freq_Coup, 
                                                         Nl, Nc,Type_Wavelet);
                Den = Filter_H * Filter_H + Filter_G * Filter_G;
                if (Den < FLOAT_EPSILON) Filter_H_Tilde = 0.;
                else Filter_H_Tilde = Filter_H / Den;
            break;
        case TO_PYR_FFT_DIFF_SQUARE_RESOL:
            Filter_H_Tilde = pyr_2d_cf_filter_h(Freq_u, Freq_v, Freq_Coup, 
                                                Nl, Nc);
            break;
    }
    return (Filter_H_Tilde);
}

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

float pyr_2d_cf_filter_g_tilde (Freq_u, Freq_v, Freq_Coup, Nl, Nc, Type_Wavelet)
float Freq_u, Freq_v;
float Freq_Coup;
int Nl, Nc, Type_Wavelet;
{
    float Filter_G_Tilde, Filter_H, Filter_G, Den;
    float pyr_2d_cf_filter_h(), pyr_2d_cf_filter_g();

Filter_G_Tilde = 0.0;

    switch (Type_Wavelet)
    {
        case TO_PYR_FFT_DIFF_RESOL:
        case TO_PAVE_BSPLINE_FFT:
                Filter_H = pyr_2d_cf_filter_h(Freq_u, Freq_v, Freq_Coup, 
                                              Nl, Nc);
                Filter_G = pyr_2d_cf_filter_g(Freq_u, Freq_v, 
                                           Freq_Coup, Nl, Nc,Type_Wavelet);
                Den = Filter_H * Filter_H + Filter_G * Filter_G;
                if (Den < FLOAT_EPSILON) Filter_G_Tilde = 0.;
                else Filter_G_Tilde = Filter_G / Den;
                break;
        case TO_PYR_FFT_DIFF_SQUARE_RESOL:
                Filter_G_Tilde = pyr_2d_cf_filter_g(Freq_u, Freq_v, Freq_Coup, 
                                              Nl, Nc, Type_Wavelet);
            break;
    }
    return (Filter_G_Tilde);
}
   
/***************************************************************************/   

float pyr_2d_cf_filter_g (Freq_u, Freq_v, Freq_Coup, Nl, Nc, Type_Wavelet)
float Freq_u, Freq_v;
float Freq_Coup;
int Nl, Nc, Type_Wavelet;
{
    float Filter_G;
    float Filter_H;
    float pyr_2d_cf_filter_h ();

Filter_G = 0.0;

     Filter_H = pyr_2d_cf_filter_h (Freq_u, Freq_v, Freq_Coup, Nl, Nc);
     switch (Type_Wavelet)
     {
         case TO_PYR_FFT_DIFF_RESOL:
         case TO_PAVE_BSPLINE_FFT: 
                      Filter_G = 1 - Filter_H;
                      break;
         case TO_PYR_FFT_DIFF_SQUARE_RESOL:
                      Filter_G  = sqrt (1. - Filter_H * Filter_H);
                      break;
     }
    return (Filter_G);
}

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

float pyr_2d_cf_filter_wavelet (Freq_u, Freq_v, Freq_Coup, Nl, Nc, Type_Wavelet)
float Freq_u, Freq_v;
float Freq_Coup;
int Nl, Nc, Type_Wavelet;
{
    float Filter_Psi;
    float u2,v2;
    float Freq1,Freq2;
    float pyr_2d_cf_scaling_function();

Filter_Psi = 0.0;

    Freq1 = pyr_2d_cf_scaling_function (Freq_u, Freq_v, Freq_Coup, Nl, Nc);
    u2 = Freq_u / 2.;
    v2 = Freq_v / 2.;
    Freq2 = pyr_2d_cf_scaling_function (u2, v2, Freq_Coup, Nl, Nc);

    switch (Type_Wavelet)
    {
        case TO_PYR_FFT_DIFF_RESOL: 
        case TO_PAVE_BSPLINE_FFT:
            Filter_Psi = Freq2 - Freq1;
            break;
        case TO_PYR_FFT_DIFF_SQUARE_RESOL:
            Filter_Psi = Freq2*Freq2 - Freq1*Freq1;
            break;
    }
    return (Filter_Psi);
}

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

float pyr_2d_cf_filter (Which_Filter, Freq_u, Freq_v, Fc, Nl, Nc, Type_Wavelet)
int Which_Filter;
float Freq_u, Freq_v;
float Fc;
int Nl, Nc, Type_Wavelet;
{
    float pyr_2d_cf_filter_wavelet ();
    float pyr_2d_cf_filter_g ();
    float pyr_2d_cf_filter_h ();
    float pyr_2d_cf_filter_h_tilde();
    float pyr_2d_cf_filter_g_tilde();
    float pyr_2d_cf_scaling_function();
    float Val_Return;

Val_Return = 0.0;


    switch (Which_Filter)
    {
        case SCALING_FUNCTION :
              Val_Return = pyr_2d_cf_scaling_function (Freq_u, Freq_v, Fc, 
                                                       Nl, Nc);
              break;
        case FILTER_H :
              Val_Return = pyr_2d_cf_filter_h (Freq_u, Freq_v, Fc, Nl, Nc);
              break;
        case FILTER_H_TILDE :
              Val_Return =  pyr_2d_cf_filter_h_tilde (Freq_u, Freq_v, Fc, 
                                                   Nl, Nc, Type_Wavelet);
              break;
        case FILTER_G :
              Val_Return = pyr_2d_cf_filter_g (Freq_u, Freq_v, Fc, 
                                                   Nl, Nc, Type_Wavelet);
              break;
        case FILTER_G_TILDE :
              Val_Return = pyr_2d_cf_filter_g_tilde (Freq_u, Freq_v, Fc, 
                                                   Nl, Nc, Type_Wavelet);
              break;
        case WAVELET :
              Val_Return = pyr_2d_cf_filter_wavelet (Freq_u, Freq_v, Fc, 
                                                   Nl, Nc, Type_Wavelet);
              break;
    }
    return (Val_Return);
}

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

void pyr_2d_cf_create_filter (Fc, Nl, Nc, Filter, Which, Type_Wavelet)
float Fc;
int Nl, Nc;
float *Filter;
int Which, Type_Wavelet;
{
    int i,j;
    float u,v;
    float pyr_2d_cf_filter ();

    for (i = 0; i < Nl; i++)
    {
        u = (float) i - (float) Nl / 2.;
        for (j = 0; j < Nc; j++)
        {
            v = (float) j - (float) Nc / 2.;
            Filter [i * Nc + j] = pyr_2d_cf_filter (Which, u, v, Fc, 
                                                 Nl, Nc, Type_Wavelet);
        }
    }
}

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


