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

#include <Triangle.h>




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

static triangle_t _ProjectionOrtho(triangle_t tr, int axe)
{
  triangle_t projete; 

      
  projete.A = V_ProjectionOrtho(tr.A, axe); 
  projete.B = V_ProjectionOrtho(tr.B, axe); 
  projete.C = V_ProjectionOrtho(tr.C, axe); 

  return(projete);
}

//-------------------------------------------
// Chaque triangle definit une boite englobante
// Cette fonction retourne 1 si point appartient
// a cette boite englobante et 0 sinon. 
//-------------------------------------------

static int _EstDansBoiteEnglobante(triangle_t tr, vecteur_t point)
{
  if((point.x>tr.A.x)&&
     (point.x>tr.B.x)&&
     (point.x>tr.C.x))
    return(0); 

  if((point.x<tr.A.x)&&
     (point.x<tr.B.x)&&
     (point.x<tr.C.x))
    return(0); 

  else if((point.y>tr.A.y)&&
	  (point.y>tr.B.y)&&
	  (point.y>tr.C.y))
    return(0); 
  
  else if((point.y<tr.A.y)&&
	  (point.y<tr.B.y)&&
	  (point.y<tr.C.y))
    return(0); 
  
  else if((point.z>tr.A.z)&&
	  (point.z>tr.B.z)&&
	  (point.z>tr.C.z))
    return(0); 

  else if((point.z<tr.A.z)&&
	  (point.z<tr.B.z)&&
	  (point.z<tr.C.z))
    return(0); 

  else return(1); 
}


//-------------------------------------------
// Retourne 1 si P appartient a 
// l'interieur de tr et 0 sinon. 
//-------------------------------------------

static int _EstDansTriangle2D(triangle_t tr, vecteur_t P, int quel_axe)
{
  double coteAB, coteBC, coteCA; 
  vecteur_t axe, AB, BC, CA, AP, BP, CP; 

  switch(quel_axe)
    {
    case V_X : V_Set(&axe, 1.0, 0.0, 0.0); break; 
    case V_Y : V_Set(&axe, 0.0, 1.0, 0.0); break; 
    case V_Z : V_Set(&axe, 0.0, 0.0, 1.0); break;
    default : 
      fprintf(stderr,"_EstDansTriangle2D : \n");
      fprintf(stderr,"%d n'est pas une valeur autorisee pour quel_axe.\n", quel_axe);
      exit(1); 
    }

  AB = V_Difference(tr.B,tr.A);
  BC = V_Difference(tr.C,tr.B);
  CA = V_Difference(tr.A,tr.C);

  AP = V_Difference(P,tr.A);
  BP = V_Difference(P,tr.B);
  CP = V_Difference(P,tr.C);

  coteAB = V_ProduitScalaire(V_ProduitVectoriel(AB,AP), axe);
  coteBC = V_ProduitScalaire(V_ProduitVectoriel(BC,BP), axe);
  coteCA = V_ProduitScalaire(V_ProduitVectoriel(CA,CP), axe);

  if((coteAB>=0)&&(coteBC>=0)&&(coteCA>=0))
    return(1);
  else if((coteAB<=0)&&(coteBC<=0)&&(coteCA<=0))
    return(1);
  else 
    return(0);
}

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

static int _TraverseTriangle2D(triangle_t tr, vecteur_t P, vecteur_t u, int quel_axe)
{
  vecteur_t axe, PA, PB, PC; 
  float cotePA, cotePB, cotePC; 

  switch(quel_axe)
    {
    case V_X : V_Set(&axe, 1.0, 0.0, 0.0); break; 
    case V_Y : V_Set(&axe, 0.0, 1.0, 0.0); break; 
    case V_Z : V_Set(&axe, 0.0, 0.0, 1.0); break;
    default : 
      fprintf(stderr,"_TraverseTriangle2D : \n");
      fprintf(stderr,"%d n'est pas une valeur autorisee pour quel_axe.\n", quel_axe);
      exit(1); 
    }
  PA = V_Difference(tr.A,P);
  PB = V_Difference(tr.B,P);
  PC = V_Difference(tr.C,P);

  cotePA = V_ProduitScalaire(V_ProduitVectoriel(PA,u),axe);
  cotePB = V_ProduitScalaire(V_ProduitVectoriel(PB,u),axe);
  cotePC = V_ProduitScalaire(V_ProduitVectoriel(PC,u),axe);

  if((cotePA>0.0)&&(cotePB>0.0)&&(cotePC>0.0))
    return(0);
  else if((cotePA<0.0)&&(cotePB<0.0)&&(cotePC<0.0))
    return(0);
  else
    return(1);
}

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

void TR_Check(triangle_t t, char *commentaire)
{
  fprintf(stderr,"\n%s : check triangle\n", commentaire); 
  V_Check(t.A, "A");
  V_Check(t.B, "B");
  V_Check(t.C, "C");
}

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

void TR_Set(triangle_t *t, vecteur_t A, vecteur_t B, vecteur_t C)
{
  t->A = A; 
  t->B = B; 
  t->C = C; 
}

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

void TR_IntersectRayon(triangle_t tr, rayon_t rayon, int *nb_points, vecteur_t *M, vecteur_t *normal)
{
  plan_t plan; 
  vecteur_t droite_inter_plan, dip_projete, u_projete, o_projete; 
  int nb_pt_plan, quel_axe; 
  triangle_t tr_projete; 

  P_Set3(&plan, tr.A, tr.B, tr.C);

  P_IntersectRayon(plan, rayon, &nb_pt_plan, &droite_inter_plan, normal);

  if(nb_pt_plan==0)
    *nb_points = 0;

  else if(nb_pt_plan==1)
    {
      if(_EstDansBoiteEnglobante(tr, droite_inter_plan)==0)
	*nb_points = 0; 
      else
	{
	  quel_axe = P_OrientationGlobale(plan); 	  
	  tr_projete = _ProjectionOrtho(tr, quel_axe);
	  dip_projete = V_ProjectionOrtho(droite_inter_plan, quel_axe); 

	  if(_EstDansTriangle2D(tr_projete, dip_projete, quel_axe))
	    {
	      *nb_points = 1; 
	      *M = droite_inter_plan; 
	      *normal = plan.normal; 
	    }
	  else
	    *nb_points = 0; 
	}
    }
  else // if(nb_pt_plan==2)
    {
      quel_axe = P_OrientationGlobale(plan); 
      u_projete = V_Unitaire(V_ProjectionOrtho(rayon.direction, quel_axe)); 
      o_projete = V_ProjectionOrtho(rayon.origine, quel_axe);
      tr_projete = _ProjectionOrtho(tr, quel_axe);

      if(_TraverseTriangle2D(tr_projete, o_projete, u_projete, quel_axe))
	{
	  *nb_points = 2; 
	  *normal = plan.normal; 
	}
      else 
	*nb_points = 0; 
    }
}

//-------------------------------------------
// Idem que la fonction précédente, mais 
// sans la normale (vieille version). 
//-------------------------------------------

void TR_IntersectRayon2(triangle_t tr, rayon_t rayon, int *nb_points, vecteur_t *M)
{
  plan_t plan; 
  vecteur_t droite_inter_plan, dip_projete, u_projete, o_projete; 
  int nb_pt_plan, quel_axe; 
  triangle_t tr_projete; 

  P_Set3(&plan, tr.A, tr.B, tr.C);

  P_IntersectRayon2(plan, rayon, &nb_pt_plan, &droite_inter_plan);

  if(nb_pt_plan==0)
    *nb_points = 0;

  else if(nb_pt_plan==1)
    {
      if(_EstDansBoiteEnglobante(tr, droite_inter_plan)==0)
	*nb_points = 0; 
      else
	{
	  quel_axe = P_OrientationGlobale(plan); 	  
	  tr_projete = _ProjectionOrtho(tr, quel_axe);
	  dip_projete = V_ProjectionOrtho(droite_inter_plan, quel_axe); 

	  if(_EstDansTriangle2D(tr_projete, dip_projete, quel_axe))
	    {
	      *nb_points = 1; 
	      *M = droite_inter_plan; 
	    }
	  else
	    *nb_points = 0; 
	}
    }
  else // if(nb_pt_plan==2)
    {
      quel_axe = P_OrientationGlobale(plan); 
      u_projete = V_Unitaire(V_ProjectionOrtho(rayon.direction, quel_axe)); 
      o_projete = V_ProjectionOrtho(rayon.origine, quel_axe);
      tr_projete = _ProjectionOrtho(tr, quel_axe);

      if(_TraverseTriangle2D(tr_projete, o_projete, u_projete, quel_axe))
	*nb_points = 2; 
      else 
	*nb_points = 0; 
    }
}

