/*
 *  basicas.cpp
 *  GC
 *
 *  Created by Chema on 10/21/09.
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
 *
 */
#include <math.h>
#include <iostream>
#include "vec.h"
#include "basicas.h"

using namespace std;

// namespace sin nombre para que no entren en conflicto con las estándar
namespace {
    const real epsilon = 1e-06f;
//    real max ( real a, real b ) { return (b<a)?a:b; }
//    real min ( real a, real b ) { return (b>a)?a:b; }
}

//Distancia entre dos puntos (longitud de un segmento)
//real dist (const Real2& a, const Real2& b) {
//    return (b-a).norm();
//}

//Area (signada) del paralelogramo (método de Ángel)
//real pgArea(const Real2& a, const Real2& b, const Real2& c) {
//    return ( (b.x() - a.x())*(c.y() - a.y()) - (b.y() - a.y())*(c.x() - a.x()) );
//}

//Area (signada) del triángulo
//real triArea(const Real2& a, const Real2& b, const Real2& c) {
//    return 0.5f*pgArea(a,b,c);
//}

//Signo del área signada de un triángulo
//int signoArea(const Real2& a, const Real2& b, const Real2& c) {
//    real area = pgArea(a,b,c);
//    return area > 0? 1: 
//           area < 0? -1:
//           0;
//}

//Test de tres puntos alineados
//bool alineados (const Real2& a, const Real2& b, const Real2& c) {
//    return signoArea(a,b,c) == 0;
//}

//Distancia de punto a recta (p punto, a y b puntos de linea)
real distPtRecta (const Real2& p, const Real2& a, const Real2& b) {
    return dotProd(p-a, normalize(orthogonal(a-b)));
}

//Distancia de punto a segmento
real distPtSegmento (const Real2& p, const Real2& a, const Real2& b) {
    Real2 perp = orthogonal(b-a);
    if (signoArea(a, a+perp, p) > 0) {
        return dist(a,p);
    }
    if (signoArea(b, b+perp, p) < 0) {
        return dist(b,p);
    }
    else {
        return distPtRecta(p, a, b);
    }
}

//Distancia de punto a circunferencia
float distPtCircunf (const Real2& p, const Real2& cOri, real cRadio) {
    return dist(p,cOri)-cRadio;
}

//Distancia angular entre dos vectores
float distAngular (const Real2& a, const Real2& b) {
    float arc = acos(dotProd( normalize(b), normalize(a) ) );
    return signoArea(Real2(0,0), a, b) >= 0 ? arc : 2*Pi -arc;
}

//Test de inclusión de punto en triángulo (p punto, a b c triángulo)
bool testPtEnTri (const Real2& p, const Real2& a, const Real2& b, const Real2& c) {
    bool ret = true;
//    cout << "abc:"<<signoArea(a,b,c)<<endl;
//    cout << "abp:"<< signoArea(a,b,p)<<endl;
//    cout << "bcp:"<<signoArea(b,c,p)<<endl;
//    cout << "cap:"<<signoArea(c,a,p)<<endl;
    real signo = signoArea(a,b,c);
    
    if (signo == 1) {
        if (signoArea(a,b,p)<0 || signoArea(b,c,p)<0 || signoArea(c,a,p) <0) {
            ret=false;
        }
    }
    else if (signo == -1) {
        if (signoArea(a,b,p)>0 || signoArea(b,c,p)>0 || signoArea(c,a,p) >0) {
            ret=false;
        }
    }
    else if (!alineados(a,b,p)) {
        ret = false;
    }
    return ret;
}

//Test de inclusión de punto en segmento
//bool testPtEnSeg(const Real2& p, const Real2& a, const Real2& b) {
//    bool ret = false;
//    if (alineados(a,b,p) ) {
//        Real2 b2a = a-b;
//        if (fabs(b2a.x()) > fabs(b2a.y()) ) {
//            ret = min(a.x(),b.x())<=p.x() && p.x()<=max(a.x(),b.x());
//        }
//        else {
//            ret = min(a.y(),b.y())<=p.y() && p.y()<=max(a.y(),b.y());
//        }
//    }
//    return ret;
//}

//Test de intersección de dos segmentos
//bool testIntersecxSegs(const Real2& a, const Real2& b, const Real2& c, const Real2& d) {
//    bool ret = true;
//    if (alineados(a,b,c) && alineados(a,b,d) ) 
//    {
//        if (testPtEnSeg(c,a,b) || testPtEnSeg(d,a,b)) {
//            ret = true;
//        }
//    } // ret = true
//    else if (signoArea(a,b,c) == signoArea(a,b,d)) {
//        ret = false; // s,t está completamente en uno de los semiplano de a,b
//    }
//    else if (signoArea(a,c,d) == signoArea(b,c,d)) {
//        ret = false; // s,t no corta a,b ni pasa por a ó b 
//    }
//    return ret;
//}

//Intersección de dos rectas 
//Entrada:  a,b=recta1 
//          c,d=recta2
//Salida:   true si hay intersección, false caso contrario
//          solapan = true si las rectas son idénticas, 
//          p = punto intersección (sólo válido si valor retorno=true y solapan=false)
//bool intersecxRectas(const Real2& a, const Real2& b, const Real2& c, const Real2& d, bool& solapan, Real2& p, real& ua, real & ub) {
//    bool ret = false;
//    
//    real numa = (d.x()-c.x())*(a.y()-c.y()) - (d.y()-c.y())*(a.x()-c.x());
//    real numb = (b.x()-a.x())*(a.y()-c.y()) - (b.y()-a.y())*(a.x()-c.x());
//    real den = (d.y()-c.y())*(b.x()-a.x()) - (d.x()-c.x())*(b.y()-a.y());
//
//    if (fabs (den) > epsilon) {
//        ua = numa/den;
//        ub = numb/den;
//        p = a+ ua*(b-a);
//        ret = true;
//    }
//    else if (fabs(numa) < epsilon && fabs(numb) < epsilon) {
//        solapan = true;
//        ret = true;
//    }
//    return ret;
//}
   

//Intersección de recta y segmento
//Entrada:  a,b=recta1 
//          s1,s2=segmento
//Salida:   true si hay intersección, false caso contrario
//          solapa = true si la recta1 y la recta del segmento son idénticas, 
//          p = punto intersección (sólo válido si valor retorno=true y solapan=false)
bool intersecxRectaSeg(const Real2& a, const Real2& b, const Real2& s1, const Real2& s2, bool& solapan, Real2& p) {
    bool ret = false;
    real ua,ub;
    if (intersecxRectas(a,b,s1,s2, solapan, p, ua, ub) ) {
        if (solapan) {
            ret = true;
        }
        else if (ub>0 && ub<=1) {
            ret=true;
        }
    }
    return ret;
}

// Circuncentro del triangulo (centro del circulo que pasa por los tres vertices)
bool triCcentro(const Real2& a, const Real2& b, const Real2& c, Real2& cc) {
    bool ret = false;

    const Real2 AB = b-a;
    const Real2 oAB = orthogonal(AB);
    const Real2 mAB = (a+b)*static_cast<real> (0.5);
    const Real2 BC = c-b;
    const Real2 oBC = orthogonal(BC);
    const Real2 mBC = (b+c)*static_cast<real> (0.5);
    const Real2 CA = a-c;
    const Real2 oCA = orthogonal(CA);
    const Real2 mCA = (c+a)*static_cast<real> (0.5);

    bool solapan0=false;
    Real2 p0;
    real ua0,ub0;
    bool ret0 = intersecxRectas(mAB, mAB+oAB, mBC, mBC+oBC, solapan0, p0, ua0, ub0);

    bool solapan1=false;
    Real2 p1;
    real ua1,ub1;
    bool ret1 = intersecxRectas(mBC, mBC+oBC, mCA, mCA+oCA, solapan1, p1, ua1, ub1);
    
    bool solapan2=false;
    Real2 p2;
    real ua2,ub2;
    bool ret2 = intersecxRectas(mCA, mCA+oCA, mAB, mAB+oAB, solapan2, p2, ua2, ub2);
    
    if (ret0 && ret1 && ret2 && !(solapan0 || solapan1 || solapan2)) {
        ret = true;
        cc = (p0+p1+p2)/3;
    }
    return ret;
}
