/* -*- mode: c++; c-basic-offset: 3 -*- 
 * @(#)lowpass.cc PANDORE 2005-07-26
 * 
 * PANTHEON Project 
 * 
 * GREYC IMAGE 
 * 6 Boulevard Maréchal Juin 
 * F-14050 Caen Cedex France 
 * 
 * This file is free software. You can use it, distribute it 
 * and/or modify it. However, the entire risk to the quality 
 * and performance of this program is with you. 
 * 
 * Please email any bugs, comments, and/or additions to this file to: 
 * Regis.Clouard@greyc.ensicaen.fr * http://www.greyc.ensicaen.fr/~regis 
 *
 */

/* 
 * (C)Hoock Jean-Baptiste - 2005-07-26 
 */ 


/**
 * Generate a low-pass filter
 */

/**
 * Generer un filtre passe-bas
 */

#include <pandore.h>

#ifdef MAIN
#undef MAIN

#include "arithmetic/pabs.cpp"
#include "arithmetic/pdiv.cpp"
#include "arithmetic/ppow.cpp"
#include "arithmetiic/pmult.cpp"
#include "arithmetic/psqrt.cpp"	
#include "arithmetic/padd.cpp"

#include "wedgewindow.cc"

#define MAIN
#endif

/*
 * Generates a low-pass filter by using a Meyer window.
 * Mi and Ni are parameters in order to calculate the filter.
 * M1 and N1 influence the height
 * M2 and N2 influence the width
 * the formule is 
 * 1+2*floor(Mi)+2*(floor(2*Mi)-floor(Mi)-1-(Ni mod 3==0))
 * i=1 for the height
 * i=2 for the width
 * lowpass is the the result: the filter
 */


/*
 * used by fct and fict
 * M1 et M2 doivent etre superieurs a 1 sinon window_length=0
 * la consequence peut etre un segmentation fault 
 */
Errc Lowpass(Img2dsf& lowpass, Double M1, Double M2, Long N1, Long N2) {
   Short lowpass_length_1;
   Short lowpass_length_2;
   Short lowpass_width;
   Short lowpass_height;
   Img1dsf lowpass_1;
   Img1dsf lowpass_2;
   Img1dsf one_1;     //des images 1D de 1
   Img1dsf one_2;
   Short one_length_1; 
   Short one_length_2;

   //Declaration des variables qui servent pour les cas Ni mod 3
   //suivant la valeur des Ni, la taille des fenetres peuvent varier de 1.
   int decalage_N1=(N1%3==0) ? 1 : 0;
   int decalage_N2=(N2%3==0) ? 1 : 0;

   //initializations and allocations
   //windows of Meyer
   int window_length_1=(int)(floor(2*M1)-floor(M1)-1-decalage_N1);
   int window_length_2=(int)(floor(2*M2)-floor(M2)-1-decalage_N2);
   Img1dsf coord_1(1+window_length_1);
   Img1dsf coord_2(1+window_length_2);
   Img1dsf wl_1(1+window_length_1);
   Img1dsf wr_1(1+window_length_1);
   Img1dsf wl_2(1+window_length_2);
   Img1dsf wr_2(1+window_length_2);

   int i;
   Double a;
   for(i=0, a=0; i<window_length_1+1; i++, a+=(Double)1.0/window_length_1)
      coord_1[i]=(Float)a;
   Double b;
   for(i=0, b=0; i<window_length_2+1; i++, b+=(Double)1.0/window_length_2)
      coord_2[i]=(Float)b;

    Wedgewindow(coord_1,wl_1,wr_1);
    Wedgewindow(coord_2,wl_2,wr_2);

   //the low-pass filters
  
   //allocations of filters

   lowpass_length_1=2*(1+window_length_1+(Short)floor(M1))+1; 
   //=window_length_1+(2*floor(M1)+1)+window_length_1
   lowpass_length_2=2*(1+window_length_2+(Short)floor(M2))+1;

   one_length_1=2*(Short)floor(M1)+1;
   one_length_2=2*(Short)floor(M2)+1;
   one_1.New(one_length_1);
   one_2.New(one_length_2);
   one_1=1;
   one_2=1;

   lowpass_width=lowpass_length_2+2*decalage_N2;
   lowpass_height=lowpass_length_1+2*decalage_N1;
   lowpass_1.New(lowpass_height);
   lowpass_2.New(lowpass_width);
   lowpass_1[0]=0;
   lowpass_2[0]=0;
   lowpass_1[lowpass_height-1]=0;
   lowpass_2[lowpass_width-1]=0;

   memcpy(&lowpass_2[decalage_N2],&wl_2[0],(window_length_2+1)*sizeof(Img1dsf::ValueType));
   memcpy(&lowpass_2[decalage_N2+window_length_2+1],&one_2[0], one_length_2*sizeof(Img1dsf::ValueType));
   memcpy(&lowpass_2[decalage_N2+window_length_2+1+one_length_2], &wr_2[0],(1+window_length_2)*sizeof(Img1dsf::ValueType));
   
   memcpy(&lowpass_1[decalage_N1],&wl_1[0],(window_length_1+1)*sizeof(Img1dsf::ValueType));
   memcpy(&lowpass_1[decalage_N1+window_length_1+1],&one_1[0], one_length_1*sizeof(Img1dsf::ValueType));
   memcpy(&lowpass_1[decalage_N1+window_length_1+1+one_length_1], &wr_1[0],(1+window_length_1)*sizeof(Img1dsf::ValueType));
   
   lowpass.New(lowpass_height,lowpass_width); 
   //allocation genante: elle devrait etre faite a l'exterieur de
   //l'operateur
   //apparemment lowpass.Size=(bigN1,bigN2)

   for(i=0; i<lowpass_width; i++)
      for(int j=0; j<lowpass_height; j++)
	 lowpass[j][i]=lowpass_1[j]*lowpass_2[i];
   
   coord_1.Delete();
   coord_2.Delete();
   one_1.Delete();
   one_2.Delete();
   wl_1.Delete();
   wr_1.Delete();
   wl_2.Delete();
   wr_2.Delete();
   lowpass_1.Delete();
   lowpass_2.Delete();
   
   return SUCCESS;
}

#ifdef MAIN 
/* 
 * Modify only the following constants, and the operator switches. 
 */ 
#define USAGE "USAGE : %s M1 M2 N1 N2 [-m mask] [im_in|-] [im_out|-]" 
#define PARC 4 // Number of parameters 
//les 2 parametres supplementaires sont optionnelles
#define FINC 0 // Number of input images 
#define FOUTC 1 // Number of output images 
#define MASK 0 // Level of masking 
int main(int argc,char* argv[]) {
   Errc result; // The result code of the execution. 
   Pobject* mask; // The mask. 
   Pobject* objin[FINC+1]; // The input objects; 
   Pobject* objs[FINC+1]; // The source objects masked by the mask. 
   Pobject* objout[FOUTC+1]; // The output object. 
   Pobject* objd[FOUTC+1]; // The result object of the execution. 
   char* parv[PARC+1]; // The input parameters. 
 
   ReadArgs(argc,argv,PARC,FINC,FOUTC,&mask, objin,objs,objout,objd,parv,USAGE,MASK); 

   objd[0]=new Img2dsf; 
   Img2dsf* const imd=(Img2dsf*)objd[0];
   result=Lowpass(*imd,atof(parv[0]),atof(parv[1]),(Short)atoi(parv[2]),(Short)atoi(parv[3]));  

   WriteArgs(argc,argv,PARC,FINC,FOUTC,&mask,objin,objs,objout,objd,MASK);
   Exit(result); 
   return 0; 
}

#endif
