/*
 * ADAPT2D : a software for automatic mesh adaptation in 2D
 *
 * AUTHOR : Manuel J. Castro Diaz(e-mail:castro@gamba.cie.uma.es)
 * ADAPTED FOR FREEFEM : Prud'homme Christophe (e-mail:prudhomm@ann.jussieu.fr) 
 *
 * this code is public domain
 * 
 * You may copy freely these files and use it for    
 * teaching or research. These or part of these may   
 * not be sold or used for a commercial purpose without
 * our consent
 * 
 * Any problems should be reported to the AUTHOR
 * at the following address : castro@gamba.cie.uma.es
 */


#ifndef _R2_h
#define _R2_h

#include <header.hxx>

class Metrica;
class R2xR2;
class R2 {
  friend ostream& operator<<(ostream&, R2&);
  friend istream& operator>>(istream&, R2&);
public:  
  Scalar x,y;
  R2 () :x(0),y(0) {};
  R2 (Scalar a,Scalar b=0):x(a),y(b)  {}
  void set (Scalar a, Scalar b) {x=a; y=b;}
  void set (R2 c) {x=c.x;y=c.y;}
  R2   operator+(R2 cc) {return R2(x+cc.x,y+cc.y);}
  R2   operator-(R2 cc) {return R2(x-cc.x,y-cc.y);}
  Scalar   operator*(R2 cc) {return  x*cc.x+y*cc.y;} // Scalar Product.
  R2   operator*(Scalar cc) {return R2(x*cc,y*cc);}
  R2   operator/(Scalar cc) {return R2(x/cc,y/cc);}
  R2   operator*(R2xR2 cc);
  R2&   operator=(const R2& c) { 
         x=c.x;
         y=c.y;
         return (*this);
  }

  R2&   operator*= (Scalar cc) {
    x*=cc;
    y*=cc;
    return (*this);
} 
  void write(ostream&);

  int operator==(R2 cc) {
     int v=0;
     if (x==cc.x && y==cc.y) v=1;
     return v;
  }
  int operator!=(R2 cc) {
     int v=0;
     if (x!=cc.x || y!=cc.y) v=1;
     return v;
}
 
  Scalar norme() { return sqrt ((*this)*(*this));}
  Scalar norma() { return sqrt ((*this)*(*this));}
  friend R2   maximo(R2,R2); 
  friend R2   minimo(R2,R2); 
  friend Scalar maximo(R2); 
  friend Scalar minimo(R2);
  friend Scalar maximo(R2, int&);
  friend Scalar minimo(R2, int&);
  friend Scalar distance(R2,R2);
  friend Scalar distance (R2,Metrica,R2,Metrica);
  friend Scalar norme (R2,Metrica);
  friend Scalar distance0 (R2,Metrica,R2,Metrica);
  friend Scalar norme0 (R2,Metrica);

  friend Scalar angle(R2, R2);     
  friend Scalar proyec(R2,R2,R2,R2&,Scalar&);
  friend R2     coor_b(R2,R2,R2,R2);
};


class R2xR2 {
  friend ostream& operator <<(ostream& f, R2xR2 & c) ;
  friend R2xR2 inter(R2xR2,R2xR2);
  friend R2xR2 intersec(R2xR2,R2xR2);
  friend R2xR2 matriz(Scalar,R2,Scalar,R2);
  friend void writep(R2xR2*,ostream&);
 public:
  R2 x,y; 
  R2xR2 (): x(),y()  {}
  R2xR2 (R2 a,R2 b): x(a),y(b) {}
  R2xR2 (Scalar xx,Scalar xy,Scalar yx,Scalar yy) :x(xx,xy),y(yx,yy) {}

  void set (R2 a,R2 b) { x.x=a.x; x.y=a.y; y.x=b.x; y.y=b.y;}
  void set (Scalar xx,Scalar xy,Scalar yx,Scalar yy) {
   x.x=xx; x.y=xy;
   y.x=yx; y.y=yy; }
  R2xR2& operator=(const R2xR2& m0) {
   x=m0.x;
   y=m0.y;
   return (*this);
  }
  R2 operator*(R2 c) {return R2(x.x*c.x + x.y*c.y, y.x*c.x + y.y*c.y);}
  R2xR2 operator*(R2xR2);
  R2xR2 operator*(Scalar c) { return R2xR2(x.x*c,x.y*c,y.x*c,y.y*c);}
  R2xR2 operator+(R2xR2 m0) { 
     return R2xR2(x.x+m0.x.x,x.y+m0.x.y,y.x+m0.y.x,y.y+m0.y.y);
  }
  R2xR2 operator/(Scalar c) {
    R2xR2 m0;   
    if (c!=0) { 
      m0.set(x.x/c,x.y/c,y.x/c,y.y/c);
    }
    else {
      cerr<<"Atencion. Division por cero."<<endl;
      cerr<<"Error: R2xR2::operator/."<<endl;
      exit(1);
    }
    return m0;
  }
  Scalar det(){return x.x*y.y - x.y*y.x;}
  void vecpro(Scalar&,R2&,Scalar&,R2&);
  void vecpro1(Scalar&,R2&,Scalar&,R2&);
  R2xR2 truncada(Scalar,Scalar);
  R2xR2 metriz(Boolean);
  R2xR2 transwall(Scalar,R2);
  R2xR2 inv() 
     { Scalar d = (*this).det();
       if (fabs(d)<1e-30) {
          cerr<<"Atencion. La matriz no es inversible."<<endl;
          cerr<<"Error: R2xR2::inv."<<endl;
          cerr<<*(this)<<endl;
          cerr<<"det:"<<d<<endl;
          d=1e-30;
       } 
       return R2xR2(y.y /d ,-x.y/d, -y.x/d, x.x/d );
     };
   R2xR2 transpose() {return R2xR2(x.x,y.x,x.y,y.y);} //transposer 
  ~R2xR2() {DEL(R2xR2())}
   void write (ostream&);
};  


inline R2  R2::operator*(R2xR2 cc) {return R2(x*cc.x.x + y*cc.y.x, x*cc.x.y + y*cc.y.y);} 

#endif
