// Plane.cpp: Implementierung der Klasse Plane.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include <math.h>

#include "Plane.h"

// MFC - Assists in finding memory leaks:
#ifdef MFC_DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

/****************************************************************************/
/** \brief Konstruktor
*****************************************************************************/
Plane::Plane()
{
  m_D = 0;
}

/****************************************************************************/
/** \brief Destruktor
*****************************************************************************/
Plane::~Plane()
{

}

/****************************************************************************/
/** \brief Initialisiert die Ebene
*****************************************************************************/
void Plane::clear(void)
{
 m_N.clear();
 m_P.clear();
 m_D = 0;
}

/****************************************************************************/
/** \brief Setter fuer die Ebenenparameter:
 Definiert die Ebene ueber drei Punkte, die sich auf der Ebene befinden
 Die Punkte duerfen nicht alle auf einer Geraden liegen!
 Aus den Punkten wird der Normalenvektor berechnet, und normalisiert (Laenge 1)
 Ausserdem wird der Abstand zum Ursprung D berechnet.
 Der Normalenvektor zeigt in Richtung der Ebene.
 Es gilt:  d = N * Q + D

  va
  |
  |
  |
  |----------vb
  v0

 \param v0
 \param va
 \param vb
*****************************************************************************/
void Plane::set(Vec& v0, Vec& va, Vec& vb)
  {
  Vec a, b; 

  a.sub(va, v0);
  b.sub(vb, v0);

  m_N.cross(a, b);
  m_N.normalize(); 
  m_D = -m_N.dot(v0); // V dot N = -d
  }

/****************************************************************************/
/** \brief Testet, ob ein Punkt (Vektor) innerhalb, ausserhalb oder auf 
           der Ebene liegt.
      
    \param v0 Der Punkt
    \return OUTSIDE  --> Der Punkt liegt ausserhalb der Ebene
            INSIDE   --> Der Punkt liegt innerhalb der Ebene 
            INPLANE  --> Der Punkt liegt genau in der Ebene
*******************************************************************************/
int Plane::check(Vec& v0)
  {
  float erg = m_N.dot(v0) + m_D;

  if (erg >  0.00001) return (OUTSIDE);
  if (erg < -0.00001) return (INSIDE);
  return (INPLANE);
  }


/****************************************************************************/
/** \brief Liefert die Distanz der Linie zur Ebene.
      
Damit ist die Laenge vom Startpunkt der Linie bis zur Ebene gemeint. 
Diese Laenge ist Normiert. 
Die Laenge einer Linie/Strahls ist normalerweise unendlich.
Mann kann aber ein Polygonsegment (hier Tilesegment) in eine Linie mit einer
festen Laenge umwandeln. Vergleicht mann die Laenge des Tilesegments mit der
der Distanz t zur Plane weiss mann, ob das Tilesegment die Plane schneidet.
Wichtig: um beide laengen vergleichen zu koennen, muss die Laenge der Tile-
segments normiert werden.
Es gilt:
    Wenn t < 0 dann liegt die Ebene 'hinter' dem Segment
    Wenn t > (normierte) Laenge des Segments, ist das Segment zu kurz, und
    schneidet die Ebene nicht.
    Nur wenn (0 <=t) && t < SegLen) schneidet die Linie die Ebene.
 Der Schnittpunkt selbst kann mit line.getEndPoint(t) ermittelt werden.   
    
 
     -(N * S + D)
 t = ------------
         N * V
         
 \param P Line
 \param dist Distanz 
 \return true->Schnittpunkt, false->kein Schnittpunkt, dist bleibt unveraendert
         (kann Double.NaN sein, wenn kein Schnittpunkt vorliegt)
*******************************************************************************/
bool Plane::intersect(Line& P, float* dist)
   {
   Vec N; 

   N.set(m_N);
   float b = N.dot(P.m_V);
 
   if (fabs(b) < 0.00001)
      return (false); 
 
   *dist = m_intersectLength = (-(N.dot(P.m_S) + m_D)) / b;

   return (true);
   }
  
/****************************************************************************/
/** \brief Liefert die Distanz zur Intersection zurueck
    \return laenge
*****************************************************************************/
float Plane::getInterLegth()   
   {
   return (m_intersectLength); 
   }
    
/****************************************************************************/
/** \brief Obligatorische Dumb-Methode fuer Debugzwecke
    \param msg Text
*****************************************************************************/
void Plane::dump(char* msg)
   {
   msg; // makes compiler happy
//  System.out.println(msg);
//  System.out.println("Plane.m_D=" + m_D); 
//  System.out.println("Plane.m_N=" + m_N.dump() );
//  System.out.println("Plane.m_P=" + m_P.dump());
  }
