/*******************************************************************************
+
+  LEDA 3.5
+
+  d3_point.h
+
+  This file is part of the LEDA research version (LEDA-R) that can be 
+  used free of charge in academic research and teaching. Any commercial
+  use of this software requires a license which is distributed by the
+  LEDA Software GmbH, Postfach 151101, 66041 Saarbruecken, FRG
+  (fax +49 681 31104).
+
+  Copyright (c) 1991-1997  by  Max-Planck-Institut fuer Informatik
+  Im Stadtwald, 66123 Saarbruecken, Germany     
+  All rights reserved.
+ 
*******************************************************************************/
#ifndef LEDA_D3_POINT_H
#define LEDA_D3_POINT_H

#if !defined(LEDA_ROOT_INCL_ID)
#define LEDA_ROOT_INCL_ID 350027
#include <LEDA/REDEFINE_NAMES.h>
#endif


#include <LEDA/list.h>
#include <LEDA/vector.h>
#include <LEDA/point.h>

class d3_point;

//------------------------------------------------------------------------------
// d3_points
//------------------------------------------------------------------------------

class d3_point_rep  : public handle_rep {

friend class d3_point;

static leda_mutex mutex_id_counter;
static unsigned long id_counter;
   
   double x;
   double y;
   double z;

   unsigned long id;

public:
    
   d3_point_rep(double=0, double=0, double=0);
  ~d3_point_rep() {}

friend inline unsigned long ID_Number(const d3_point&);
   
};

/*{\Manpage {d3_point} {} {Points}}*/

class d3_point  : public handle_base 
{
/*{\Mdefinition
An instance of the data type |\Mname| is a point in the three-dimensional
space $\real^3$. We use $(x,y,z)$ to denote a point with first (or x-)
coordinate $x$, second (or y-) coordinate $y$, and third (or z-) 
coordinate $z$.}*/


d3_point_rep* ptr() const { return (d3_point_rep*)PTR; }

public:

/*{\Mcreation p }*/

 d3_point();
/*{\Mcreate introduces a variable |\Mvar| of type |\Mname| initialized 
            to the point $(0,0,0)$.}*/

 d3_point(double x, double y, double z);
/*{\Mcreate introduces a variable |\Mvar| of type |\Mname| initialized to 
            the point $(x,y,z)$.}*/

 d3_point(vector v);
/*{\Mcreate introduces a variable |\Mvar| of type |\Mname| initialized 
            to the point $(v[0],v[1],v[2])$.\\
            \precond |v.dim() = 3|. }*/

// for compatibility with rat_d3_point. 
 d3_point(double x, double y, double z, double w);

 d3_point(const d3_point& p) : handle_base(p) {}
~d3_point() {}

d3_point& operator=(const d3_point& p) 
{ handle_base::operator=(p); return *this; }


/*{\Moperations 2 4}*/

double  xcoord()  const   { return ptr()->x; }
/*{\Mop     returns the first coordinate of |\Mvar|.}*/

double  ycoord()  const   { return ptr()->y; }
/*{\Mop     returns the second coordinate of |\Mvar|.}*/

double  zcoord()  const   { return ptr()->z; }
/*{\Mop     returns the third coordinate of |\Mvar|.}*/

vector  to_vector() const { return vector(xcoord(),ycoord(),zcoord()); }
/*{\Mop     returns the vector $\vec{xy}$.}*/

d3_point to_d3_point() const { return *this; }
/*{\Xop  for compatibility with |d3_rat_point|. }*/

double  X()   const   { return xcoord(); }
double  XD()  const   { return xcoord(); }
/*{\Xop  for compatibility with |d3_rat_point|. }*/

double  Y()   const   { return ycoord(); }
double  YD()  const   { return ycoord(); }
/*{\Xop  for compatibility with |d3_rat_point|. }*/

double  Z()   const   { return zcoord(); }
double  ZD()  const   { return zcoord(); }
/*{\Xop  for compatibility with |d3_rat_point|. }*/

double  W()   const   { return 1; }
double  WD()  const   { return 1; }
/*{\Xop  for compatibility with |d3_rat_point|. }*/

int     dim() const { return 3; }
/*{\Xop  returns 3.}*/


point project_xy() const;
/*{\Mop  returns |\Mvar| projected into the xy-plane. }*/

point project_yz() const;
/*{\Mop  returns |\Mvar| projected into the yz-plane. }*/

point project_xz() const;
/*{\Mop  returns |\Mvar| projected into the xz-plane. }*/


double  sqr_dist(const d3_point& q) const;
/*{\Mop     returns the square of the Euclidean distance between |\Mvar|
            and $q$.}*/

double xdist(const d3_point& q) const;
/*{\Mopl    returns the x-distance between |\Mvar| and $q$. }*/

double ydist(const d3_point& q) const;
/*{\Mopl    returns the y-distance between |\Mvar| and $q$. }*/

double zdist(const d3_point& q) const;
/*{\Mopl    returns the z-distance between |\Mvar| and $q$. }*/


double  distance(const d3_point& q) const;
/*{\Mop     returns the Euclidean distance between |\Mvar| and $q$.}*/


//double  angle(const d3_point& q, const d3_point& r) const;
//d3_point   translate_by_angle(double alpha, double d) const;


d3_point translate(double dx, double dy, double dz) const;
/*{\Mopl    returns |\Mvar| translated by vector $(dx,dy,dz)$.}*/


d3_point translate(const vector& v) const;
/*{\Mop     returns \Mvar$+v$, i.e., |\Mvar| translated by vector 
	    $v$.\\
	    \precond $v$.dim() = 3.}*/

d3_point operator+(const vector& v) const { return translate(v); }
/*{\Mbinop  returns |\Mvar| translated by vector $v$.}*/

d3_point operator-(const vector& v) const { return translate(-v); }
/*{\Mbinop  returns |\Mvar| translated by vector $-v$.}*/


d3_point reflect(const d3_point& q, const d3_point& r, const d3_point& s) const;
/*{\Mop     returns |\Mvar| reflected  across the plane passing
            through $q$, $r$ and $s$.}*/

d3_point reflect(const d3_point& q) const;
/*{\Mop     returns |\Mvar| reflected across point $q$. }*/


int operator==(const d3_point& q) const;
int operator!=(const d3_point& q)  const { return !operator==(q);}

vector operator-(const d3_point& q)  const
{ return vector(xcoord()-q.xcoord(),
                ycoord()-q.ycoord(),
                zcoord()-q.zcoord()); }
/*{\Mbinop  returns the difference vector of the coordinates.}*/



static int  cmp_xyz(const d3_point&, const d3_point&);

friend ostream& operator<<(ostream& O, const d3_point& p) ;
/*{\Mbinopfunc  writes |\Mvar| to output stream $O$.}*/

friend istream& operator>>(istream& I, d3_point& p) ;
/*{\Mbinopfunc  reads the coordinates of |\Mvar| (three $double$ numbers)
	        from input stream $I$.}*/

friend inline unsigned long ID_Number(const d3_point&);

};


inline int compare(const d3_point& a, const d3_point& b)
{ return d3_point::cmp_xyz(a,b); }



// geometric primitives

/*{\Mtext
{\bf Non-Member Functions}
\smallskip
}*/

d3_point center(const d3_point& a, const d3_point& b);
/*{\Mfuncl returns the center of $a$ and $b$, i.e. $a +\vec{ab}/2$. }*/

inline d3_point midpoint(const d3_point& a, const d3_point& b) 
{ return center(a,b); }
/*{\Mfuncl returns the center of $a$ and $b$. }*/



inline unsigned long ID_Number(const d3_point& p) { return p.ptr()->id; }

int orientation(const d3_point& a, const d3_point& b, 
                                             const d3_point& c,
                                             const d3_point& d);
/*{\Mfuncl computes the orientation of points $a$, $b$, $c$, and $d$ as
           the sign of the determinant\\
           \[ \left\Lvert \begin{array}{cccc} a_x & a_y &  a_z & 1\\
                                              b_x & b_y &  b_z & 1\\
                                              c_x & c_y &  c_z & 1\\
                                              d_x & d_y &  d_z & 1
                       \end{array} \right\Lvert \] 
   }*/


int orientation_xy(const d3_point& a, const d3_point& b, 
                                                const d3_point& c);
int orientation_yz(const d3_point& a, const d3_point& b, 
                                                const d3_point& c);
int orientation_xz(const d3_point& a, const d3_point& b, 
                                                const d3_point& c);


double volume(const d3_point& a, const d3_point& b, 
                                           const d3_point& c,
                                           const d3_point& d);
/*{\Mfuncl computes the signed volume of the simplex determined by $a$,$b$,
           $c$, and $d$,
           positive if $orientation(a,b,c,d) > 0$ and negative otherwise. }*/


bool collinear(const d3_point& a, const d3_point& b, 
                                            const d3_point& c);
/*{\Mfuncl returns true if points $a$, $b$, $c$ are collinear and
           false otherwise.}*/


int side_of_sphere(const d3_point& a, const d3_point& b, 
                                                const d3_point& c,
                                                const d3_point& d,
                                                const d3_point& e);
/*{\Mfuncl returns $+1$ ($-1$) if point $e$ lies on the positive (negative)
           side of the oriented sphere through points $a$, $b$, $c$, and $d$, 
           and $0$ if $d$ is contained in this sphere. }*/


inline bool insphere(const d3_point& a, const d3_point& b, const d3_point& c, 
                                                           const d3_point& d,
                                                           const d3_point& e)
{ return (orientation(a,b,c,d) * side_of_sphere(a,b,c,d,e)) > 0; }
/*{\Mfuncl returns $true$ if $e$ lies in the interior of the sphere
           through $a$, $b$, $c$, and $d$, and $false$ otherwise. }*/

inline bool outsphere(const d3_point& a, const d3_point& b, const d3_point& c, 
                                                           const d3_point& d,
                                                           const d3_point& e)
{ return (orientation(a,b,c,d) * side_of_sphere(a,b,c,d,e)) < 0; }
/*{\Mfuncl returns $true$ if $e$ lies in the exterior of the sphere
           through $a$, $b$, $c$, and $d$, and $false$ otherwise. }*/

inline bool onsphere(const d3_point& a, const d3_point& b, const d3_point& c, 
                                                           const d3_point& d,
                                                           const d3_point& e)
{ return side_of_sphere(a,b,c,d,e) == 0; }

/*{\Mfuncl returns $true$ if $a$, $b$, $c$, $d$, and $e$ lie on a common
           sphere. }*/

d3_point point_on_positive_side(const d3_point& a, const d3_point& b, 
                                                             const d3_point& c);
/*{\Mfuncl returns point $a + (b-a)\times (c-a)$. }*/


inline char* leda_tname(const d3_point*) { return "d3_point"; }


#if LEDA_ROOT_INCL_ID == 350027
#undef LEDA_ROOT_INCL_ID
#include <LEDA/UNDEFINE_NAMES.h>
#endif

#endif

