/* -*- mode: c++; c-basic-offset: 3 -*-
 *
 * PANDORE (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:
 * pandore@greyc.ensicaen.fr
 * http://www.greyc.ensicaen.fr/EquipeImage/Pandore/
 */

/**
 * @author Hoock Jean-Baptiste - 28-07-2005
 * @author Ouédraogo Nael - 05-01-2006
 * @author Rémy Yannick - 05-01-2006
 */

/**
 * @file curvelet.cc
 */

#ifndef CURVELET_CC
#define CURVELET_CC 

#include "curvelet.h"

/**
 * Give the rounded number
 * No optimization for negative numbers (recursive function)
 */
Double my_round(Double a) {
   Double m=ceil(a);
   if (a<0) return -my_round(-a);
   else return (m-a>0.5) ? floor(a) : m;
}

/**
 * Class CurveletTransformAlgorithm.
 * this class makes some initializations.
 * this class should be more important.
 */

//default constructor
CurveletTransformAlgorithm::CurveletTransformAlgorithm(){}

//destructor
CurveletTransformAlgorithm::~CurveletTransformAlgorithm(){}

/**
 * initializations of Mi
 * the Mi are used into the pyramidal decomposition 
 */
void CurveletTransformAlgorithm::init_Mi(const Long& N1, const Long& N2,Double& M1, Double& M2) {
   M1=N1/3.0;
   M2=N2/3.0;
}

/**
 * initializations of Mi and bigNi
 * the Mi are used to in decomposition pyramidal
 */
void CurveletTransformAlgorithm::init_Mi_bigNi(const Long& N1, const Long& N2,
					       Double& M1, Double& M2, Long& bigN1, Long& bigN2) {
   init_Mi(N1,N2,M1,M2);
   bigN1=2*(Long)floor(2*M1)+1;
   bigN2=2*(Long)floor(2*M2)+1;
}
//end of CurveletTransformAlgorithm


/**
 * CurveletImage
 */

/**
 * Default constructor
 */
CurveletImage::CurveletImage():curv(0){}

/**
 * the constructor used by fct
 */
CurveletImage::CurveletImage(const Img2dsf& img, const Long& nbscales, const Long& nbangles_coarse)
   : nbscales(nbscales) , nbangles_coarse(nbangles_coarse) {
   nbangles.New(nbscales);
   Long i; //variables of loop
   
   height=img.Height();
   width=img.Width();

   for(i=0; i<nbscales-1; i++)
      nbangles[i]=nbangles_coarse*(Long)pow(2,(ceil((nbscales-(i+2))/2.0)));
  
   nbangles[nbscales-1]=1;  
  
   alloc(nbangles,nbscales);
}

/**
 * the constructor used by fict.
 */
CurveletImage::CurveletImage(Collection** les_curvelets, Img2dsl** curv_size,
			     Img1dsl* p_nbangles, const Long& nbscales, const Long& height,
			     const Long& width, const Long& nbangles_coarse)
   : nbscales(nbscales) , nbangles_coarse(nbangles_coarse) {
   Long i,j,x,y; //variables of loop
   Img2dsf**  curvdata_tmp=NULL;
   this->height=height;
   this->width=width;
   nbangles.New(nbscales);
   nbangles=*p_nbangles;
   
   //allocation of curv
   alloc(nbangles,nbscales);
   for(i=0; i<nbscales; i++)
      for(j=0; j<nbangles[i]; j++)
	 curv[i][j].New((*(curv_size[i]))[j][0],(*(curv_size[i]))[j][1]);


   //initialization of curv
   for(i=0; i<nbscales; i++){
      curvdata_tmp=les_curvelets[i]->GETPARRAY("curvangles",Img2dsf);
      for(j=0; j<nbangles[i]; j++)
	 for(x=0; x<(*(curv_size[i]))[j][1]; x++)
	    for(y=0; y<(*(curv_size[i]))[j][0]; y++)
	       curv[i][j][y][x]=(*(curvdata_tmp[j]))[y][x];
   }
}

/**
 * destructor
 */
CurveletImage::~CurveletImage() {
   Long i,j; //variables de boucles
   
   if (curv) {
      //desallocation des images
      for(i=0; i<nbscales; i++)
	 for(j=0; j<nbangles[i]; j++) 
	    //rq: la philosophie de pandore n'est pas ici respectee pour i et j
	    curv[i][j].Delete();
      
      //desallocation des pointeurs "angulaires"
      for(j=0; j<nbscales; j++)
	 if(curv[j]) delete[] curv[j];
      
      //desallocation des pointeurs "d'echelle"
      delete[] curv;
   }
   
   nbangles.Delete();
}

/**
 * alloc: allocation of curv
 * WARNING:
 * We allocate here only pointers because
 * we don't know still the size of curvelets.
 * the allocation of images is made later.
 */
void CurveletImage::alloc(const Img1dsl& nbangles, const Long& nbscales) {
   Long j; //variable de boucles
   
   curv=new Img2dsf*[nbscales];
   for(j=0; j<nbscales; j++)
      curv[j]=new Img2dsf[nbangles[j]];
}

/**
 * rechDimMax: search the maximal dimensions of curvelets at a given scale
 * results are in h_max and w_max
 */
void CurveletImage::rechDimMax(const Long& scale, Long& h_max,Long& w_max) {
   Long j; //variables of loop
   for (j=0; j<nbangles[scale]; j++) {
      if(h_max<curv[scale][j].Height()) h_max=curv[scale][j].Height();
      if(w_max<curv[scale][j].Width()) w_max=curv[scale][j].Width();
   }
}


/**
 ** Low-pass filter.
 **/

/**
 * default constructor
 */
LowPass::LowPass(){}

/**
 * destructor
 */
LowPass::~LowPass(){}

/**
 * initialization of a low-pass filter
 */
void LowPass::initPasseBas(Img2dsf& lowpass, const Double& M1, const Double& M2, const Long& N1,const Long& N2) {
   Lowpass(lowpass,M1,M2,N1,N2);
}

/**
 * application of low-pass filter on an image
 * X the image
 * lowpass est const
 */
void LowPass::applyLowPass(Img2dsf& X, Img2dsf& lowpass, Img2dsf& Xlow) {
   PMult(X,lowpass,Xlow);
}

/**
 * initialization of a high-pass filter from a low-pass filter
 * the formule is simply: hipass=sqrt(1-lowpass^2)
 * (afin de pouvoir profiter des operateurs Pandore notamment Mult, lowpass n'a 
 * pas ete declare cons).
 */
void LowPass::initHauteFrequence(Img2dsf& lowpass, Img2dsf& hipass) {
   Img2dsf temp;
   Long i,j; //variables of loop
   temp.New(lowpass.Size()); //temporary image
   PMult(lowpass,lowpass,temp);

   for(i=0; i<lowpass.Width(); i++)
      for(j=0;j<lowpass.Height(); j++)
	 temp[j][i]=1-temp[j][i];
  
   PSqrt(temp,hipass);

   //desallocation
   temp.Delete();
}

/**
 * Reinitialization of Xlow and some others variables 
 * Xlow the image obtained after an application of a lowpass filter 
 * on an image  
 * (e)lowpass est const
 */
void LowPass::reinitXlow(Img2dsf& lowpass, Img2dsf& hipass, Img2dsf& Xlow_re,
			 Img2dsf& Xlow_im, Img2dsf& Xhi_re, Img2dsf& Xhi_im, 
			 const Double& M1, const Double& M2) {
   //variables de boucle
   Long Xlow_index_1;
   Long Xlow_index_2; 
   Long i,j; 

   Long temp_1=(Long)floor(4*M1)-(Long)floor(2*M1);//+1;
   Long temp_2=(Long)floor(4*M2)-(Long)floor(2*M2);//+1;

   Long bigN1j=2*(Long)floor(2*M1)+1;
   Long bigN2i=2*(Long)floor(2*M2)+1;

   Img2dsf Xlow_temp_re, Xlow_temp_im;
   PExtractSubImage(Xlow_re,Xlow_temp_re,0,0,bigN1j,bigN2i);
   PExtractSubImage(Xlow_im,Xlow_temp_im,0,0,bigN1j,bigN2i);
  
   //reinitialization of Xhi
   Xhi_re.Delete();
   Xhi_im.Delete();
   Xhi_re.New(Xlow_re.Size());
   Xhi_im.New(Xlow_im.Size());
  
   Xhi_re=Xlow_re;  
   Xhi_im=Xlow_im;
  
   for(i=0; i<bigN2i; i++) 
      for(j=0; j<bigN1j; j++) {
	 //Xlow_index_n varie de -floor(2*Mn)+floor(4*Mn)+1 
	 //a floor(2*Mn)+floor(4*Mn)+1
	 Xlow_index_1=j+temp_1;
	 Xlow_index_2=i+temp_2;
	 Xlow_temp_re[j][i]=Xlow_re[Xlow_index_1][Xlow_index_2];
	 Xlow_temp_im[j][i]=Xlow_im[Xlow_index_1][Xlow_index_2];
	 
	 Xhi_re[Xlow_index_1][Xlow_index_2]=Xlow_temp_re[j][i]*hipass[j][i];
	 Xhi_im[Xlow_index_1][Xlow_index_2]=Xlow_temp_im[j][i]*hipass[j][i];
      }
   
   //reinitialization of Xlow
   Xlow_re.Delete();
   Xlow_im.Delete();
   Xlow_re.New(Xlow_temp_re.Size());   
   Xlow_im.New(Xlow_temp_im.Size());   

   PMult(Xlow_temp_re,lowpass,Xlow_re);   //applyLowPass
   PMult(Xlow_temp_im,lowpass,Xlow_im);   //applyLowPass
  
   //desallocation
   Xlow_temp_re.Delete();
   Xlow_temp_im.Delete();
}

/**
 * Reinitializes Xlow and Xhi.
 * Xhi is the image obtained after an application of a high-pass filter 
 * on an image
 */
void LowPass::updateXlowXhi(Img2dsf& Xlow_re, Img2dsf& Xlow_im, Img2dsf& Xhi_re,
			    Img2dsf& Xhi_im, const Double& M1, const Double& M2) {
   Img2dsf lowpass,hipass;
   initPasseBas(lowpass,M1,M2,1,1);

   // 1 et 1 sont deux valeurs sans importance 
   // le point important est qu'ils ne doivent pas etre divisibles par 3
   // 1 is not a multiple of 3
   // see operator Lowpass
   hipass.New(lowpass.Size());

   initHauteFrequence(lowpass,hipass);
   reinitXlow(lowpass,hipass,Xlow_re,Xlow_im,Xhi_re,Xhi_im,M1,M2);

   lowpass.Delete();
   hipass.Delete();
}

/**
 * initializations of filters: low-pass and high-pass filters
 */
void LowPass::initFilters(Img2dsf& lowpass, Img2dsf& hipass, const Double& M1, const Double& M2) {
   initPasseBas(lowpass,M1,M2,1,1);
   hipass.New(lowpass.Size());
   initHauteFrequence(lowpass,hipass);
}

/**
 * updateXj: updating of variable lowpass
 */
void LowPass::updateX(const Img2dsf& lowpass_next, const Img2dsf& hipass, 
		      Img2dsf& Xj_re, Img2dsf& Xj_im, Img2dsf& X_re, 
		      Img2dsf& X_im, Img2dsf& lowpass, const Double& M1, 
		      const Double& M2, const Long& Xj_topleft_1, 
		      const Long& Xj_topleft_2) {
   Long Xj_index_1;
   Long Xj_index_2;
   Long loc_1;
   Long loc_2;
   Long i,j; 
 
   Long temp_1=(Long)floor(4*M1)-(Long)floor(2*M1);
   Long temp_2=(Long)floor(4*M2)-(Long)floor(2*M2);
 
   Long bigN1j=2*(Long)floor(2*M1)+1;
   Long bigN2i=2*(Long)floor(2*M2)+1;
   Long n1=2*(Long)floor(4*M1)+1;
   Long n2=2*(Long)floor(4*M2)+1;
  
   applyLowPass(Xj_re,lowpass,Xj_re);
   applyLowPass(Xj_im,lowpass,Xj_im);
 
   for (i=0; i<bigN2i; i++) 
      for (j=0; j<bigN1j; j++) {
	    //Xj_index_n varie de -floor(2*Mn)+floor(4*Mn)+1 
	    //a floor(2*Mn)+floor(4*Mn)+1
	    Xj_index_1=j+temp_1;
	    Xj_index_2=i+temp_2;
	    Xj_re[Xj_index_1][Xj_index_2]*=hipass[j][i];
	    Xj_im[Xj_index_1][Xj_index_2]*=hipass[j][i];
	 }
  
   for(i=0; i<n2; i++) 
      for(j=0; j<n1; j++) {
	 loc_1=Xj_topleft_1+j;
	 loc_2=Xj_topleft_2+i;
	 X_re[loc_1][loc_2]+=Xj_re[j][i];
	 X_im[loc_1][loc_2]+=Xj_im[j][i];
      }
  
   //updating of low-pass
   lowpass.Delete();
   lowpass.New(lowpass_next.Props());
   lowpass=lowpass_next;
}


//end of LowPass


/**
 * Pyramidal scale decomposition.
 */
PyramidalScaleDecomposition::PyramidalScaleDecomposition()
   :scale(0){}


/**
 * constructor 
 * N1 and N2 are the dimaensions of the original image
 * N1 the height
 * N2 the width
 */
PyramidalScaleDecomposition::PyramidalScaleDecomposition(const Long& N1, const Long& N2) :scale(0) {
   M1=N1/3.0;
   M2=N2/3.0;
}

/**
 * Destructor
 */
PyramidalScaleDecomposition::~PyramidalScaleDecomposition(){}

/**
 * Performs the pyramidal scale decomposition
 */
void PyramidalScaleDecomposition::decompose(const Img1dsl& nbangles, Img2dsf** C, Img2dsf& Xlow_re, 
					    Img2dsf& Xlow_im, Img2dsf& Xhi_re, Img2dsf& Xhi_im) {
   LowPass lp;
   Long nb_step=nbangles.Width()-1;
   
   while(scale<nb_step) {
      //initialization of filters
      maj_Mi();
      lp.updateXlowXhi(Xlow_re,Xlow_im,Xhi_re,Xhi_im,M1,M2);
      //angular decomposition
      AngularDecomposition ad(nbangles,scale,M1,M2);
      ad.decompose(Xhi_re,Xhi_im,C,scale);
      scale++; //the following scale 
   }
}


//pyramidal reconstruction
void PyramidalScaleDecomposition::reconstruction(Img2dsf** C, const Img1dsl& nbangles, Img2dsf& lowpass, Img2dsf& lowpass_next,
						 Img2dsf& Xj_re, Img2dsf& Xj_im, Img2dsf& X_re, Img2dsf& X_im,
						 Long& Xj_topleft_1, Long& Xj_topleft_2) {
   Img2dsf hipass;
  
   LowPass lp;
   Long nb_step=nbangles.Width()-1;
  
   while(scale<nb_step) {
      {//block: reinitialization of filters for the new scale
	 maj_Mi();
	 lp.initFilters(lowpass_next,hipass,M1,M2);       
	 Xj_re.Delete();
	 Xj_im.Delete();
	 Xj_re.New(2*(Long)floor(4*M1)+1,2*(Long)floor(4*M2)+1);
	 Xj_im.New(2*(Long)floor(4*M1)+1,2*(Long)floor(4*M2)+1);
	 Xj_re=Xj_im=0;
      }
      
      {//block: angular reconstruction
	 AngularDecomposition ad(nbangles,scale,M1,M2);
	 ad.recompose(C,Xj_re,Xj_im,scale);
      }
      
      {//block: prepare loop reentry
	 lp.updateX(lowpass_next,hipass,Xj_re,Xj_im,X_re,X_im,lowpass,M1,M2,
		    Xj_topleft_1,Xj_topleft_2);
	 scale++;
	 Xj_topleft_1+=(Long)(floor(4*M1)-floor(2*M1));
	 Xj_topleft_2+=(Long)(floor(4*M2)-floor(2*M2));
      }
      
   }
   
   //desallocation
   hipass.Delete();
}

/**
 * angular decomposition
 */

/**
 * default constructor
 */
AngularDecomposition::AngularDecomposition(){}

/**
 * A constructor
 */
AngularDecomposition::AngularDecomposition(const Img1dsl& nbangles,
					   const Long& niv,
					   const Double& M1, const Double& M2)
   : quadrant(0),nbquadrants(2),theta(-1) {
   nbangles_perquad=nbangles[niv]/nbquadrants; 
  
   M_horiz=M1; 
   M_vert=M2; 
   //a l'initialisation, M_horiz et M_vert sont inverses
   //MAIS des qu'on commence la decomposition les valeurs sont
   //aussitot echanges
}

/**
 * A constructor 
 */
AngularDecomposition::AngularDecomposition(const Long& quadrant, const Long& nbquadrants,
					   const Long& nbangles_perquad, const Double& M_horiz,
					   const Double& M_vert, const Long& theta)
   :quadrant(quadrant),nbquadrants(nbquadrants),
    nbangles_perquad(nbangles_perquad),M_horiz(M_horiz),M_vert(M_vert),
    theta(theta){}

//the destructor
AngularDecomposition::~AngularDecomposition(){}

//SWAP
//swap M_horiz and M_vert
void AngularDecomposition::maj_M_horiz_M_vert() {
   Double temp=M_horiz;
   M_horiz=M_vert;
   M_vert=temp;
}

/**
 * decompose: the angular decomposition
 */
void AngularDecomposition::decompose(Img2dsf& Xhi_re, Img2dsf& Xhi_im, Img2dsf** C, const Long& ind) {
   Long i; //variable of loop
  
   while (quadrant<nbquadrants) {
      maj_M_horiz_M_vert();
      LeftCornerWedge* leftWedge=new LeftCornerWedge(M_horiz,M_vert,
						     nbangles_perquad);
      RegularWedge* regularWedge;
      regularWedge=new RegularWedge(M_horiz,M_vert,nbangles_perquad);
      RightCornerWedge* rightWedge;
      rightWedge=new RightCornerWedge(M_horiz,M_vert,nbangles_perquad);
      
      leftWedge->decompose(Xhi_re,Xhi_im,C,M_horiz,quadrant,ind,theta);
      
      for (i=1; i<nbangles_perquad-1; i++) {
	 regularWedge->decompose(Xhi_re,Xhi_im,C,M_horiz,quadrant,ind,theta);
	 regularWedge->incrSubl();
      }
	 
      rightWedge->decompose(Xhi_re,Xhi_im,C,M_horiz,quadrant,ind,theta);
	 
      if (quadrant<nbquadrants-1) {
	 //rotation of the image obtained after an application of a high-pass filter
	 Img2dsf* cloneXhi_re=(Img2dsf*) Xhi_re.Clone(); 
	 Img2dsf* cloneXhi_im=(Img2dsf*) Xhi_im.Clone(); 
	 Xhi_re.Delete();
	 Xhi_im.Delete();
	 Xhi_re.New(cloneXhi_re->Width(),cloneXhi_re->Height());
	 Xhi_im.New(cloneXhi_im->Width(),cloneXhi_im->Height());
	 QuartDeTour(*cloneXhi_re,Xhi_re,1); 
	 QuartDeTour(*cloneXhi_im,Xhi_im,1);
	 delete cloneXhi_re;
	 delete cloneXhi_im;
      }
      
      delete leftWedge;
      delete regularWedge;
      delete rightWedge;
      
      quadrant++; //the following quadrant
   }
}

/**
 * recompose: the angular reconstruction
 */
void AngularDecomposition::recompose(Img2dsf** C, Img2dsf& Xj_re,
				     Img2dsf& Xj_im, const Long& scale) {
   Long i; //variable of loop
  
   LeftCornerWedge* leftWedge;
   RegularWedge* regularWedge;
   RightCornerWedge* rightWedge;
  
   Img2dsf* cloneXj_re;
   Img2dsf* cloneXj_im;  

   while (quadrant<nbquadrants) {
      maj_M_horiz_M_vert();
  
      leftWedge=new LeftCornerWedge(M_horiz,M_vert,nbangles_perquad);
      regularWedge=new RegularWedge(M_horiz,M_vert,nbangles_perquad);      
      rightWedge=new RightCornerWedge(M_horiz,M_vert,nbangles_perquad);
       
      //the wedges
      leftWedge->recompose(C,Xj_re,Xj_im,scale,quadrant,M_horiz,theta);
      
      for (i=1; i<nbangles_perquad-1; i++) {
	 regularWedge->recompose(C,Xj_re,Xj_im,scale,quadrant,M_horiz,theta);
	 regularWedge->incrSubl();
      }
      
      rightWedge->recompose(C,Xj_re,Xj_im,scale,quadrant,M_horiz,theta);
      
      //the block of the rotation of Xj
      {
	 cloneXj_re=(Img2dsf*) Xj_re.Clone(); 
	 cloneXj_im=(Img2dsf*) Xj_im.Clone(); 
	 Xj_re.Delete();
	 Xj_im.Delete();
	 Xj_re.New(cloneXj_re->Width(),cloneXj_re->Height());
	 Xj_im.New(cloneXj_im->Width(),cloneXj_im->Height());
	 QuartDeTour(*cloneXj_re,Xj_re,1);  //optimisation?
	 QuartDeTour(*cloneXj_im,Xj_im,1);
	 delete cloneXj_re;
	 delete cloneXj_im;
      }

      quadrant++; //following quadrant

      //desallocation
      delete leftWedge;
      delete regularWedge;
      delete rightWedge;
   }
}


/**
 * families of WedgePartitions *
 */

/**
 * the class Wedge
 * 
 * Wedge: a constructor
 */
Wedge::Wedge(Double M_horiz, Double M_vert, Long nbangles_perquad):
   abs((Long)floor(4*M_horiz)),
   ord((Long)floor(4*M_vert)),
   first_wedge_endpoint_vert((Long)my_round(2*ord/(Double)(2*nbangles_perquad)+1)) {
   /**
    * declaration
    */
   Double a;
   Long i,k;
   Double pas=(Double)1/(2*nbangles_perquad);

   //size of wedges
   //Long t_ticks_side=1+(Long)floor(0.5/pas);
   Long t_ticks_side=1+nbangles_perquad;
   Long t_ticks_wedge;

   //the wedge_ticks
   Img1dsl wedge_ticks_left, wedge_ticks_right, wedge_ticks;

   /**
    * wedge_ticks
    */
   //allocation
   wedge_ticks_left.New(t_ticks_side);
   wedge_ticks_right.New(t_ticks_side);

   //initialization
   if (nbangles_perquad%2==1) {
      t_ticks_wedge=2*t_ticks_side;
      wedge_ticks.New(t_ticks_wedge);
      
      for(i=0,a=0; i<t_ticks_side; i++,a+=pas) { 
	 wedge_ticks_left[i]=(Long)my_round(a*2*abs+1); 
	 wedge_ticks_right[i]=2*abs+2-wedge_ticks_left[i];
      }
      
      for(i=0,a=0; i<t_ticks_side; i++,a+=pas) {
	 wedge_ticks[i]=wedge_ticks_left[i];
	 wedge_ticks[t_ticks_side+i]=wedge_ticks_right[t_ticks_side-i-1];
      }
   } else {
      t_ticks_wedge=2*t_ticks_side-1;
      wedge_ticks.New(t_ticks_wedge);
      
      for(i=0,a=0; i<t_ticks_side; i++,a+=pas) { 
	 wedge_ticks_left[i]=(Long)my_round(a*2*abs+1); 
	 wedge_ticks_right[i]=2*abs+2-wedge_ticks_left[i];
      }

      for(i=0,a=0; i<t_ticks_side; i++,a+=pas) {
	 wedge_ticks[i]=wedge_ticks_left[i];
	 wedge_ticks[t_ticks_side+i-1]=wedge_ticks_right[t_ticks_side-i-1];
      }
   }

   /**
    * wedge_points
    */
   //allocation
   t_endpoints=t_ticks_side-1;
   wedge_endpoints.New(t_endpoints);
   wedge_midpoints.New(t_endpoints-1);

   //initializations
   for(i=0,k=1; i<t_endpoints; i++, k+=2)
      wedge_endpoints[i]=wedge_ticks[k];

   //t_midpoints=t_endpoints-1
   for(i=0; i<t_endpoints-1; i++)
      wedge_midpoints[i]=(Float)(wedge_endpoints[i]+wedge_endpoints[i+1])/2;

   //desallocation of local arrays
   wedge_ticks_right.Delete();
   wedge_ticks_left.Delete();
   wedge_ticks.Delete();
}


//the destructor
Wedge::~Wedge() {
   wedge_endpoints.Delete();
   wedge_midpoints.Delete();
}

/**
 * function test of printing of the caracteristics of wedge
 */
void Wedge::afficheWedge() {
   std::cout<<"abs="<<abs<<std::endl;
   std::cout<<"ord="<<ord<<std::endl;
   std::cout<<"first_vedge_endpoint_vert="<<first_wedge_endpoint_vert;
   std::cout<<std::endl;
   std::cout<<"t_endpoints="<<t_endpoints<<std::endl;

   std::cout<<"wedge_endpoints"<<std::endl;
   for(int i=0; i<t_endpoints; i++)
      std::cout<<wedge_endpoints[i]<<" ";
   std::cout<<std::endl;

   std::cout<<"wedge_midpoints"<<std::endl;
   for(int i=0; i<t_endpoints-1; i++)
      std::cout<<wedge_midpoints[i]<<" ";
   std::cout<<std::endl;  
}
//end of class Wedge


/**
 * la classe WedgePartition
 */

//initialization of static variables
Long WedgePartition::compteur=0; 

Wedge* WedgePartition::wedge=0;

Img1dsl WedgePartition::left_line;
Img2dsl WedgePartition::cols;


/** 
 * initWedge: static method in order to initialize the wedge
 */
void WedgePartition::initWedge(const Double& M_horiz, const Double& M_vert, 
			       const Long& nbangles_perquad) {
   if(compteur==0)
      wedge=new Wedge(M_horiz,M_vert,nbangles_perquad);
}

/**
 * deleteWedge: static method so as to desallocate the wedge
 */
void WedgePartition::deleteWedge() {
   if(compteur==0)
      delete wedge;
}


//default constructor
WedgePartition::WedgePartition(){}

/**
 * WedgePartition: a constructor
 */
WedgePartition::WedgePartition(const Double& M_horiz, const Double& M_vert, 
			       const Long& nbangles_perquad) {
   initWedge(M_horiz,M_vert,nbangles_perquad);
   compteur++;
}

/**
 * the destructor
 */
WedgePartition::~WedgePartition() {
   compteur--;
   deleteWedge();
   deleteStaticData();
}

//desallocation of static data
void WedgePartition::deleteStaticData() {
   if (compteur==0) {
      left_line.Delete();
      cols.Delete();
   }
}

//method in order to print the caracteristics of the wedge part 
void WedgePartition::affiche() {
   Long k;
   std::cout<<"compteur="<<compteur<<std::endl;
   std::cout<<"wedge"<<std::endl;
   wedge->afficheWedge();
   std::cout<<"slope_wedge="<<slope_wedge<<std::endl;
   std::cout<<"width_wedge="<<width_wedge<<std::endl;
   std::cout<<"length_wedge="<<length_wedge<<std::endl;
  
   for(k=0; k<length_wedge; k++)
      std::cout<<"left_line["<<k<<"]="<<left_line[k]<<std::endl;
}

//reallocation of static data
void WedgePartition::reallocStaticData() {
   if(width_wedge>cols.Width())
      {
	 cols.Delete();
	 cols.New(left_line.Width(),width_wedge);  
      }
}

/**
 * init_coordX: initialization of coord
 */
void WedgePartition::init_coordX(const Double& M_horiz ,
				 const Img2dsl& X_XX,
				 Img2dsf& coord) {
   Long i;
   Long j;
   Double a=1/(Double)2;
   Double b;
   Double c;
  
  
   Double sw; //slope_wedge_lor  (lor=left or right)
   Double ml;  //mid_line_lor
   //ind_r is a shift of index
   //because the formula are unavailable for the RightCornerWedge
   Long ind_r=(subl==wedge->t_endpoints-1) ? subl-1 : subl;
  
   b=wedge->ord/(Double)
      (wedge->wedge_endpoints[1+ind_r]-wedge->wedge_endpoints[ind_r]);
   sw=(wedge->abs+1-wedge->wedge_midpoints[ind_r])/(Double)wedge->ord;
  
   for(j=0; j<length_wedge; j++) 
      {
	 ml=wedge->wedge_midpoints[ind_r]+sw*j;
	 for(i=0; i<width_wedge; i++)
	    {  
	       c=(X_XX[j][i]-ml)/(wedge->ord-j);
	       coord[j][i]=(float)(a+b*c);
	    }
      }
}
	
/**
 * calculWedgeWindow: calculate wedgeWindows
 * @param wl_left the left window of the left part
 * @param wr_right the right window of the right part
 */  
void WedgePartition::calculWedgeWindow(Img2dsf& coordX,
				       Img2dsf& coordY,
				       Img2dsf& wl_left,
				       Img2dsf& wr_right) {
   Img2dsf wr_left, wl_right; //not used
   wr_left.New(coordX.Size());
   wl_right.New(coordY.Size());
   Wedgewindow(coordX,wl_left,wr_left);
   Wedgewindow(coordY,wl_right,wr_right);
   wr_left.Delete();
   wl_right.Delete();
}

/**
 * init_cols: initialization of the attribute cols
 */
void WedgePartition::init_cols() {
   //variables of loop
   Long row,i;
   Long temp;
   for (i=0; i<width_wedge; i++)
      for (row=0; row<length_wedge; row++) {
	 temp=(i-(left_line[row]-left_line[0]))%width_wedge;
	 if (temp<0) temp+=width_wedge;  
	 cols[row][i]=left_line[row]+temp;
      }
}


/**
 * last step of decomposition for a WedgePart
 * a rotation and then an ifft 
 */
void WedgePartition::rotation_et_ifft(Img2dsf& padded_data_re, 
				      Img2dsf& padded_data_im, Img2dsf& x,
				      const Long& quadrant) {
   Img2dsf temp_re;
   Img2dsf temp_im;

   Img2dsf x_im;
   Long nb_pixels=x.Height()*x.Width();

   //allocation and initialization 
   temp_re.New(x.Size()); 
   temp_im.New(x.Size());
   x_im.New(x.Size()); 
 
   Long nb_quart_tour=-quadrant;
   QuartDeTour(padded_data_re,temp_re,nb_quart_tour);
   QuartDeTour(padded_data_im,temp_im,nb_quart_tour); 
 
   //ifft
   //x_im isn't used after but the operator FFTW needs it
   FFTW(temp_re,temp_im,x,x_im,-1);
   PMultCst(x,x,(float)(1/sqrt((Double)nb_pixels)));
  
   //desallocation
   temp_re.Delete();
   temp_im.Delete();
   x_im.Delete();
}


/**
 * fillCurv: to fill a part of curvelet matrix
 */
//wl_left and wr_right are const
//ind is the scale
void WedgePartition::fillCurv(Img2dsf** C, Img2dsf& wl_left, 
			      Img2dsf& wr_right,
			      Img2dsf& wrapped_data_re,
			      Img2dsf& wrapped_data_im,
			      const Long& quadrant,
			      const Long& ind, const Long& theta) {
   Long i; //variable of loop

   Img2dsf padded_data_re;
   Img2dsf padded_data_im;
   Img2dsf temp_zero;
   Img2dsf x;

   temp_zero.New(1,width_wedge);
   temp_zero=0;
  
   Long h_padded_data=2*length_wedge+1;
   Long w_padded_data=width_wedge;
   padded_data_re.New(h_padded_data,w_padded_data);
   padded_data_im.New(h_padded_data,w_padded_data);

   //if the number of rotation is odd,
   //the height becomes the width and reciprocally
   if(quadrant%2==1)
      x.New(w_padded_data,h_padded_data);
   else x.New(h_padded_data,w_padded_data);

   //updating of wrapped_data 
   PMult(wrapped_data_re,wl_left,wrapped_data_re);
   PMult(wrapped_data_im,wl_left,wrapped_data_im);
   PMult(wrapped_data_re,wr_right,wrapped_data_re);
   PMult(wrapped_data_im,wr_right,wrapped_data_im);

   //creation of padding_data
   for (i=0; i<length_wedge; i++) {
      memcpy(padded_data_re[i],wrapped_data_re[i],
	     w_padded_data*sizeof(Img2dsf::ValueType));
      memcpy(padded_data_im[i],wrapped_data_im[i],
	     w_padded_data*sizeof(Img2dsf::ValueType));
      memcpy(padded_data_re[i+length_wedge],temp_zero[0],
	     w_padded_data*sizeof(Img2dsf::ValueType));
      memcpy(padded_data_im[i+length_wedge],temp_zero[0],
	     w_padded_data*sizeof(Img2dsf::ValueType));
   }
   memcpy(padded_data_re[2*length_wedge],temp_zero[0], w_padded_data*sizeof(Img2dsf::ValueType));
   memcpy(padded_data_im[2*length_wedge],temp_zero[0], w_padded_data*sizeof(Img2dsf::ValueType));
  
  
   rotation_et_ifft(padded_data_re,padded_data_im,x,quadrant);
  
   //allocation of the curvelet for this scale ind and this orientation
   //theta
   C[ind][theta].New(x.Size());
  
   //save the curvelet image
   PAdd(x,x,C[ind][theta]);
  
   //desallocations
   x.Delete();
   temp_zero.Delete();
   padded_data_re.Delete();
   padded_data_im.Delete();
}

/**
 * fillWrappedData: to fill the variable wrapped_data for the scale scale
 *                  and the orientation theta 
 */
void WedgePartition::fillWrappedData(Img2dsf** C, 
				     Img2dsf& wrapped_data_re,
				     Img2dsf& wrapped_data_im,
				     const Long& scale,
				     const Long& theta,
				     const Long& quadrant) {
   Long i, j; //variables of loop

   Long nb_pixels=C[scale][theta].Height()*C[scale][theta].Width();
   Double norm;     //value of normalization  
   Img2dsf zero;
   Img2dsf fft_re, fft_im;
   Img2dsf rot_fft_re, rot_fft_im;
 
   fft_re.New(C[scale][theta].Size());
   fft_im.New(C[scale][theta].Size());
   //allocation of the image of rotation
   //if the number of rotation is odd,
   //the height becomes the width and reciprocally
   if (quadrant%2==1) {
      rot_fft_re.New(fft_re.Width(),fft_re.Height());
      rot_fft_im.New(fft_im.Width(),fft_im.Height());
   } else {
      rot_fft_re.New(fft_re.Size());
      rot_fft_im.New(fft_im.Size());
   }
   
   //fft
   zero.New(C[scale][theta].Size());
   zero=0;
   norm=1/sqrt((Double)nb_pixels);

   //fft
   FFTW(C[scale][theta],zero,fft_re,fft_im,1); 

   //normalization
   PMultCst(fft_re,fft_re,(float)norm);
   PMultCst(fft_im,fft_im,(float)norm);

   //rotation
   QuartDeTour(fft_re,rot_fft_re,quadrant); //rio
   QuartDeTour(fft_im,rot_fft_im,quadrant);
  
   //filling of wrapped_data
   /*
    * wrapped_data.Height()=C[scale][data]/2
    * wrapped_data.Width()=C[scale][theta]/2
    */
   for (i=0; i<width_wedge; i++)
      for (j=0; j<length_wedge; j++) {
	 wrapped_data_re[j][i]=rot_fft_re[j][i];
	 wrapped_data_im[j][i]=rot_fft_im[j][i];
      }
   
   //desallocation
   fft_re.Delete();
   fft_im.Delete();
   rot_fft_re.Delete();
   rot_fft_im.Delete();
   zero.Delete();
}


//fin de WedgePartition

/**
 * la classe RegularWedge
 */

//default constructor
RegularWedge::RegularWedge() : WedgePartition(){}

//destructor
RegularWedge::~RegularWedge() {
   mid_line_left_next.Delete();
}

//a constructor
RegularWedge::RegularWedge(const Double& M_horiz, const Double& M_vert, 
			   const Long& nbangles_perquad, const Long& subl)
   : WedgePartition(M_horiz,M_vert,nbangles_perquad) {
   this->subl=subl;
   initLengthWedge(M_vert);
   mid_line_left_next.New(length_wedge);
}

//a constructor
RegularWedge::RegularWedge(const Double& M_horiz, const Double& M_vert, 
			   const Long& nbangles_perquad)
   : WedgePartition(M_horiz,M_vert,nbangles_perquad) {
   subl=1;
   initLengthWedge(M_vert);
   mid_line_left_next.New(length_wedge);
}

//initialization of wrapped_XX
//wrapped_XX is a matrix of index 
void RegularWedge::init_wrapped_XX(Img2dsl& wrapped_XX) {
   Long row, columns; //variable of loop
   for(columns=0; columns<width_wedge; columns++)
      for(row=0; row<length_wedge; row++)
	 wrapped_XX[row][columns]=cols[row][columns];
}

//initialization of coordX
//and safeguard mid_line so as to avoid of operations are already made
void RegularWedge::init_coordX_save_mid_line(const Double& M_horiz ,
					     const Img2dsl& X_XX,
					     Img2dsf& coord) {
   Long i;
   Long j;
   Double a=1/(Double)2;
   Double b;
   Double c;  
   Double sw; //slope_wedge_lor  (lor=left or right)

   b=wedge->ord/(Double)
      (wedge->wedge_endpoints[1+subl]-wedge->wedge_endpoints[subl]);
   sw=(wedge->abs+1-wedge->wedge_midpoints[subl])/(Double)wedge->ord;
  
   for (j=0; j<length_wedge; j++) {
      mid_line_left_next[j]=(float)(wedge->wedge_midpoints[subl]+sw*j);
      for (i=0; i<width_wedge; i++) {  
	 c=(X_XX[j][i]-mid_line_left_next[j])/(wedge->ord-j);
	 coord[j][i]=(float)(a+b*c);
      }
   }
}

//initialization of the length of the wedge
void RegularWedge::initLengthWedge(const Double& M_vert) {
   length_wedge=wedge->ord-(Long)(floor(M_vert));
}

//initialization of width_wedge, slope_wedge and left_line
void RegularWedge::initWidthWedge_SlopeWedge_LeftLine() {
   Long k;
   width_wedge=wedge->wedge_endpoints[subl+1]-wedge->wedge_endpoints[subl-1]+1;
   slope_wedge=(wedge->abs+1-wedge->wedge_endpoints[subl])/(Double)wedge->ord;
   for(k=0; k<length_wedge; k++)
      left_line[k]=(Long)my_round(wedge->wedge_endpoints[subl-1]+slope_wedge*k);
}

//initialization of the wedge windows
void RegularWedge::initWedgeWindow(Img2dsf& wl_left, Img2dsf& wr_right,
				   const Double& M_horiz) {
   Long i,j; //variables of loop
   Double a,b,c; //variables in order to calculate coord_left
  
   Img2dsl wrapped_XX;
   Img2dsf coord_right, coord_left;

   //wrapped_XX is used to calculate coord
   wrapped_XX.New(length_wedge,width_wedge);

   //coord is used to calculate the wedge windows
   coord_right.New(length_wedge,width_wedge);
   coord_left.New(length_wedge,width_wedge);
   wrapped_XX=0;
  
   //initialization of wrapped_XX
   init_wrapped_XX(wrapped_XX);


   //initialization of coord_left
   if (subl==1) {
      subl--;
      init_coordX(M_horiz,wrapped_XX,coord_left);
      subl++;
   } else { //thanks to mid_line_left, we avoid some operations
      b=wedge->ord/(Double)
	 (wedge->wedge_endpoints[subl]-wedge->wedge_endpoints[subl-1]);
      a=1/2.0;
      for (j=0; j<length_wedge; j++) 
	 for (i=0; i<width_wedge; i++) {
	    c=(wrapped_XX[j][i]-mid_line_left_next[j])/(wedge->ord-j);
	    coord_left[j][i]=(float)(a+b*c);
	 }
   }
   
   //initialization of coord_right and saveguard of mid_line_right
   //for the following step, mid_line_right becomes mid_line_left
   init_coordX_save_mid_line(M_horiz,wrapped_XX,coord_right);
   
   //initialization of wedge windows
   calculWedgeWindow(coord_left,coord_right,wl_left,wr_right);
   
   //desallocation
   wrapped_XX.Delete();
   coord_right.Delete();
   coord_left.Delete();
}

/**
 * decompose : decomposition according to a regular wedge
 */
void RegularWedge::decompose(const Img2dsf& xhi_re, const Img2dsf& xhi_im,
			     Img2dsf** C, const Double& M_horiz, 
			     const Long& quadrant, const Long& ind, 
			     Long& theta) {
   Long row, columns; //variable of loop
   Img2dsf wrapped_data_re, wrapped_data_im;
   Img2dsf wl_left, wr_right;
   initWidthWedge_SlopeWedge_LeftLine();
   wrapped_data_re.New(length_wedge,width_wedge);
   wrapped_data_im.New(length_wedge,width_wedge);
   wrapped_data_re=0;
   wrapped_data_im=0;
   wl_left.New(length_wedge,width_wedge);
   wr_right.New(length_wedge,width_wedge);

   //allocations
   reallocStaticData();
   init_cols();
   theta++; //the following orientation
   initWedgeWindow(wl_left,wr_right,M_horiz);

   //initialization of wrapped_data
   for (columns=0; columns<width_wedge; columns++)
      for (row=0; row<length_wedge; row++) {
	 wrapped_data_re[row][columns]=xhi_re[row][cols[row][columns]-1];
	 wrapped_data_im[row][columns]=xhi_im[row][cols[row][columns]-1];
      }

   //saveguard of the curvelet image at this scale ind and the
   //orientation theta
   fillCurv(C,wl_left,wr_right,wrapped_data_re,wrapped_data_im,
	    quadrant,ind,theta);
  
   //desallocation
   wrapped_data_re.Delete();
   wrapped_data_im.Delete();
   wl_left.Delete();
   wr_right.Delete();
}


//unwrappind data 
//a method for fict
void RegularWedge::unwrappingData(const Img2dsf& wrapped_data,
				  Img2dsf& Xj) {
   Long i, row; //variables of loop
   Img2dsf *clone_Xj=(Img2dsf*)Xj.Clone();
  
   //unwrappind data
   for (i=0; i<width_wedge; i++)
      for (row=0; row<length_wedge; row++) {
	 Xj[row][cols[row][i]-1]=(*clone_Xj)[row][cols[row][i]-1]
	    +wrapped_data[row][i];
	 //code matlab doesn't mean 
	 //Xj[row][cols[i]]+=wrapped_data[row][i];
	 //no accumulation
      }
   
   //desallocation of pointer
   delete clone_Xj;
}

//recompose: reconstruction according to a regular wedge
//a method for fict
void RegularWedge::recompose(Img2dsf** C, Img2dsf& Xj_re, Img2dsf& Xj_im, 
			     const Long& scale, const Long& quadrant,
			     const Double& M_horiz,
			     Long& theta) {
   Img2dsf wrapped_data_re, wrapped_data_im;
   Img2dsf wl_left, wr_right;
   
   //allocations and initializations
   initWidthWedge_SlopeWedge_LeftLine();
  
   wrapped_data_re.New(length_wedge,width_wedge);
   wrapped_data_im.New(length_wedge,width_wedge);
   wrapped_data_re=0;
   wrapped_data_im=0;

   wl_left.New(length_wedge,width_wedge);
   wr_right.New(length_wedge,width_wedge);

   reallocStaticData();
  
   init_cols();

   theta++; //the following orientation
  
   //initialization of wrapped data
   initWedgeWindow(wl_left,wr_right,M_horiz);
   fillWrappedData(C,wrapped_data_re,wrapped_data_im,scale,theta,quadrant); 
  
   PMult(wrapped_data_re,wl_left,wrapped_data_re);
   PMult(wrapped_data_im,wl_left,wrapped_data_im);
   PMult(wrapped_data_re,wr_right,wrapped_data_re);
   PMult(wrapped_data_im,wr_right,wrapped_data_im);
  
   //unwrapping data
   unwrappingData(wrapped_data_re,Xj_re);
   unwrappingData(wrapped_data_im,Xj_im);
  
   //desallocation
   wrapped_data_re.Delete();
   wrapped_data_im.Delete();
   wl_left.Delete();
   wr_right.Delete();
} 

//end of RegularWedge


/**
 * la classe WedgeSide
 */

//initialization of the static data
Img2dsl WedgeSide::admissible_cols;

//le constructeur par defaut
WedgeSide::WedgeSide():WedgePartition(){}

//a constructor
WedgeSide::WedgeSide(const Double& M_horiz, const Double& M_vert, 
		     const Long& nbangles_perquad)
   :WedgePartition(M_horiz,M_vert,nbangles_perquad) {}

//the destructor
WedgeSide::~WedgeSide() {
   admissible_cols.Delete();
}

/**
 * initLengthWedge: initialization of length of wedge 
 */
void WedgeSide::initLengthWedge(const Double& M_vert) {
   length_wedge=wedge->ord-(Long)(floor(M_vert))
      +(Long)ceil((Double)wedge->first_wedge_endpoint_vert/4);
}


//realoocation of static data
void WedgeSide::reallocStaticData() {
   if (width_wedge>cols.Width()) {
      cols.Delete();
      admissible_cols.Delete();
      cols.New(left_line.Width(),width_wedge);
      admissible_cols.New(left_line.Width(),width_wedge);
   }
}

//initialisation of wrapped_XX
//wrapped_XX is a matrix of index
void WedgeSide::init_wrapped_XX(Img2dsl& wrapped_XX) {
   Long row, columns; //variable of loop
   for(columns=0; columns<width_wedge; columns++)
      for(row=0; row<length_wedge; row++)
	 wrapped_XX[row][columns]=admissible_cols[row][columns]+1;
}

//initialization of the attribute admissible
//in the case of fict, it avoids the same operations several times
//see unwrappingData and initWedgeWindow 
void WedgeSide::init_admissible_cols() {
   Long row,i; //variables of loop
   for(i=0; i<width_wedge; i++)
      for(row=0; row<length_wedge; row++)
	 admissible_cols[row][i]=(Long)my_round(1/2.0*(cols[row][i]+1
						       +abs(cols[row][i]-1)))-1;
}

//calculate C1 and C2
//C1 and C2 are used to calculate coord_corner
//coord_corner is used to initialize wedge windows
void WedgeSide::calcul_Ci(Double&,Double&){}

/**
 * initialisation of coord_corner
 */
void WedgeSide::calcul_coord_corner(const Img2dsl& X_XX,
				    const Double& C1, const Double& C2,
				    Img2dsf& coord_corner){}

/**
 * initialization of wedge windows
 */
void WedgeSide::initWedgeWindow(Img2dsf& wl_left, Img2dsf& wr_right,
				const Double& M_horiz) {
   Img2dsl wrapped_XX;
   Img2dsf coord, coord_corner;
   Double C1, C2;
  
   //initialization of coord 
   //if WedgeSide is LeftCornerWedge, coord is right else it is left  
   wrapped_XX.New(length_wedge,width_wedge);
   coord.New(length_wedge,width_wedge);
   coord_corner.New(length_wedge,width_wedge);
   wrapped_XX=0;
   init_wrapped_XX(wrapped_XX); 
   init_coordX(M_horiz,wrapped_XX,coord);
  
   //initialization of coord_corner
   calcul_Ci(C2,C1);
   calcul_coord_corner(wrapped_XX,C1,C2,coord_corner);
  
   //WedgeSide is LeftCornerWedge or RightCornerWedge?
   //the parameters are not the same order
   if(subl==0) 
      calculWedgeWindow(coord_corner,coord,wl_left,wr_right);
   else calculWedgeWindow(coord,coord_corner,wl_left,wr_right);
  
   //desallocation
   wrapped_XX.Delete();
   coord_corner.Delete();
   coord.Delete();
}


/**
 * decompose: decomposition according to a side of wedge
 */
void WedgeSide::decompose(const Img2dsf& xhi_re,const Img2dsf& xhi_im, 
			  Img2dsf** C, const Double& M_horiz, 
			  const Long& quadrant, const Long& ind, Long& theta) {
   Long row, columns; //variable of loop
   Img2dsf wrapped_data_re, wrapped_data_im;
   Img2dsf wl_left, wr_right;
 
   //allocations and initializations
   initWidthWedge_SlopeWedge_LeftLine();
  
   wrapped_data_re.New(length_wedge,width_wedge);
   wrapped_data_im.New(length_wedge,width_wedge);
   wrapped_data_re=0;
   wrapped_data_im=0;

   wl_left.New(length_wedge,width_wedge);
   wr_right.New(length_wedge,width_wedge);

   reallocStaticData();
  
   init_cols();
   init_admissible_cols();
  
   theta++; //the following angle
   initWedgeWindow(wl_left,wr_right,M_horiz);
  
   //initialization of wrapped_data
   for (columns=0; columns<width_wedge; columns++)
      for (row=0; row<length_wedge; row++) {
	 if(cols[row][columns]>0) {
	    wrapped_data_re[row][columns]=
	       xhi_re[row][admissible_cols[row][columns]];
	    wrapped_data_im[row][columns]=
	       xhi_im[row][admissible_cols[row][columns]];
	 }
      }

   fillCurv(C,wl_left,wr_right,wrapped_data_re,wrapped_data_im,
	    quadrant,ind,theta);
  
   //desallocation
   wrapped_data_re.Delete();
   wrapped_data_im.Delete();
    
   wl_left.Delete();
   wr_right.Delete();
}

/**
 * recompose: reconstruction of image
 * step: WedgeSide (left or right) in the angular recomposition
 */
void WedgeSide::recompose(Img2dsf** C, Img2dsf& Xj_re, Img2dsf& Xj_im, 
			  const Long& scale, const Long& quadrant,
			  const Double& M_horiz,
			  Long& theta) {
   Img2dsf wrapped_data_re, wrapped_data_im;
   Img2dsf wl_left, wr_right;
  
   initWidthWedge_SlopeWedge_LeftLine();
  
   wrapped_data_re.New(length_wedge,width_wedge);
   wrapped_data_im.New(length_wedge,width_wedge);
   wrapped_data_re=0;
   wrapped_data_im=0;

   wl_left.New(length_wedge,width_wedge);
   wr_right.New(length_wedge,width_wedge);

   reallocStaticData();
  
   init_cols();
   init_admissible_cols();

   theta++;
  
   //initialization of wrapped data
   initWedgeWindow(wl_left,wr_right,M_horiz);
   fillWrappedData(C,wrapped_data_re,wrapped_data_im,scale,theta,quadrant); 

   PMult(wrapped_data_re,wl_left,wrapped_data_re);
   PMult(wrapped_data_im,wl_left,wrapped_data_im);
   PMult(wrapped_data_re,wr_right,wrapped_data_re);
   PMult(wrapped_data_im,wr_right,wrapped_data_im);
  
   //unwrapping data
   unwrappingData(wrapped_data_re,Xj_re);
   unwrappingData(wrapped_data_im,Xj_im);
  
   //desallocation
   wl_left.Delete();
   wr_right.Delete();
   wrapped_data_re.Delete();
   wrapped_data_im.Delete();
} 

//end of WedgeSide


/**
 * methods of LeftCornerWedge
 */

//default constructor
LeftCornerWedge::LeftCornerWedge() : WedgeSide() {}

//the destructor
LeftCornerWedge::~LeftCornerWedge() {}

//a constructor
LeftCornerWedge::LeftCornerWedge(const Double& M_horiz, const Double& M_vert, 
				 const Long& nbangles_perquad)
   :WedgeSide(M_horiz,M_vert,nbangles_perquad) {
   subl=0;
   initLengthWedge(M_vert);

   //LeftCorner is the first to be allocated  
   left_line.New(length_wedge);
   //therefore, the test compteur==1 isn't used

   initWidthWedge_SlopeWedge_LeftLine();
 
   //LeftCorner is the first to be allocated 
   cols.New(length_wedge,width_wedge);
   admissible_cols.New(length_wedge,width_wedge);
   //therefore, the test compteur==1 isn't used
}

/**
 * initWidthWedge_SlopeWedge_LeftLine: 
 *        initialization of width_wedge slope_wedge and left_line
 */
void LeftCornerWedge::initWidthWedge_SlopeWedge_LeftLine() {
   Long k;
   width_wedge=wedge->wedge_endpoints[1]+wedge->wedge_endpoints[0]-1; 
   slope_wedge=(wedge->abs+1-wedge->wedge_endpoints[0])/(Double)wedge->ord;
   for(k=0; k<length_wedge; k++)
      left_line[k]=(Long)my_round(2-wedge->wedge_endpoints[0]+slope_wedge*k);
}



/**
 * calculAdmissibleCols: find valid columns
 */
void LeftCornerWedge::calculAdmissibleCols(const Img1dsl& cols, 
					   Img1dsl& admissible_cols, 
					   const Long& i) {
   admissible_cols[i]=(Long)my_round(1/2.0*(cols[i]+1+abs(cols[i]-1)))-1;
}



/**
 * calcul_Ci: calculate C1 and C2 that used to calculate coord_corner
 */
void LeftCornerWedge::calcul_Ci(Double& C2, Double& C1) {
   //variables in order to calculate C2
   Double a21=2*wedge->abs/(Double)(wedge->wedge_endpoints[0]-1)-1;
   Double a22 =2*wedge->ord/(Double)(wedge->first_wedge_endpoint_vert-1)-1;
   Double b21=1/a21;
   Double b22=1/a22;

   C2=1/(b21+b22);
   C1=C2/a22;
}

/**
 * calcul_coord_corner: calculate coord_corner using to
 *                      initialize a wedgewindow
 */
void LeftCornerWedge::calcul_coord_corner(const Img2dsl& X_XX,
					  const Double& C1, const Double& C2,
					  Img2dsf& coord_corner) {
   Long largeur=X_XX.Width();
   Long hauteur=X_XX.Height();

   //variables of loop
   Long i,j;
   //temporary variables used to calculate the values of coord_corner
   Double a;
   Double b;
   Double c;
   Double d;

   for (i=0; i<largeur; i++)
      for (j=0; j<hauteur; j++) {
	 a=(X_XX[j][i]-1)/(Double)wedge->abs;
	 b=j/(Double)wedge->ord;
	 c=a-b;
	 if(c==2) {//this condition is difficult to test
	    //we don't reinitialize this variable like in matlab because
	    //then, we don't use this variable
	    a=X_XX[j][i]/(Double)wedge->abs; 
	    c=a-b;
	 } //to avoid division by zero

	 d=2-(a+b);
	 coord_corner[j][i]=(float)(C1+C2*c/d);
      }
}

//unwrapping data
//method for fict
void LeftCornerWedge::unwrappingData(const Img2dsf& wrapped_data,
				     Img2dsf& Xj) {
   Long i, row; //variable of loop

   Img2dsf *clone_Xj=(Img2dsf*)Xj.Clone();
  
   //unwrappind data
   for(i=0; i<width_wedge; i++)
      for(row=0; row<length_wedge; row++) {
	 Xj[row][admissible_cols[row][i]]=
	    (*clone_Xj)[row][admissible_cols[row][i]]+wrapped_data[row][i];
	 //code matlab doesn't mean 
	 //Xj[row][admissible_cols[i]]+=wrapped_data[row][i];
	 //no accumulation
      }
  
   //desallocation of pointer
   delete clone_Xj;
}

//fin de LeftCornerWedge

/**
 * Methods of RightCornerWedge
 */

//default constructor
RightCornerWedge::RightCornerWedge() : WedgeSide() {}

//the destructor
RightCornerWedge::~RightCornerWedge() {}

//a constructor
RightCornerWedge::RightCornerWedge(const Double& M_horiz, 
				   const Double& M_vert, 
				   const Long& nbangles_perquad)
   :WedgeSide(M_horiz,M_vert,nbangles_perquad) {
   subl=nbangles_perquad-1;
   initLengthWedge(M_vert);
   initWidthWedge_SlopeWedge_LeftLine();
   init_cols();
   init_admissible_cols();
}

/**
 * initWidthWedge_SlopeWedge_LeftLine: 
 *        initialization of width_wedge slope_wedge and left_line
 */
void RightCornerWedge::initWidthWedge_SlopeWedge_LeftLine() {
   Long k;
   Long der=wedge->t_endpoints-1;
  
   width_wedge=4*wedge->abs+3-wedge->wedge_endpoints[der]
      -wedge->wedge_endpoints[der-1]; 
   slope_wedge=(wedge->abs+1-wedge->wedge_endpoints[der])/(Double)wedge->ord;
   for(k=0; k<length_wedge; k++)
      left_line[k]=(Long)my_round(wedge->wedge_endpoints[der-1]+slope_wedge*k);
}

/**
 * calculAdmissibleCols: find valid columns
 */
void RightCornerWedge::calculAdmissibleCols(const Img1dsl& cols, 
					    Img1dsl& admissible_cols, 
					    const Long& i) {
   Long temp=2*wedge->abs+1;
   admissible_cols[i]=(Long)my_round(1/2.0*(cols[i]+temp+abs(cols[i]-temp)))-1;
}


/**
 * calcul_Ci: calculate C1 and C2 that used to calculate coord_corner
 */
void RightCornerWedge::calcul_Ci(Double& C2, Double& C1) {
   const Long der_elt=wedge->t_endpoints-1;
   //variables pour le calcul de C2
   const Double a21=2*wedge->abs/(Double)(wedge->wedge_endpoints[der_elt]-1)-1;
   const Double a22 =2*wedge->ord/
      (Double)(wedge->first_wedge_endpoint_vert-1)-1;
   const Double b22=1/a22;
  
   C2=-1/(a21+b22);
   C1=-C2*a21;
}

/**
 * calcul_coord_corner: calculate coord_corner
 * coord_corner is used to calculate a wedge window  
 */
void RightCornerWedge::calcul_coord_corner(const Img2dsl& X_XX,
					   const Double& C1, const Double& C2,
					   Img2dsf& coord_corner) {
   Long largeur=X_XX.Width();
   Long hauteur=X_XX.Height();

   //variables of loop
   Long i,j;

   //temporary variables used to calculate the values of coord_corner
   Double a;
   Double b;
   Double c;
   Double d;

   //allocation 
   coord_corner.New(hauteur,largeur);
  
   //calculation of coord_corner
   for(i=0; i<largeur; i++)
      for(j=0; j<hauteur; j++) {
	 a=(X_XX[j][i]-1)/(Double)wedge->abs;
	 b=j/(Double)wedge->ord;
	 c=a-b;
	 if(c==0) { //to avoid division by zero
	    a=(X_XX[j][i]-2)/(Double)wedge->abs;
	    c=a-b;
	 }
	
	 d=2-(a+b);
	 coord_corner[j][i]=(float)(C1+C2*d/c);
      }
}

/**
 * Unwrapping data
 */
void RightCornerWedge::unwrappingData(const Img2dsf& wrapped_data,
 				      Img2dsf& Xj) {
   Long i, row; //variables of loop
   Img2dsf *clone_Xj=(Img2dsf*)Xj.Clone();
  
   //unwrappind data
   //we must begin by the end (cf matlab commentary)
   for (i=width_wedge-1; i>-1; i--)
      for (row=0; row<length_wedge; row++) {
	 //warning warning warning
	 Xj[row][admissible_cols[row][i]]=
	    (*clone_Xj)[row][admissible_cols[row][i]]+wrapped_data[row][i];
	 //code matlab doesn't mean 
	 //Xj[row][admissible_cols[i]]+=wrapped_data[row][i];
	 //no accumulation
	 //end warning 
	 /**
	  * matlab commentary
	  * "We use the following property: in an assignment
	  *  A(B)=C where B and C are vectors, if some value
	  *  x repeats in B, then the last occurrence of wx is the
	  *  one corresponding to the eventual assignment"
	  */
      }
  
   //desallocation of pointer
   delete clone_Xj;
}
//end of RightCornerWedge


/**
 * the class FoldingMatrix
 */
//default constructor
FoldingMatrix::FoldingMatrix(){}

//a constructor
FoldingMatrix::FoldingMatrix(const Long& shift_1, const Long& shift_2)
   : shift_1(shift_1), shift_2(shift_2) {}

//
FoldingMatrix::FoldingMatrix(const Long& N1, const Long& N2, const Double& M1, const Double& M2) {
   shift_1=(Long)(floor(2*M1)-floor(N1/2.0)); 
   shift_2=(Long)(floor(2*M2)-floor(N2/2.0)); 
}

//destructor
FoldingMatrix::~FoldingMatrix(){}


/**
 * folding: folding back onto N1-by-N2 matrix
 * matrix are here 2D images 
 * X : an image that is in frequency domain
 * (N1,N2) size of the original image 
 * N1 is the height
 * N2 is the width
 */
void FoldingMatrix::folding(const Long& N1, const Long& N2, Img2dsf& X) {
   //variables of loop
   Long i,j;
   Long ki,kj;

   //shifts
   Long decalage2m=N2-shift_2; //m for minus
   Long decalage2p=N2+shift_2; //p for plus
   Long decalage1m=N1-shift_1; 
   Long decalage1p=N1+shift_1;
   Long hauteur=X.Height();
   Long largeur=X.Width();
   Img2dsf* cloneX;  

   //a temporary image in order to update X
   Img2dsf Y;
   Y.New(X.Size());
  
   for (i=0; i<N2; i++)
      for (j=0; j<hauteur; j++)
	 Y[j][i]=X[j][i+shift_2];
      
   for (i=0; i<shift_2; i++)
      for (j=0; j<hauteur; j++) {
	 ki=decalage2m+i;
	 Y[j][ki]=Y[j][ki]+X[j][i];
      }

   for (i=0; i<shift_2; i++)
      for (j=0; j<hauteur; j++)
	 Y[j][i]+=X[j][decalage2p+i];

   for (i=0; i<largeur; i++)
      for (j=0; j<N1; j++)
	 X[j][i]=Y[j+shift_1][i];

   for (i=0; i<largeur; i++)
      for (j=0; j<shift_1; j++) {
	 kj=decalage1m+j;
	 X[kj][i]+=Y[j][i];
      }
   
   for (i=0; i<largeur; i++)
      for (j=0; j<shift_1; j++)
	 X[j][i]+=Y[decalage1p+j][i];
   
   
   cloneX=(Img2dsf*)(X.Clone());
   X.Delete();
   PExtractSubImage(*cloneX,X,0,0,N1,N2);
   
   //desallocation
   delete cloneX;
   Y.Delete();
}
//end of class FoldingMatrix

#endif
