/* -*- mode: c++; c-basic-offset: 3 -*-
 *
 * 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/
 */

/**
 * Projet 3A : WAVEATOM transform
 * @author Mahmoud Ghoniem 
 *
 */

/*
 * @file g.cpp
 * @brief function Villemoe's construction
 *
 * NB : G is only for test.
 *      What is used by other operators is the function g
 *
 * This file inclues several functions:
 * - beta
 * - hf
 * - sf
 */

#include <math.h>
#include <complex>
using namespace std;
#include "complexe.h"
using namespace pandore;

// modulus function
float modulo(float w, float p){ 
  return p!=0 ? w-p*floor(w/p):w;
}

/****************
 * Function beta
 ****************/
Img1dsf beta(Img1dsf x){
  Img1dsf r(x.Props());
  r=0;

  for (int k=0; k<r.Width(); k++)
    r[k] = x[k]*x[k]*x[k]*x[k] * (35.F - 84.F*x[k] + 70.F*x[k]*x[k] - 20.F*x[k]*x[k]*x[k]);

  return r;
}

// version for floats
float beta(float x){
  return x*x*x*x *(35.F - 84.F*x + 70.F*x*x - 20.F*x*x*x);
}

/***************
 * Function hf
 ***************/
Img1dsf hf (Img1dsf w){
  Img1dsf r(w.Props());
  r=0;

  for (int k=0; k<w.Width(); k++){
    w[k] = modulo(w[k]+M_PI, 2*M_PI) - M_PI;
    w[k] = abs(w[k]);
      
    if (w[k] <= M_PI/3)
      r[k] = M_SQRT2;
    else
      if (w[k] >= 2*M_PI/3)
	r[k] = 0;
      else
	r[k] = M_SQRT2 * cos(M_PI/2 * beta(3*w[k]/M_PI-1));
  }
  return r;
}

// hf with float parameter
float hf (float w){
  float r = 0;
  w = modulo(w+M_PI , 2*M_PI) - M_PI;
  w = abs(w);

  
  if (w <= M_PI/3) 	return M_SQRT2;
  if (w >= 2.F*M_PI/3)	return 0;
  
  r = M_SQRT2 * cos(M_PI/2 * beta(3.F*w/M_PI-1));    
  return r;
}

/**************
 * Function sf
 **************/
Img1dsf sf (Img1dsf w){
  Img1dsf r(w.Props());
  r=0;
  
  Img1dsf aw(w.Props());

  for (int k=0; k<w.Width(); k++)
    {
      aw[k]= abs(w[k]);
     
      if(aw[k]<=2.F*M_PI/3 || aw[k] > 8.F*M_PI/2)
	r[k] = 0;
  
      if(aw[k]>=2.F*M_PI/3 && aw[k]<=4.F*M_PI/3)
	r[k] = hf(w[k]/2+M_PI)*M_SQRT1_2;
    
      if(aw[k]>=4.F*M_PI/3 && aw[k]<=8.F*M_PI/3)
	r[k] = hf(w[k]/4)*M_SQRT1_2;
    }
  return r;
}

// sf with float parameter
float sf (float w){
  float aw,r = 0;
  aw = abs(w);
     
  if(aw <= 2.F*M_PI/3 || aw > 8.F*M_PI/2)
    r = 0;
  
  if(aw >= 2.F*M_PI/3 && aw <= 4.F*M_PI/3)
    r = hf(w/2+M_PI)*M_SQRT1_2;
    
  if(aw >= 4.F*M_PI/3 && aw <= 8.F*M_PI/3)
    r = hf(w/4)*M_SQRT1_2;
  
  return r;
}


/*******************
 * Function g
 *
 * @param w Img1dsf
 *******************/
Img1dsf g(Img1dsf w){
  Img1dsf r(w.Props());
  r=0;
      
  for (int k=0; k<w.Width(); k++)
    if(w[k] < 5.F*M_PI/6 && w[k] > -7.F*M_PI/6)
      r[k] = abs(sf(w[k]-3.F*M_PI/2));

  return r;
}

// g with float parameter
float g(float w)
{
  float r=0;
  if(w < 5*M_PI/6 && w > -7*M_PI/6)  // -3.66 < x < 2.61
    r = abs(sf(w-3*M_PI/2));
  return r;
}

/**
 * Operator
 */
Errc G(const Img1dsf &ims, Img1dsf &imd) {
  Img1dsf tmp(ims.Props());
  for(int k=0; k<256; k++)
    tmp[k]=(k+1)*2*M_PI/256;
  
  Img1dsf out(ims.Props());
  out = g(ims);
  cout << "g(0) = " << out[0]<<endl;
  out.SaveFile("out.pan");
  return SUCCESS;
}

#ifdef MAIN
#define USAGE   "usage: %s [im_in|-] [im_out|-]"
#define PARC    0
#define FINC    0
#define FOUTC   0
#define MASK    0

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 mask.
   Pobject *objout[FOUTC+1];	// The output object unmasked by mask.
   Pobject *objd[FOUTC+1];	// The result object.
   char *parv[PARC+1];		// The input parameters.
  
   ReadArgs(argc,argv,PARC,FINC,FOUTC,&mask,objin,objs,objout,objd,parv,USAGE,MASK);
   switch(objs[0]->Type()){
   case Po_Img1dsf :{
      Img1dsf* const ims=(Img1dsf*)objs[0];
      objd[0]=new Imx2dsf(ims->Props());
      Img1dsf* const imd=(Img1dsf*)objd[0];
     
      result=G(*ims,*imd);
   }break;
   default :
      PrintErrorFormat(objin,FINC);
      result =FAILURE;
   }
  
   if (result)
      WriteArgs(argc,argv,PARC,FINC,FOUTC,&mask,objin,objs,objout,objd,MASK);
   Exit(result);
   return 0;
}

#endif
