/* Ce fichier contient des fonction de calculs sur les contours :
     - mesures sur contour binaire
     - filtrage suivant les mesures binaires
     - mesures sur objet en niveau de gris
*/

#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "pile.h"
#include "vecteur.h"
#include "vectint.h"
#include "liste.h"
extern "C"
{
#include "image.h"
#include "grille.h"
#include "r.h"
#include "contour.h"
}


int Aire(Liste *con)
/***************************************************/
/***   Calcul de l'aire a partir du contour      ***/
/***************************************************/
{
  int i,taille,x,y,avant,aire=0;
  char*m;
  float ff;

  m=con->Lire(&x,&y,&taille,&ff);
  if (taille==1) return 1;
  avant=m[taille-1];

  for(i=0;i<taille;i++)
  {
	 if(m[i]==0)        { if((avant==4)||(avant==5)) aire++;
    							 else  if((avant==0)||(avant==1)||(avant==6)||(avant==7))aire-=x-1;
                         avant=0;
                       }
	 else if (m[i]==1)  { if (avant==5) aire++;
    							 else if((avant==0)||(avant==1)||(avant==6)||(avant==7))	aire-=x-1;
                         x++;
                         avant=1;
                        }
	 else if (m[i]==2)  { if((avant==0)||(avant==1)||(avant==6)||(avant==7)) aire-=x-1;
                         x++;
                         avant=2;
                       }
	 else if (m[i]==3)  { if((avant==7)||(avant==0)||(avant==1)) aire++;
    							 else if((avant==2)||(avant==5)||(avant==3)||(avant==4)) aire+=x;
                         x++;
                         avant=3;
                       }
	 else if (m[i]==4)  { if((avant==2)||(avant==3)||(avant==4)||(avant==5)) aire+=x;
    							 else if((avant==1)||(avant==0)) aire++;
                         avant=4;
                       }
	 else if (m[i]==5)  { if((avant==2)||(avant==3)||(avant==4)||(avant==5)) aire+=x;
    							 else if((avant==1)||(avant==0)) aire++;
                         x--;
                         avant=5;
                       }
	 else if (m[i]==6)  { if((avant==2)||(avant==3)||(avant==4)||(avant==5)) aire+=x;
                         x--;
                         avant=6;
    							}
	 else if (m[i]==7)  { if((avant==0)||(avant==1)||(avant==6)||(avant==7)) aire-=x-1;
    							 else if((avant==3)||(avant==4)||(avant==5)) aire++;
                         x--;
                         avant=7;
                       }
  }
return aire;
}


int Perimetre(Liste *con)
/***********************************************************/
/***  Calcul du perimetre à partir du contour            ***/
/***********************************************************/
{
  int i,taille,x,y,perim=0; char*m; float ff;
  m=con->Lire(&x,&y,&taille,&ff);

  for(i=0;i<taille;i++)
  {
	 if(m[i]%2==0) { perim+=5; } else { perim+=7; }
  }
  return (perim/5);
}



float Niveau(Liste *con)
/************************************/
/***    Retour du niveau de gris du contour ***/
/************************************/
{
  int taille,x,y; float ff;
  con->Lire(&x,&y,&taille,&ff);
  return (ff);
}


void PointCG(Liste *con,float *XCG, float *YCG, Fenetre *fenetre,float *dMin,float *dMax,int drapeau)
/***************************************************************************************************/
/*** Calcul des valeurs suivantes :
      - (XCG,YCG) centre de gravite
      - fenetre  fenêtre circonsrite
      - si fenetre==NULL, pas de calcul de la fenêtre
      - dMin,dMax distances min et max par rapport au centre de gravité
      - si dMin==NULL  pas de calcul de dMin
      - si dMax==NULL  pas de calcul de dMax
*/
{
  int i,j,a,taille,x,y,inf_x,sup_x,inf_y,sup_y,y_rel,ini_x,ini_y,dim_x,dim_y;
  char*m;
  float ff,max,min,temp;
  double sx,sy;
  Image imC,imD; Reel **grille_imD; Liste supp;

  m=con->Lire(&x,&y,&taille,&ff); ini_x=x;ini_y=y;
  sup_y=inf_y=y; sup_x=inf_x=x;
  if (taille>1) for(i=0;i<taille;i++)
  {
	if(m[i]==0)        { y++;      if(y>sup_y){ sup_y=y; } }
	else if (m[i]==1)  { x++; y++; if(x>sup_x){ sup_x=x; } if(y>sup_y){ sup_y=y; } }
	else if (m[i]==2)  { x++;      if(x>sup_x){ sup_x=x; } }
	else if (m[i]==3)  { x++; y--; if(x>sup_x){ sup_x=x; } if(y<inf_y){ inf_y=y; } }
	else if (m[i]==4)  { y--;      if(y<inf_y){ inf_y=y; } }
	else if (m[i]==5)  { x--; y--; if(x<inf_x){ inf_x=x; } if(y<inf_y){ inf_y=y; } }
	else if (m[i]==6)	{ x--;      if(x<inf_x){ inf_x=x; } }
	else if (m[i]==7)  { x--; y++; if(x<inf_x){ inf_x=x; } if(y>sup_y){ sup_y=y; } }
  }
  y_rel=ini_y-inf_y; supp.Insertion(1,y_rel+1,taille,m,ff);

  imC=CreeImCont(NULL,&supp);

  dim_x=sup_x-inf_x+1;  dim_y=sup_y-inf_y+1;
  if (fenetre!=NULL)
    {
    fenetre->origine.x=inf_y;
    fenetre->origine.y=inf_x;
    fenetre->taille.x=dim_y;
    fenetre->taille.y=dim_x;
    }

  imD=CreeImageSimple(NULL,T_REEL,V_CARTE,dim_y+2,dim_x+2);
  if (drapeau==0) imD=TraceImCont(imC,imD,imD);
  else imD=TraceContour(imC,imD,imD);
  LibereImage(imC);
  grille_imD=(Reel **)CreeGrille(imD,Z_FENETRE);
  sx=sy=a=0;
  for(i=1;i<dim_x+1;i++)
  {for(j=1;j<dim_y+1;j++) if(grille_imD[i][j]==ff) { sy+=j;sx+=i; a++; }}

  if (a!=0)	{*YCG=sy/a;*XCG=sx/a;}
  else 		{*YCG=inf_y;*XCG=inf_x;}

  LibereGrille(grille_imD);
  LibereImage(imD);

  if (dMin!=NULL || dMax!=NULL)
   {
   x=1;y=1+y_rel;
   max=min=(x-(*XCG))*(x-(*XCG))+(y-(*YCG))*(y-(*YCG));
   if (taille>1)
   for(i=0;i<taille;i++)
    {
	 if(m[i]==0)
	  { y++;   temp=(x-(*XCG))*(x-(*XCG))+(y-(*YCG))*(y-(*YCG));
     if (temp>max) max=temp;
     if(temp<min) min=temp;
     }
	 else if (m[i]==1)
	  { x++; y++;  temp=(x-(*XCG))*(x-(*XCG))+(y-(*YCG))*(y-(*YCG));
     if (temp>max) max=temp;
     if(temp<min) min=temp;
     }
	 else if (m[i]==2)
	  { x++;  temp=(x-(*XCG))*(x-(*XCG))+(y-(*YCG))*(y-(*YCG));
     if (temp>max) max=temp;
     if(temp<min) min=temp;
     }
	 else if (m[i]==3)
	  { x++; y--;temp=(x-(*XCG))*(x-(*XCG))+(y-(*YCG))*(y-(*YCG));
     if (temp>max) max=temp;
     if(temp<min) min=temp;
     }
	 else if (m[i]==4)
	  { y--; temp=(x-(*XCG))*(x-(*XCG))+(y-(*YCG))*(y-(*YCG));
     if (temp>max) max=temp;
     if(temp<min) min=temp;
     }
	 else if (m[i]==5)
	  { x--; y--;temp=(x-(*XCG))*(x-(*XCG))+(y-(*YCG))*(y-(*YCG));
     if (temp>max) max=temp;
     if(temp<min) min=temp;
     }
	 else if (m[i]==6)
	  { x--;temp=(x-(*XCG))*(x-(*XCG))+(y-(*YCG))*(y-(*YCG));
     if (temp>max) max=temp;
     if(temp<min) min=temp;
     }
	 else if (m[i]==7)
	  { x--; y++;temp=(x-(*XCG))*(x-(*XCG))+(y-(*YCG))*(y-(*YCG));
     if (temp>max) max=temp;
     if(temp<min) min=temp;
     }
    }

   if (dMin!=NULL) *dMin=sqrt(min);
   if (dMax!=NULL) *dMax=sqrt(max);
   }
 if (a!=0)
	{
	*YCG=(sx/a)+ini_x-1;
	*XCG=(sy/a)+inf_y-1;
	}
else
	{
   *YCG=0;
	*XCG=0;
   }
}

/********************************************************************/
/***   Routine  qui a en entrée une image source avec derriere    ***/
/***   les contours et un paramètre int et qui returne l' image   ***/
/***   sans les regions qui ont une aire inferieur à le paramètre ***/
/********************************************************************/
Image FiltreAireR(Image imS, Image imD, int aireMin,int aireMax)
{
  int i,dim,area;
  Liste source,dest,c;
  Image imC,imC1;

  if (imS==NULL) return(NULL);
  imC=imS->suivant;
  if (CreeListe(imC,&source)) return(NULL);
  dim=source.Dimension();
  for(i=0;i<dim;i++)
  { Lire(&source,&c); area=Aire(&c); if((aireMin<=area)&&(area<aireMax)){ Ecrire(&c,&dest); } }

  if ((imC1=CreeImCont(NULL,&dest))==NULL) return(NULL);
  if (atoi(imC->commentaire)==0) {if ((imD=TraceImCont(imC1,imS,imD))==NULL) return(NULL);}
  else if ((imD=TraceContour (imC1,imS,imD))==NULL) return (NULL);
  imC1->commentaire=(char *)calloc (4,sizeof (int));
  strcpy (imC1->commentaire,imC->commentaire);
  imD->suivant=imC1;
  if (imS==imD) LibereImage(imC);
  return(imD);
}
/********************************************************************/
/***   Routine  qui a en entrée une image source avec derriere    ***/
/***   les contours et un paramètre int et qui returne l' image   ***/
/***   sans les regions qui ont un perimetre inferieur à le       ***/
/***                 paramètre.                                   ***/
/********************************************************************/

Image FiltrePerR(Image imS, Image imD, int perMin,int perMax)
{
  int i,dim,per;
  Liste source,dest,c;
  Image imC,imC1;

  if (imS==NULL) return(NULL);
  imC=imS->suivant;
  if (CreeListe(imC,&source)) return(NULL);
  dim=source.Dimension();

  for(i=0;i<dim;i++)
  {
	 Lire(&source,&c); per=Perimetre(&c);	if((perMin<=per)&&(per<perMax)) { Ecrire(&c,&dest); }
  }

  if((imC1=CreeImCont(NULL,&dest))==NULL) return(NULL);
  if (atoi(imC->commentaire)==0) {if ((imD=TraceImCont(imC1,imS,imD))==NULL) return(NULL);}
  else if ((imD=TraceContour (imC1,imS,imD))==NULL) return (NULL);
  imC1->commentaire=(char *)calloc (4,sizeof (int));
  strcpy (imC1->commentaire,imC->commentaire);
  imD->suivant=imC1;
  if (imS==imD) LibereImage(imC);
  return(imD);
}

/********************************************************************/
/***   Routine  qui a en entrée une image source avec derriere    ***/
/***   les contours et un paramètre int et qui returne l' image   ***/
/***   sans les regions qui ont la coulour du paramètre.          ***/
/********************************************************************/

Image FiltreNiveauR(Image imS, Image imD, float nivMin,float nivMax)
{
  int i,dim;
  Liste source,dest,c;
  Image imC,imC1;   float gg;

  if (imS==NULL) return(NULL);
  imC=imS->suivant;
  if (CreeListe(imC,&source)) return(NULL);
  dim=source.Dimension();
  for(i=0;i<dim;i++)
  {
	 Lire(&source,&c);
	 gg=Niveau(&c);
	 if((nivMin<=gg)&&(gg<nivMax)){ Ecrire(&c,&dest); }
  }

  if ((imC1=CreeImCont(NULL,&dest))==NULL) return(NULL);
  if (atoi(imC->commentaire)==0) {if ((imD=TraceImCont(imC1,imS,imD))==NULL) return(NULL);}
  else if ((imD=TraceContour (imC1,imS,imD))==NULL) return (NULL);
  imC1->commentaire=(char *)calloc (4,sizeof (int));
  strcpy (imC1->commentaire,imC->commentaire);
  imD->suivant=imC1;
  if (imS==imD) LibereImage(imC);
  return(imD);
}


Image FiltreCircR(Image imS, Image imD, float circMin,float circMax)
/******************************************************************/
/* Elimination des contours dont le rapport dMin/dMax
  n'est pas dans l'intervalle donné [circMin, circMax[
*/
{
  int i,dim,drapeau;
  float xg,yg,dMin,dMax,circ;
  Liste source,dest,c;
  Image imC,imC1;
  Fenetre fen;
  if (imS==NULL) return(NULL);
  imC=imS->suivant;
  if (CreeListe(imC,&source)) return(NULL);
  dim=source.Dimension();
  if (imC->commentaire==NULL) return (NULL);
  drapeau=atoi(imC->commentaire);
  for(i=0;i<dim;i++)
  { Lire(&source,&c);

  PointCG(&c,&xg,&yg,&fen,&dMin,&dMax,drapeau);
  circ=dMin/dMax;
  if((circMin<=circ)&&(circ<circMax)){ Ecrire(&c,&dest); }

  }

  if ((imC1=CreeImCont(NULL,&dest))==NULL) return(NULL);
  if (atoi(imC->commentaire)==0) {if ((imD=TraceImCont(imC1,imS,imD))==NULL) return(NULL);}
  else if ((imD=TraceContour (imC1,imS,imD))==NULL) return (NULL);
  imC1->commentaire=(char *)calloc (4,sizeof (int));
  strcpy (imC1->commentaire,imC->commentaire);
  imD->suivant=imC1;
  if (imS==imD) LibereImage(imC);
  return(imD);
}



/***************************************************/
/* Calcule la moyenne des points intérieurs à un contour
 change le niveau du contours pour le mettre à la moyenne
 imS : image en niveau de gris contenant les objets
 cont : contours dans lequel doit se faire la mesure
 front : 0 si contour plein et 1 si uniquement la frontière
 */
/***************************************************/

Reel MoyContourR(Image imS,Liste *cont,int front)
{
double moy;
Fenetre fen;
int x,y,taille,ox,oy,tx,ty,i,j,n;
float dm,dn,x1,y1;
Image imCont,imTraceCont,imT;
char *codes;
Liste liste,cont1,contNull;
Reel niv,**grS,**grC;

PointCG(cont,&y1,&x1,&fen,&dm,&dn,front);
imTraceCont=CreeImageSimple(NULL,T_REEL,V_CARTE,fen.taille.x+2,fen.taille.y+2);
codes=cont->Lire(&y,&x,&taille,&niv);
// Changement d'origine du contours, création d'une liste de 1 contours
liste.Insertion(y-fen.origine.y+1,x-fen.origine.x+1,taille,codes,niv);
// Tracé du contours dans une image
imCont=CreeImCont(NULL,&liste);
if (!front)
  TraceImCont(imCont,imTraceCont,imTraceCont);
else TraceContour (imCont,imTraceCont,imTraceCont);

LibereImage(imCont);

EcritFenetre(imTraceCont,1,1,fen.taille.x,fen.taille.y);
LitFenetre(imS,&ox,&oy,&tx,&ty);
EcritFenetre(imS,fen.origine.x,fen.origine.y,fen.taille.x,fen.taille.y);
imT=ExtraitFenetreR(imS,NULL);
grS=(Reel**)CreeGrille(imT,Z_FENETRE);
grC=(Reel**)CreeGrille(imTraceCont,Z_FENETRE);
moy=0;
n=0;
for (i=0;i<(int)fen.taille.y;i++)
  for (j=0;j<(int)fen.taille.x;j++)
    {
    if (grC[i][j]!=0)
      {
      n++;
      moy+=grS[i][j];
      }
    }
if (n>0) moy/=n;
LibereGrille(grC);
LibereGrille(grS);
EcritFenetre(imS,ox,oy,tx,tx);
LibereImage(imT);
LibereImage(imTraceCont);
cont1.Insertion(y,x,taille,codes,moy);
cont->Elimination();
*cont=cont1;
cont1=contNull;
//cont->Change(y,x,taille,codes,moy);
return ((Reel)moy);
}


int FenetreCirc(Liste *contour,Fenetre *fenetre)
/**********************************************/
/* Calcul de la fenêtre circonscrite au contours
*/
{
  	int i,taille,inf_x,sup_x,inf_y,sup_y,dim_x,dim_y;
  	char *code;//code de FreeMan
   int	 x,y;
   Reel  ngObjet;

      if (contour==NULL || fenetre==NULL) return(1);
		code=contour->Lire(&x,&y,&taille,&ngObjet);
      if (taille<1) return (1);
		sup_y=inf_y=y; sup_x=inf_x=x;
  		if (taille>1) for(i=0;i<taille;i++)
  		{
				  if (code[i]==0)	 { y++;      if(y>sup_y){ sup_y=y; } }
			else if (code[i]==1)  { x++; y++; if(x>sup_x){ sup_x=x; } if(y>sup_y){ sup_y=y; } }
			else if (code[i]==2)  { x++;      if(x>sup_x){ sup_x=x; } }
			else if (code[i]==3)  { x++; y--; if(x>sup_x){ sup_x=x; } if(y<inf_y){ inf_y=y; } }
			else if (code[i]==4)  { y--;      if(y<inf_y){ inf_y=y; } }
			else if (code[i]==5)  { x--; y--; if(x<inf_x){ inf_x=x; } if(y<inf_y){ inf_y=y; } }
			else if (code[i]==6)	 { x--;      if(x<inf_x){ inf_x=x; } }
			else if (code[i]==7)  { x--; y++; if(x<inf_x){ inf_x=x; } if(y>sup_y){ sup_y=y; } }
  		}
  		dim_x=sup_x-inf_x+1;
  		dim_y=sup_y-inf_y+1;

  		fenetre->origine.x=inf_y;
  		fenetre->origine.y=inf_x;
  		fenetre->taille.x=dim_y;
  		fenetre->taille.y=dim_x;
      return (0);
}



Image TraceImagetteContR(Image imD,Liste *contour,int drapeau)
/************************************************************/
/*Création d'une imagette de la taille de la fenêtre circonscrite agrandie de 1
   et tracé du contour. Le conour ne touche pas les bords de la fenêtre.
 Si drap=1 on ne trace que le contours
 Si drap=0 on trace le contours rempli
*/
{
	int    taille;
   char   *code;
   int	 x,y;
   float ngObjet;
	Image	 imDC=NULL;
	Liste  contSupp;
   Fenetre fen;

   if (contour==NULL) return(NULL);
   FenetreCirc(contour,&fen);
	code=contour->Lire(&x,&y,&taille,&ngObjet);
  	contSupp.Insertion(1,y-(fen.origine.x)+1,taille,code,ngObjet);
  	if ( (imDC=CreeImCont(imDC,&contSupp))==NULL )return (NULL);
//Regeneration de l'image a partir du contour
	if ( (imD=CreeImageSimple(imD,T_REEL,V_CARTE,fen.taille.x+2,fen.taille.y+2))==NULL ){LibereImage(imDC);return (NULL);}
   NiveauR(imD,imD,0);
	if (drapeau==0) imD=TraceImCont(imDC,imD,imD);
	else imD=TraceContour(imDC,imD,imD);
	LibereImage(imDC);
   return imD;
}


int Covariance(Liste *contour,double *covXX,double *covXY,double *covYY)
/*******************************************************************/
//Calcul de la matrice d'autocovarience d'une forme donnée sur image binaire
{
	int    i,j;
  	double mx,my,vxx,vyy,vxy;
   int	 nbPts;
   int x,y;
   Reel **grille;
   Image imagette;

   if (contour==NULL) return(1);
   if ((imagette=TraceImagetteContR(NULL,contour,0))==NULL) return(1);
   if ((grille=(Reel **)CreeGrille(imagette,Z_FENETRE))==NULL) return(1);
   LitTailleFenetre(imagette,&x,&y);
	//Calcul des variances
		mx=my=nbPts=0;
		vxx=vxy=vyy=0;
  		for(i=1;i<y-1;i++)
  		{
   		for(j=1;j<x-1;j++)
      	{
      		if(grille[i][j]!=0)
         	{
					mx+=j;
					my+=i;
					vxx+=j*j;
					vyy+=i*i;
					vxy+=i*j;
               //Aire
            	nbPts++;
         	}
      	}
   	}
   LibereGrille(grille);
   LibereImage(imagette);
   if (nbPts==0) return (1);
	mx/=nbPts;
	my/=nbPts;
	*covXX=vxx/nbPts-mx*mx;
	*covXY=vxy/nbPts-mx*my;
	*covYY=vyy/nbPts-my*my;
	return (0);
}


int AxesPrincipaux(Liste *contour,double *axe1X,double *axe1Y,double *axe2X,double *axe2Y)
/************************************************************************************/
/*Recherche des axes principaux d'une forme binaire
  retour des composantes des vecteurs principaux dans (axe1X,axe1Y) et (axe2X,axe2Y)
*/
{
	double sxx,syy,sxy;
	double delta,l1,l2;
   double tempo;

	if (Covariance(contour,&sxx,&sxy,&syy)) {*axe1X=0.;*axe1Y=0.;*axe2X=0.;*axe2Y=0.;return (1);}
   	//Résolution du system
      if (( tempo=(sxx-syy)*(sxx-syy)+4*sxy*sxy )<0) return (91);
		delta=sqrt(tempo);
		l1=(sxx+syy+delta)/2;
		l2=(sxx+syy-delta)/2;
      if (( tempo=sxy*sxy+(l1-sxx)*(l1-sxx) )<0) return (92);
      if (( tempo=sqrt(tempo) )==0)
		{
      	*axe1X=1;
			*axe1Y=0;
      }
      else
      {
			*axe1X=sxy/tempo;
			*axe1Y=(l1-sxx)/tempo;
      }
      if (( tempo=sxy*sxy+(l2-sxx)*(l2-sxx) )<0) return (93);
      if (( tempo=sqrt(tempo) )==0)
      {
      	*axe2X=0;
			*axe2Y=1;
      }
      else
      {
			*axe2X=sxy/tempo;
			*axe2Y=(l2-sxx)/tempo;
      }
	return(0);
}


int CovarSurAxes(Liste *contour,double axe1X,double axe1Y,double *covXX,double *covXY,double *covYY)
/**************************************************************************************************/
/* Calcul des coefficients de la matrice de covariance calculée dans un système d'axes donné
   (typiquement, on peut prendre le repère des axes principaux)
   (axe1X,axe1Y) composantes du premier vecteur unitaire du système d'axe (l'autre est déduit)
   (covXX,covXY, covYY) résultat du calcul de covariance
*/
{
	int    i,j;
   double I,J;
  	double mx,my,vxx,vyy,vxy;
   double  teta;
   double cosTeta,sinTeta;
   int	 nbPts;
   int x,y;
   Reel **grille;
   Image imagette;

   if (contour==NULL) return(1);
   if ((imagette=TraceImagetteContR(NULL,contour,0))==NULL) return(1);
   if ((grille=(Reel **)CreeGrille(imagette,Z_FENETRE))==NULL) return(1);
   LitTailleFenetre(imagette,&x,&y);
   //Ini
   if (axe1X==0) teta=M_PI_2; else	teta=atan(axe1Y/axe1X);
   cosTeta=cos(teta);
   sinTeta=sin(teta);
	//Calcul des variances principales
	mx=my=nbPts=0;
	vxx=vyy=vxy=0;
  	for(i=1;i<y-1;i++)
  	{
   	for(j=1;j<x-1;j++)
      {
      	if(grille[i][j]!=0)
         {
				//Changement de repere
            J=cosTeta*j+sinTeta*i;
            I=cosTeta*i-sinTeta*j;
            //Calcul comme CoVar
				mx+= J;
				my+= I;
				vxx+=J*J;
				vyy+=I*I;
				vxy+=I*J;
            nbPts++;
         }
      }
   }
   LibereGrille(grille);
   LibereImage(imagette);
   if (nbPts==0) return (1);
	mx/=nbPts;
	my/=nbPts;
	*covXX=vxx/nbPts-mx*mx;
	*covXY=vxy/nbPts-mx*my;
	*covYY=vyy/nbPts-my*my;
   return (0);
}


int DirPrincipale(Liste *contour,double *angle,double *excent)
/***********************************************************/
/* Calcul de l'angle entre l'horizontale et la direction principale d'inertie
   ainsi que du coefficient d'excentricité (si excent!=NULL)
    - l'angle est calculé en degrés (s'il n'y a pas d'erreurs ie retour==0)
    - Le coeff d'excentricité vaut 0 pour un objet circulaire et 1 pour une ligne
*/
{
double covXX,covXY,covYY;
double dm,sm,num;

if (angle!=NULL) *angle=0;
if (excent!=NULL) *excent=0;
if (Covariance(contour,&covXX,&covXY,&covYY)) return (1);
dm=covYY-covXX;
if (angle!=NULL)
  {
  num=dm+sqrt(dm*dm+4*covXY*covXY);
  if (covXY==0)
    {
    *angle=90;
    if (num==0) *angle=0;
    }
  else  *angle=180*atan(num/2/covXY)/M_PI;
  }
if (excent!=NULL)
  {
  sm=covXX+covYY;
  sm*=sm;
  if (sm>0) *excent=(dm*dm+4*covXY*covXY)/sm;
  }
return (0);
}


int DiametreDir(Liste *contour,double angle,double *diam)
/*******************************************************/
/* Calcul du diamètre projeté selon une direction donnée par un angle :
   on calcule la longueur du segment projeté suivant la direction.
   L'angle est donné en degré, le diamètre est calculé en double précision
*/
{
char*m;
float fff;
double min,max,temp,u,v;
int j,taille,x,y;

if (contour==NULL) return(1);
m=contour->Lire(&x,&y,&taille,&fff);

angle=angle*M_PI/180;
u=cos(angle);
v=sin(angle);
min=max=0;
x=0;y=0;
if (taille>1)
  for(j=0;j<taille;j++)
    {temp=u*y+v*x;
     if(temp>max) max=temp;
     if(temp<min) min=temp;
     if(m[j]==0) y++;
   	else if (m[j]==1) {x++;y++;}
	   else if (m[j]==2) x++;
	   else if (m[j]==3)	{x++; y--;}
   	else if (m[j]==4) y--;
   	else if (m[j]==5)	{x--; y--;}
   	else if (m[j]==6) x--;
   	else if (m[j]==7)	{x--; y++;}
    }
*diam=max-min+fabs(u)+fabs(v);
return(0);
}


int DiametreFeret(Liste *contour,int nbdir,double *diam)
/**************************************************************************
Calcul du diamètre moyen suivant un ensemble de directions
 - les directions calculées vont de 0 à 180 par incrément de 180/nbdir°
 - si nbdir=0, on se sert de la diagonale de la fenêtre circonscrite
   pour calculer l'incrément
*/

{
 double d,moy,teta,dTeta;
 Fenetre fen;
 int i;

 if (contour==NULL) return(1);
 if (nbdir==0)
   {
   FenetreCirc(contour,&fen);
   nbdir=(int) (M_PI*sqrt(fen.taille.x*fen.taille.x+fen.taille.y*fen.taille.y)/2);
   }
 dTeta=180/nbdir;
 teta=0;
 moy=0;
 for(i=0;i<nbdir;i++)
   {
   DiametreDir(contour,teta,&d);
   moy+=d;
   teta+=dTeta;
   }
 moy/=nbdir;
 *diam=moy;
 return(0);
}



int DiametreMinMax(Liste *contour,int nbdir,double *dMin,double *dMax, double *coefAlgt)
/***************************************************************************************
Calcul des diamètres min et max suivant un ensemble de directions et calcul du
coefficient d'allongement
 - les directions calculées vont de 0 à 180 par incrément de 180/nbdir°
 - si nbdir=0, on se sert de la diagonale de la fenêtre circonscrite
   pour calculer l'incrément
 - dMin représente l'épaisseur (si dMin!=NULL)
 - dMax représente le diamètre (si dMax!=NULL)
 - l'allongement est dMin/dMax (si coefAlgt!=NULL)
*/

{
 double d,teta,dTeta,min,max;
 Fenetre fen;
 int i;

 if (contour==NULL) return(1);
 if (nbdir==0)
   {
   FenetreCirc(contour,&fen);
   nbdir=(int) (M_PI*sqrt(fen.taille.x*fen.taille.x+fen.taille.y*fen.taille.y)/2);
   }
 dTeta=180/nbdir;
 DiametreDir(contour,0,&min);
 max=min;
 teta=dTeta;
 for(i=1;i<nbdir;i++)
   {
   DiametreDir(contour,teta,&d);
   if (d<min) min=d;
   if (d>max) max=d;
   teta+=dTeta;
   }
 if (dMin!=NULL) *dMin=min;
 if (dMax!=NULL) *dMax=max;
 if (coefAlgt!=NULL && max!=0) *coefAlgt=min/max;
 return(0);
}


#define nconcav 5
#define nconcav2 2*nconcav+1

//*****************************************************************************
// Calcul la concavite maximum d'une particule
// - la concavite est calculee par  produit mixte en prenant comme vecteurs des
// vecteurs de taille nconcav pixels se suivants sur la particule
// - le résultat est entre 0 et 1 : 0 pt convexe sinon sinus de l'angle
//*****************************************************************************
float Concavite(Liste *contour){

  char*m ;
  float fff,cmax,v1x,v1y,v2x,v2y,n2 ;
  int j,i,k,taille ;
  int x,y ;
  int xi[nconcav2];
  int yi[nconcav2];

  if (contour==NULL) return(1) ;
  m=contour->Lire(&x,&y,&taille,&fff) ;
  if (taille>nconcav2){
    i=0; cmax=0.0;
    for(j=0;j<taille;j++){
      if(m[j]==0) y++ ;
      else if (m[j]==1) {x++;y++;}
      else if (m[j]==2) x++;
      else if (m[j]==3)	{x++; y--;}
      else if (m[j]==4) y--;
      else if (m[j]==5)	{x--; y--;}
      else if (m[j]==6) x--;
      else if (m[j]==7)	{x--; y++;}
      i++ ;
      if (i>=nconcav2){
        for(k=1;k<nconcav2;k++)
           {xi[k-1]=xi[k]; yi[k-1]=yi[k];}
        xi[nconcav2-1]=x; yi[nconcav2-1]=y;
        v1x=xi[nconcav]-xi[0]; v1y=yi[nconcav]-yi[0];
        v2x=x-xi[0]; v2y=y-yi[0];
        n2=max((int) (v2x*v2x+v2y*v2y),1) ;
        cmax=max(cmax,(v1x*v2y-v1y*v2x)/n2) ;
      } else {xi[i]=x; yi[i]=y;}
    }
    return (cmax) ;
  } else return (0.0) ;
}


static void ConcavM(Liste *contour,Reel **grille){

  char *m ;
  float fff,c,v1x,v1y,v2x,v2y,n2 ;
  int j,i,k,taille ;
  int x,y ;
  //int x0,y0,x1=0,y1=0,x2=0,y2=0,x3=0,y3=0 ;
  //int x4=0,y4=0,x5=0,y5=0,x6=0,y6=0,x,y ;
  int xi[nconcav2];
  int yi[nconcav2];


  m=contour->Lire(&x,&y,&taille,&fff) ;
  if ((taille>6)&&(fff>0.0)){
    i=0; grille[x][y]=1 ;
    for(j=0;j<taille;j++){
      if(m[j]==0) y++ ;
      else if (m[j]==1) {x++;y++;}
      else if (m[j]==2) x++;
      else if (m[j]==3)	{x++; y--;}
      else if (m[j]==4) y--;
      else if (m[j]==5)	{x--; y--;}
      else if (m[j]==6) x--;
      else if (m[j]==7)	{x--; y++;}
      i++ ;
      grille[x][y]=1 ;
      if (i>=nconcav2){
        for(k=1;k<nconcav2;k++)
           {xi[k-1]=xi[k]; yi[k-1]=yi[k];}
        xi[nconcav2-1]=x; yi[nconcav2-1]=y;
        v1x=xi[nconcav]-xi[0]; v1y=yi[nconcav]-yi[0];
        v2x=x-xi[0]; v2y=y-yi[0];
        n2=max((int) (v2x*v2x+v2y*v2y),1) ;
        c=(v1x*v2y-v1y*v2x)/n2 ;
        if (c>0) grille[xi[nconcav]][yi[nconcav]]+=10*c ;
      } else {xi[i]=x; yi[i]=y;}
    }
  }
}



//*****************************************************************************
// Renvoie une carte de concavité on associe a chaque point du contours une
// un niveau obtenu en ajoutant la valeur de concavité * 10.
//*****************************************************************************
Image CarteConcaviteR(Image imS,Image imD){

  int i,w,h,dim ;
  Liste source,dest,c ;
  Image imC ;
  Reel **grille ;


  if (imS==NULL) return(NULL) ;
  LitTailleFenetre(imS,&w,&h) ;
  if ((imC=imS->suivant)==NULL) return (NULL) ;
  if (CreeListe(imC,&source)) return(NULL) ;
  dim=source.Dimension();
  if ((imD=CreeImageDest(imS,imD,T_REEL))==NULL) imD=TransfereR(imS,imD) ;
  if ((grille=(Reel**)CreeGrille(imD,Z_FENETRE))==NULL) return (imS);
  for(i=0;i<dim;i++){
     Lire(&source,&c) ;
     ConcavM(&c,grille) ;
  }

  LibereGrille(grille) ;
  return(imD) ;
}


//*****************************************************************************
// Filtre les particules par diamètres et allongements
// paramètres: dmin=diamètre mini
//	            dmax=diamètre maxi strict
//             emin:alongement mini
//             emax:alongement max
//*****************************************************************************
Image FiltreDiamAllongR(Image imS,Image imD,float dmin,float dmax,float emin,float emax){

  int i,w,h,dim ;
  double dmn,dmx,e ;
  Liste source,dest,c;
  Image imC,imC1;


  if (imS==NULL) return(NULL);
  LitTailleFenetre(imS,&w,&h) ;
  if ((imC=imS->suivant)==NULL) return (NULL);
  if (CreeListe(imC,&source)) return(NULL);
  dim=source.Dimension();
  for(i=0;i<dim;i++){
     Lire(&source,&c) ;
     DiametreMinMax(&c,0,&dmn,&dmx,&e) ;
     if ((dmn>=dmin)&&(dmx<dmax)&&(e>=emin)&&(e<emax))
        Ecrire(&c,&dest) ;
  }

  if ((imC1=CreeImCont(NULL,&dest))==NULL) return(NULL);
  if (atoi(imC->commentaire)==0) {if ((imD=TraceImCont(imC1,imS,imD))==NULL) return(NULL);}
  else if ((imD=TraceContour (imC1,imS,imD))==NULL) return (NULL) ;
  imC1->commentaire=(char *)calloc (4,sizeof (int)) ;
  strcpy (imC1->commentaire,imC->commentaire) ;
  imD->suivant=imC1 ;
  if (imS==imD) LibereImage(imC) ;
  return(imD) ;
}




//*****************************************************************************
// Filtre les particules par concavite
// paramètres: cmin=concavite mini
//	            cmax=concavite maxi
//*****************************************************************************
Image FiltreConcaviteR(Image imS,Image imD,float cmin,float cmax){

  int i,w,h,dim ;
  float cv ;
  Liste source,dest,c;
  Image imC,imC1;
  bool rien=true ;


  if (imS==NULL) return(NULL);
  LitTailleFenetre(imS,&w,&h) ;
  if ((imC=imS->suivant)==NULL) return (NULL);
  if (CreeListe(imC,&source)) return(NULL);
  dim=source.Dimension();
  for(i=0;i<dim;i++){
     Lire(&source,&c) ;
     cv=Concavite(&c) ;
     if ((Niveau(&c)>0)&&(cv>=cmin)&&(cv<cmax))
        {Ecrire(&c,&dest); rien=false;}
  }

  if (rien){
    if ((imD=CreeImageDest(imS,imD,T_REEL))==NULL) return (NULL) ;
  } else {
    if ((imC1=CreeImCont(NULL,&dest))==NULL) return(NULL);
    if (atoi(imC->commentaire)==0) {if ((imD=TraceImCont(imC1,imS,imD))==NULL) return(NULL);}
    else if ((imD=TraceContour(imC1,imS,imD))==NULL) return (NULL) ;
    imC1->commentaire=(char *)calloc (4,sizeof (int)) ;
    strcpy (imC1->commentaire,imC->commentaire) ;
    imD->suivant=imC1 ;
  }
  if (imS==imD) LibereImage(imC) ;
  return(imD) ;
}


