/* Mathematiques de l'informatique graphique    */
/* Direction en 3D                              */
/*                                              */
/* Auteur: Nicolas JANEY                        */
/* nicolas.janey@univ-fcomte.fr                 */
/* Mars 2020                                    */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#include "CH3D.h"
#include "Dir3D.h"
#include "Pos3D.h"

/* Constructeurs                                */

/* Construit le vecteur nul                     */

Dir3D::Dir3D(void):CH3D() {
}

/* Construit la direction (x,y,z)               */

Dir3D::Dir3D(float x,float y,float z):CH3D(x,y,z,0.0F) {
}

/* Construit un clone de la Dir3D d             */

Dir3D::Dir3D(Dir3D *d):CH3D(d) {
}

/* Construit la direction pipf                  */

Dir3D::Dir3D(Pos3D *pi,Pos3D *pf):CH3D(pf->x-pi->x,pf->y-pi->y,pf->z-pi->z,0.0F) {
}

/* Construit la Dir3D transformee de d par tg   */

Dir3D::Dir3D(Dir3D *d,TG3D *tg) : CH3D(d) {
  transformation(tg);
}

/* Construit la direction produit vectoriel     */
/* de d1 par d2                                 */

Dir3D::Dir3D(Dir3D *d1,Dir3D *d2):CH3D() {
  produitVectoriel(d1,d2,this);
}

/* Destructeur                                  */

Dir3D::~Dir3D(void) {
}

/* Methode de calcul de la norme de this        */

float Dir3D::norme(void) {
  return((float) sqrt(x*x+y*y+z*z));
}

/* Methode de normalisation de this             */
/* Retourne la norme de this pre-normalisation  */

float Dir3D::normalisation(void) {
  float d = norme();
  if ( d != 0.0 ) {
    x /= d;
    y /= d;
    z /= d; }
  return d;
}

/* Methode de calcul du produit scalaire        */
/* de this et de la direction d                 */

float Dir3D::produitScalaire(Dir3D *d) {
  return(produitScalaire(this,d));
}

/* Methode statique de calcul                   */
/* du produit scalaire des deux directions      */
/* d1 et d2                                     */

float Dir3D::produitScalaire(Dir3D *d1,Dir3D *d2) {
  return(d1->x*d2->x+d1->y*d2->y+d1->z*d2->z);
}

/* Methode de calcul du produit vectoriel       */
/* de this par la direction d                   */
/* avec stockage du resultat dans this          */

void Dir3D::produitVectoriel(Dir3D *d) {
  produitVectoriel(this,d,this);
}

/* Methode de calcul du produit vectoriel       */
/* de la direction d1 par la direction d2       */
/* avec stockage du resultat dans this          */

void Dir3D::produitVectoriel(Dir3D *d1,Dir3D *d2) {
  produitVectoriel(d1,d2,this);
}

/* Methode statique de calcul                   */
/* du produit vectoriel de deux directions      */
/* d1 et d2 avec stockage du resultat           */
/* dans res                                     */

void Dir3D::produitVectoriel(Dir3D *d1,Dir3D *d2,Dir3D *res) {
  float x = d1->y*d2->z - d1->z*d2->y;
  float y = d1->z*d2->x - d1->x*d2->z;
  float z = d1->x*d2->y - d1->y*d2->x;
  res->x = x;
  res->y = y;
  res->z = z;
}

///////////////////////////////////////////////////////////////////

/* Methode de calcul de la direction            */
/* de reflexion speculaire a partir             */
/* de la direction d'incidence i                */
/* et de la normale n au point d'incidence      */
/* Affectation du resultat a this               */

bool Dir3D::reflexion(Dir3D *i,Dir3D *n) {
  float ps = i->produitScalaire(n);
  if ( ps < 0.0 ) return(false);
  x = 2.0F*ps*n->x-i->x;
  y = 2.0F*ps*n->y-i->y;
  z = 2.0F*ps*n->z-i->z;
  return(true);
}

/* Methode de calcul de la direction            */
/* de transmission a partir                     */
/* de la direction d'incidence i,               */
/* de la normale n au point d'incidence         */
/* et du rapport niSurNt calcule entre          */
/* les coefficients de refraction               */
/* des milieux d'incidence et de transmission   */
/* Affectation du resultat a this               */

bool Dir3D::transmission(Dir3D *i,Dir3D *n,float niSurNt) {
  float ps = i->produitScalaire(n);
  float v = 1.0F-(niSurNt*niSurNt*(1.0F-ps*ps));
  if ( v < 0.0 ) return(false);
  v =(float) (niSurNt*ps-sqrt(v));
  x = v*n->x - niSurNt*i->x;
  y = v*n->y - niSurNt*i->y;
  z = v*n->z - niSurNt*i->z;
  return(true);
}

///////////////////////////////////////////////////////////////////
