#include "math.h"
#include "jv.h"

#define _MIN_(a,b) (a<b)?a:b 
#define _MAX_(a,b) (a>b)?a:b 

float modulo( jvLine seg_z )
{
   float dx = seg_z.v1x-seg_z.v2x ;
   float dy = seg_z.v1y-seg_z.v2y ;

   return (float)sqrt(  (dx*dx) +  (dy*dy) ) ;
}


float razao( jvLine seg_z, jvLine seg_w )
{
   float mz = modulo( seg_z ) ;
   float mw = modulo( seg_w ) ;

   return (  _MIN_(mz, mw) / _MAX_(mz, mw) ) ;
}


/* Descobre ONDE duas RETAS definidas pelos segmentos se cruzam
   Se são paralelas retorna 0 e lixo em x e y
*/
int intersecao( jvLine seg_z, jvLine seg_w, float *x, float *y )
{ 
   double  az , bz , cz ;
   double  aw , bw , cw ;

   double tol = .001 ;

//  Equação da reta definida por um segmento:
//
//      V1          P           V2
//   ---o-----------o------------o-----
//
//    ( P - V1 )  //  ( V2 - V1 )
//
//    ( x - x1 ) / ( x2 - x1 )  =  ( y - y1 ) / ( y2 - y1 )
//
//    ( x - x1 ) * ( y2 - y1 )  =  ( y - y1 ) * ( x2 - x1 )  
//
//  [ (y2-y1) x ] +  [  -(x2-x1) y ] + [  -(y2-y1).x1 + (x2-x1).y1 ] = 0  
//
//       a    x   +         b    y   +                c              = 0 
//
   az = (double)   ( seg_z.v2y - seg_z.v1y ) ;
   bz = (double)  -( seg_z.v2x - seg_z.v1x ) ;
   cz = (double)( -( seg_z.v2y - seg_z.v1y ) * seg_z.v1x ) + ( ( seg_z.v2x-seg_z.v1x ) * seg_z.v1y ) ;

   aw = (double)   ( seg_w.v2y - seg_w.v1y ) ;
   bw = (double)  -( seg_w.v2x - seg_w.v1x ) ;
   cw = (double)( -( seg_w.v2y - seg_w.v1y ) * seg_w.v1x ) + ( ( seg_w.v2x-seg_w.v1x ) * seg_w.v1y ) ;

   // verificando se as retas sao paralelas
   // trivial -> duas retas horizontais
   if( aw == 0 && az == 0 )
   {
      return 0 ;
   }else
   // trivial -> duas retas vericais
   if( bw == 0 && bz == 0 )
   {
      return 0 ;
   }else
   // duas retas inclinadas
   if( (aw != 0 && bw != 0) && (az != 0 && bz != 0) )
   {
      if( (az/aw < (bz/bw + tol))  && (az/aw > (bz/bw - tol)) )
      {
         return 0 ;
      }
   }
   // Qualquer outro caso não são paralelas

//  Determinando o ponto de intersecao
//                                                 _
//        aw  x0   +     bw  y0   +     cw  =  0    \
//        az  x0   +     bz  y0   +     cz  =  0   _/
//                                                 _
//     az aw  x0   +  az bw  y0   +  az cw  =  0    \
//     aw az  x0   +  aw bz  y0   +  aw cz  =  0   _/
//                                                 _
//     az aw  x0   +  az bw  y0   +  az cw  =  0    \
//  -  aw az  x0   -  aw bz  y0   -  aw cz  =  0   _/
//
//   ( az aw - aw az ) x0  +  ( az bw - aw bz ) y0  +  ( az cw - aw cz )  =  0 
//
//   y0  =  -( az cw - aw cz ) / ( az bw - aw bz )
//
   *y = (float)(-( az*cw - aw*cz ) / ( az*bw - aw*bz )) ;
//
//   aw  x0   +     bw  y0   +     cw  =  0 
//   az  x0   +     bz  y0   +     cz  =  0 
//
//   x0  =  ( -cw - ( bw y0 ) ) / aw 
//   x0  =  ( -cz - ( bz y0 ) ) / az
//
   if( aw != 0 )
      *x = (float)(( - cw - ( bw*(*y) ) ) / aw)  ;
   else
      *x = (float)(( - cz - ( bz*(*y) ) ) / az)  ;

   return 1 ;

}


/* descobre SE dois SEGMENTOS estão se cruzando */
int cruzando( jvLine seg_z, jvLine seg_w )
{ 
   double  az , bz , cz ;
   double  aw , bw , cw ;

   double  d_v1z_rw ,
           d_v2z_rw ;

   double  d_v1w_rz ,
           d_v2w_rz ;

   double  mod_normal ;


//  Equação da reta definida por um segmento:
//
//      V1          P           V2
//   ---o-----------o------------o-----
//
//    ( P - V1 )  //  ( V2 - V1 )
//
//    ( x - x1 ) / ( x2 - x1 )  =  ( y - y1 ) / ( y2 - y1 )
//
//    ( x - x1 ) * ( y2 - y1 )  =  ( y - y1 ) * ( x2 - x1 )  
//
//  [ (y2-y1) x ] +  [  -(x2-x1) y ] + [  -(y2-y1).x1 + (x2-x1).y1 ] = 0  
//
//       a    x   +         b    y   +                c              = 0 
//
   az = (double)   ( seg_z.v2y - seg_z.v1y ) ;
   bz = (double)  -( seg_z.v2x - seg_z.v1x ) ;
   cz = (double)( -( seg_z.v2y - seg_z.v1y ) * seg_z.v1x ) + ( ( seg_z.v2x-seg_z.v1x ) * seg_z.v1y ) ;

   aw = (double)   ( seg_w.v2y - seg_w.v1y ) ;
   bw = (double)  -( seg_w.v2x - seg_w.v1x ) ;
   cw = (double)( -( seg_w.v2y - seg_w.v1y ) * seg_w.v1x ) + ( ( seg_w.v2x-seg_w.v1x ) * seg_w.v1y ) ;


// Distância de P0 = ( x0 , y0 ) a reta  aX + bY + c = 0
//
//   d = (  a * x0   +  b * y0  +  c  ) / (  sqrt( a^2 + b^2 )  ) 
// 
   // distancia dos vertices de seg_z a reta w
   mod_normal = sqrt( aw*aw + bw*bw ) ;
   d_v1z_rw = (double)( aw * seg_z.v1x   +  bw * seg_z.v1y  +  cw ) / ( mod_normal ) ;
   d_v2z_rw = (double)( aw * seg_z.v2x   +  bw * seg_z.v2y  +  cw  ) / ( mod_normal ) ;

   // distancias dos vertices de seg_w a reta z
   mod_normal = sqrt( az*az + bz*bz ) ;
   d_v1w_rz = (double)( az * seg_w.v1x   +  bz * seg_w.v1y  +  cz ) / ( mod_normal ) ;
   d_v2w_rz = (double)( az * seg_w.v2x   +  bz * seg_w.v2y  +  cz ) / ( mod_normal ) ;

   // Se os dois vertices de seg_w cruzam a RETA Z e os dois vertices de seg_z
   // cruzam a RETA W então os dois SEGMENTOS se cruzam
   if( ( d_v1z_rw*d_v2z_rw <= 0 ) && ( d_v1w_rz*d_v2w_rz <= 0 ) )
   {
      return 1 ;
   }
   else
   {
      return 0 ;
   }
}

/* descobre a distancia da reta a um ponto */
float distancia_ponto( jvLine seg, float x, float y )
{ 
   double  a , b , c ;
   double  mod_normal ;
   float   d ;
   

//  Equação da reta definida por um segmento:
//
//      V1          P           V2
//   ---o-----------o------------o-----
//
//    ( P - V1 )  //  ( V2 - V1 )
//
//    ( x - x1 ) / ( x2 - x1 )  =  ( y - y1 ) / ( y2 - y1 )
//
//    ( x - x1 ) * ( y2 - y1 )  =  ( y - y1 ) * ( x2 - x1 )  
//
//  [ (y2-y1) x ] +  [  -(x2-x1) y ] + [  -(y2-y1).x1 + (x2-x1).y1 ] = 0  
//
//       a    x   +         b    y   +                c              = 0 
//
   a = (double)   ( seg.v2y - seg.v1y ) ;
   b = (double)  -( seg.v2x - seg.v1x ) ;
   c = (double)( -( seg.v2y - seg.v1y ) * seg.v1x ) + ( ( seg.v2x-seg.v1x ) * seg.v1y ) ;


// Distância de P0 = ( x0 , y0 ) a reta  aX + bY + c = 0
//
//   d = (  a * x0   +  b * y0  +  c  ) / (  sqrt( a^2 + b^2 )  ) 
// 
   mod_normal = sqrt( a*a + b*b ) ;
   d  = (float)(( a * x  +  b * y  +  c ) / ( mod_normal )) ;

   return d ;
}

/* descobre o quadrado da distancia da reta a um ponto */
float distancia_quad_ponto( jvLine seg, float x, float y )
{ 
   double  a , b , c ;
   double  normal_quad ;
   double  p_seg_quad  ;
   float   d ;
   

//  Equação da reta definida por um segmento:
//
//      V1          P           V2
//   ---o-----------o------------o-----
//
//    ( P - V1 )  //  ( V2 - V1 )
//
//    ( x - x1 ) / ( x2 - x1 )  =  ( y - y1 ) / ( y2 - y1 )
//
//    ( x - x1 ) * ( y2 - y1 )  =  ( y - y1 ) * ( x2 - x1 )  
//
//  [ (y2-y1) x ] +  [  -(x2-x1) y ] + [  -(y2-y1).x1 + (x2-x1).y1 ] = 0  
//
//       a    x   +         b    y   +                c              = 0 
//
   a = (double)   ( seg.v2y - seg.v1y ) ;
   b = (double)  -( seg.v2x - seg.v1x ) ;
   c = (double)( -( seg.v2y - seg.v1y ) * seg.v1x ) + ( ( seg.v2x-seg.v1x ) * seg.v1y ) ;


// Distância de P0 = ( x0 , y0 ) a reta  aX + bY + c = 0
//
//   d   = (  a * x0   +  b * y0  +  c  )   / (  sqrt( a^2 + b^2 )  ) 
//   d^2 = (  a * x0   +  b * y0  +  c  )^2 / (        a^2 + b^2    ) 
// 
   normal_quad = sqrt( a*a + b*b ) ;
   p_seg_quad  = a * x   +  b * y  +  c  ;
   p_seg_quad  *= p_seg_quad ;

   d  = (float)( p_seg_quad / normal_quad ) ;

   return d ;

}