/*******************************************************************************
+
+  LEDA 3.5
+
+  line.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_LINE_H
#define LEDA_LINE_H

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


#include <LEDA/point.h>
#include <LEDA/segment.h>
#include <LEDA/ray.h>

//------------------------------------------------------------------------------
// straight lines
//------------------------------------------------------------------------------


class line_rep : public handle_rep {

friend class line;
friend class circle;

  segment  seg; 

public:
   
  line_rep() {}
  line_rep(const segment& s) : seg(s) {}

 ~line_rep() {}

friend inline int cmp_slopes(const line&, const line&);
friend inline int orientation(const line&, const point&);

};
   
/*{\Manpage {line} {} {Straight Lines}}*/

class line   : public handle_base 
{

friend class circle;

/*{\Mdefinition
An instance $l$ of the data type $line$ is a directed straight line
in the two-dimensional plane. The angle between a right oriented horizontal
line and $l$ is called the direction of $l$.}*/

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

public:

/*{\Mcreation l }*/

 line(const point& p, const point& q);
/*{\Mcreate 
introduces a variable |\Mvar| of type |\Mname|. |\Mvar| is initialized to the 
line passing through points $p$ and $q$ directed form $p$ to $q$.}*/


 line(const segment& s);
/*{\Mcreate 
introduces a variable |\Mvar| of type |\Mname|. |\Mvar| is initialized to the 
line supporting segment $s$.}*/

 line(const ray& r);
/*{\Mcreate 
introduces a variable |\Mvar| of type |\Mname|. |\Mvar| is initialized to the 
line supporting ray $r$.}*/

 line(const point& p, const vector& v);
/*{\Mcreate 
introduces a variable |\Mvar| of type |\Mname|. |\Mvar| is initialized to the 
line passing through points $p$ and $p+v$.}*/

 line(const point& p, double alpha);
/*{\Mcreate 
introduces a variable |\Mvar| of type |\Mname|. |\Mvar| is initialized to the 
line passing through point $p$ with direction $alpha$.}*/

 line();
/*{\Mcreate 
introduces a variable |\Mvar| of type |\Mname|. |\Mvar| is initialized to the 
line passing through the origin with direction 0.}*/


 line(const line& l) : handle_base(l) {};
 line& operator=(const line& l) { handle_base::operator=(l); return *this; }
~line() {}



/*{\Moperations 2 4.5 }*/

point   point1() const { return ptr()->seg.source(); }
/*{\Mop     returns a point on |\Mvar|.}*/

point   point2() const { return ptr()->seg.target(); }
/*{\Mop     returns a second point on |\Mvar|.}*/

segment seg()   const  { return ptr()->seg; }
/*{\Mop     returns a segment on |\Mvar|.}*/

line   to_line() const { return *this; }
/*{\Xop  for compatibility with rat_line. }*/


double direction() const { return angle(); }
/*{\Mop     returns the direction of |\Mvar|.}*/

double angle(const line& g) const { return ptr()->seg.angle(g.ptr()->seg); }
/*{\Mop     returns the angle between |\Mvar| and $g$, i.e., 
	    $g$.direction() $-$ |\Mvar|.direction().}*/

double angle() const     { return ptr()->seg.angle();     }
/*{\Mop     returns |\Mvar|.direction().}*/

bool is_vertical() const    { return ptr()->seg.is_vertical();  }
/*{\Mop     returns true iff |\Mvar| is vertical.}*/

bool is_horizontal() const  { return ptr()->seg.is_horizontal();}
/*{\Mop     returns true iff |\Mvar| is horizontal.}*/


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

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



double slope() const     { return ptr()->seg.slope();     }
/*{\Mop     returns the slope of |\Mvar|.\\
	    \precond  |\Mvar|  is not vertical.}*/

double y_proj(double x) const  { return ptr()->seg.y_proj(x); };
/*{\Mop     returns $p$.ycoord(), where $p \in l$ with $p$.xcoord() 
	    = $x$.\\ \precond |\Mvar| is not vertical.}*/

double x_proj(double y) const  { return ptr()->seg.x_proj(y); };
/*{\Mop     returns $p$.xcoord(), where $p \in l$ with $p$.ycoord() 
	    = $y$.\\ \precond |\Mvar| is not horizontal.}*/

double y_abs() const { return ptr()->seg.y_proj(0); }
/*{\Mop     returns the y-abscissa of |\Mvar| (|\Mvar|.y\_proj(0)).\\
	    \precond  |\Mvar|  is not vertical.}*/

bool intersection(const line& g, point& p) const;
/*{\Mopl    if |\Mvar| and $g$ intersect in a single point this point
            is assigned to $p$ and the result is true, otherwise 
            the result is false. }*/

bool intersection(const segment& s, point& inter) const;
/*{\Mopl    if |\Mvar| and $s$ intersect in a single point this point
            is assigned to $p$ and the result is true, otherwise 
            the result is false. }*/

line translate_by_angle(double a, double d) const 
{ return ptr()->seg.translate_by_angle(a,d); }
/*{\Mopl     returns |\Mvar| translated in direction $a$ by distance $d$.}*/

line translate(double dx, double dy) const 
{ return ptr()->seg.translate(dx,dy); }
/*{\Mopl     returns |\Mvar| translated by vector $(dx,dy)$.}*/

line translate(const vector& v)  const 
{ return ptr()->seg.translate(v); }
/*{\Mopl     returns |\Mvar| translated by vector $v$
	    \precond $v$.dim() = 2.}*/ 

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

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


line rotate(const point& q, double a) const
{ return ptr()->seg.rotate(q,a); }
/*{\Mopl    returns |\Mvar| rotated about point $q$ by angle $a$.}*/

line rotate(double a) const  
{ return rotate(point(0,0),a);}
/*{\Mop     returns $l$.rotate($point(0,0),\ a$). }*/

line rotate90(const point& q) const
{ return ptr()->seg.rotate90(q); }
/*{\Mopl    returns |\Mvar| rotated about $q$ by angle of $90$ degrees.}*/


line reflect(const point& p, const point& q) const
{ return ptr()->seg.reflect(p,q); }
/*{\Mop     returns |\Mvar| reflected  across the straight line passing
            through $p$ and $q$.}*/


segment perpendicular(const point& p) const;
/*{\Mop    returns the segment perpendicular to |\Mvar| with source $p$.
           and target on |\Mvar|.}*/



bool contains(const point&) const;
bool contains(const segment&) const;


bool operator==(const line& g) const { return contains(g.ptr()->seg); }

bool operator!=(const line& g) const { return !contains(g.ptr()->seg); }


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


friend int orientation(const line& l, const point& p);
/*{\Mfunc      computes orientation($a$, $b$, $p$), where $a \not= b$
and $a$ and $b$ appear in this order on line $l$. }*/

friend int cmp_slopes(const line& l1, const line& l2);
/*{\Mfunc      returns compare(slope($l_1$), slope($l_2$)).}*/


friend ostream& operator<<(ostream& out, const line& l);
friend istream& operator>>(istream& in, line& l);  

};

inline  int orientation(const line& l, const point& p)
{ return orientation(l.ptr()->seg,p); }

inline  int cmp_slopes(const line& l1, const line& l2)
{ return cmp_slopes(l1.ptr()->seg,l2.ptr()->seg); }

inline bool parallel(const line& l1, const line& l2)
{ return cmp_slopes(l1,l2) == 0; }


extern line p_bisector(const point& p, const point& q);


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

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

#endif
