/*******************************************************************************
+
+  LEDA 3.5
+
+  d3_plane.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_PLANE_H
#define LEDA_D3_PLANE_H

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


#include <LEDA/vector.h>
#include <LEDA/d3_point.h>
#include <LEDA/d3_plane.h>

class d3_plane;

//------------------------------------------------------------------------------
// d3_planes
//------------------------------------------------------------------------------

class d3_plane_rep  : public handle_rep {

friend class d3_plane;
friend int side_of(const d3_plane&, const d3_point&);

static leda_mutex mutex_id_counter;
static unsigned long id_counter;
   
   d3_point a;
   double     nx;
   double     ny;
   double     nz;

   unsigned long id;

public:
    
   d3_plane_rep(const d3_point&, const double&, const double&, 
                                                         const double&);
  ~d3_plane_rep() {}

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

/*{\Manpage {d3_plane} {} {Planes}}*/

class d3_plane  : public handle_base 
{
/*{\Mdefinition
An instance $P$ of the data type |\Mname| is an oriented plane in the 
three-dimensional space $\real^3$. It can be defined by a tripel ($a$,$b$,$c$)
of non-collinear points or a single point $a$ and a normal vector $v$. }*/


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

public:

/*{\Mcreation p }*/

 d3_plane();
/*{\Mcreate introduces a variable |\Mvar| of type |\Mname| initialized 
            to the trivial plane.}*/

 d3_plane(const d3_point& a, const d3_point& b, const d3_point& c);
/*{\Mcreate introduces a variable |\Mvar| of type |\Mname| initialized to 
            the plane through $(a,b,c)$.\\
             \precond $a$, $b$, and $c$ are not collinear. }*/

 d3_plane(const d3_point& a, const vector& v);
/*{\Mcreate introduces a variable |\Mvar| of type |\Mname| initialized 
            to the plane that contains $a$ with normal vector $v$.\\
            \precond |v.dim()| = 3 and |v.length() > 0|. }*/

 d3_plane(const d3_point& a, const d3_point& b);
/*{\Mcreate introduces a variable |\Mvar| of type |\Mname| initialized 
            to the plane that contains $a$ with normal vector $b-a$.}*/

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

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


/*{\Moperations 2 4}*/

d3_point point1() const { return ptr()->a; }
/*{\Mop     returns the first point of |\Mvar|.}*/

vector  normal() const 
{ return vector(ptr()->nx,ptr()->ny,ptr()->nz); }
/*{\Mop     returns a normal vector of |\Mvar|.}*/

d3_plane to_d3_plane() const;
/*{\Xop  for compatibility with |d3_rat_plane|. }*/


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

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


vector normal_project(const d3_point& q) const;
/*{\Mop     returns the vector pointing from |q| to its projection
            on |\Mvar| along the normal direction.}*/


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


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

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


d3_plane reflect(const d3_plane& Q) const;
/*{\Mop     returns |\Mvar| reflected  across plane $Q$.}*/

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

d3_point reflect_point(const d3_point& q) const;
/*{\Mop     returns |q| reflected across plane |\Mvar|.}*/

int side_of(const d3_point& q) const;
/*{\Mop computes the side of |\Mvar| on which |q| lies. }*/

bool contains(const d3_point& q) const { return side_of(q) == 0;}
/*{\Mop     returns true if point |q| lies on plane |\Mvar|, i.e.,
            (|\Mvar.side_of(q) == 0|), and false otherwise. }*/

bool parallel(const d3_plane& Q) const;
/*{\Mop     returns true if planes |\Mvar| and |Q| are parallel and
            false otherwise. }*/


int operator==(const d3_plane& Q) const;
int operator!=(const d3_plane& Q) const { return !operator==(Q);}


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

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


friend unsigned long ID_Number(const d3_plane&);

};


inline unsigned long ID_Number(const d3_plane& p) { return p.ptr()->id; }
inline char* leda_tname(const d3_plane*) { return "d3_plane"; }


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

#endif

