
//=============================================
// 
// Mercredi 12 decembre 2001
//  
// Arash Habibi
// 
// Plan.c
//
//============================================


#include <Plan.h>


//-------------------------------------------
//-------------------------------------------

void P_Check(plan_t p, char *commentaire)
{
  fprintf(stderr,"\n%s : check plan\n", commentaire); 
  V_Check(p.point, "point");
  V_Check(p.normal,"normal");
}

//-------------------------------------------
// le plan defini par un point et un vecteur 
// normal. 
//-------------------------------------------

void P_Set1(plan_t *p, vecteur_t point, vecteur_t normal)
{
  p->point = point; 
  p->normal = normal; 

  if(V_EstNul(p->normal))
    {
      fprintf(stderr,"V_Set1 : le vecteur ne doit pas etre nul.\n");
      exit(1);
    }
}


//-------------------------------------------
// le plan defini par les 4 coefficients de 
// son equation
//-------------------------------------------

void P_Set2(plan_t *p, double a, double b, double c, double d)
{
  if((a==0.0)&&(b==0.0)&&(c==0.0))
    {
      if(d==0.0)
	{
	  fprintf(stderr,"P_Set2 : ceci n'est pas une equation du plan\n"); 
	  fprintf(stderr,"c'est une tautologie a=b=c=d=0.0 donc forcement : \n");
	  fprintf(stderr,"0.0x + 0.0y + 0.0z + 0.0 = 0.0\n"); 
	  exit(1); 
	}
      else
	{
	  fprintf(stderr,"P_Set2 : ceci n'est pas une equation du plan\n"); 
	  fprintf(stderr,"c'est une absurdite. En effet a=b=c=0.0 et d!=0.\n");
	  fprintf(stderr,"Donc forcement 0.0x + 0.0y + 0.0z + d != 0.0\n"); 
	  exit(1); 
	}
    }
  else // au moins un des coefficients n'est pas nul
    {
      V_Set(&(p->normal), a, b, c); 
      p->normal = V_Unitaire(p->normal);
      
      if(a!=0.0)
	V_Set(&(p->point), d/a, 0.0, 0.0); 

      else if(b!=0.0)
	V_Set(&(p->point), 0.0, d/b, 0.0);

      else // if(c!=0.0)
	V_Set(&(p->point), 0.0, 0.0, d/c);
    }
}

//-------------------------------------------
// le plan defini par trois points. 
//-------------------------------------------

void P_Set3(plan_t *p, vecteur_t A, vecteur_t B, vecteur_t C)
{
  vecteur_t AB, AC, PV; 

  AB = V_Difference(B,A); 
  AC = V_Difference(C,A); 
  PV = V_ProduitVectoriel(AB,AC);
  if(V_EstNul(PV))
    {
      fprintf(stderr,"P_Set3 : A, B et C sont alignes et ne definissent pas un plan.\n");
      exit(1); 
    }
  else
    {
      p->point = A; 
      p->normal = V_Unitaire(PV); 
    }
}


//-------------------------------------------
// a partir d'un plan donne son equation. 
//-------------------------------------------

void P_Equation(plan_t p, double *a, double *b, double *c, double *d)
{
  *a = p.normal.x; 
  *b = p.normal.y; 
  *c = p.normal.z; 
  *d = - V_ProduitScalaire(p.normal, p.point); 
}


//-------------------------------------------
// Indique si le point M appartient au plan
// p ou non. 
//-------------------------------------------

int P_Comprend(plan_t p, vecteur_t M)
{
  return(V_ProduitScalaire(p.normal,V_Difference(M,p.point))==0.0);
}

//-------------------------------------------
// a partir d'un plan donne P_X, P_Y ou P_Z
// qui represente l'axe auquel le plan est 
// le plus perpendiculaire. 
//-------------------------------------------

int P_OrientationGlobale(plan_t p)
{
  if(p.normal.x < p.normal.y)
    if(p.normal.x < p.normal.z)
      return(V_X);
    else // if(p.normal.x > p.normal.z)
      return(V_Z);

  else // if(p.normal.x > p.normal.y)
    if(p.normal.y < p.normal.z)
      return(V_Y);
    else // if(p.normal.y > p.normal.z)
      return(V_Z);
}


//-------------------------------------------
// *nb_points est 0 si la droite et le plan
// sont paralleles, 1, s'il sont secants et 
// 2 (pour dire infini) si la droite st 
// incluse dans le plan. 
//-------------------------------------------

void P_IntersectRayon(plan_t p, rayon_t rayon, int *nb_points, vecteur_t *M, vecteur_t *normal)
{
  double t, u_scalaire_n, O_scalaire_n, coeff_d; 

  rayon.direction = V_Unitaire(rayon.direction); 
  O_scalaire_n = V_ProduitScalaire(rayon.origine,  p.normal); 
  u_scalaire_n = V_ProduitScalaire(rayon.direction,p.normal); 

  if(u_scalaire_n==0.0)
    {
      if(P_Comprend(p, rayon.origine)) // droite incluse dans le plan
	{
	  *nb_points = 2; 
	  *normal = p.normal; 
	}
      else 
	*nb_points = 0;                // droite parallèle au plan
    }
  else
    {
      coeff_d = - V_ProduitScalaire(p.normal, p.point); 
      t = -(O_scalaire_n+coeff_d)/u_scalaire_n; 

      if(t<0.0)
	*nb_points = 0; 
      else
	{
	  *nb_points = 1; 
	  *M = V_Addition2(rayon.origine, V_Homothetie(t, rayon.direction)); 
	  *normal = p.normal; 
	}
    }
}

//-------------------------------------------
// Même chose que la fonction précédente, mais 
// sans la normale (vieille version). 
//-------------------------------------------

void P_IntersectRayon2(plan_t p, rayon_t rayon, int *nb_points, vecteur_t *M)
{
  double t, u_scalaire_n, O_scalaire_n; 

  rayon.direction = V_Unitaire(rayon.direction); 
  O_scalaire_n = V_ProduitScalaire(rayon.origine,  p.normal); 
  u_scalaire_n = V_ProduitScalaire(rayon.direction,p.normal); 

  if(u_scalaire_n==0.0)
    {
      if(P_Comprend(p, rayon.origine)) // droite incluse dans le plan
	*nb_points = 2; 
      else 
	*nb_points = 0; 
    }
  else
    {
      t = -O_scalaire_n/u_scalaire_n; 
      if(t<0.0)
	*nb_points = 0; 
      else
	{
	  *nb_points = 1; 
	  *M = V_Addition2(rayon.origine, V_Homothetie(t, rayon.direction)); 
	}
    }
}


