/*******************************************************************************
+
+  LEDA 3.5
+
+  rat_segment.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_RAT_SEGMENT_H
#define LEDA_RAT_SEGMENT_H

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


#include <LEDA/rat_point.h>
#include <LEDA/segment.h>

//------------------------------------------------------------------------------
// rat_segments
//------------------------------------------------------------------------------


class rat_segment_rep : public handle_rep {

static leda_mutex mutex_id_counter;
static unsigned long id_counter;

friend class rat_segment;
friend class rat_line;
   
   rat_point start;
   rat_point end;

   integer dx;
   integer dy;

   double dxd;
   double dyd;

   unsigned long id;

public:
   
   rat_segment_rep(const rat_point&, const rat_point&);
   rat_segment_rep();  
  ~rat_segment_rep() {}

   friend inline unsigned long ID_Number(const rat_segment& s);
   
};

/*{\Manpage {rat_segment} {} {Rational Segments} }*/


class rat_segment  : public handle_base {

/*{\Mdefinition
An instance $s$ of the data type $rat\_segment$ is a directed straight line
segment in the two-dimensional plane, i.e.,
a line segment $[p,q]$ connecting two rational points $p$ and $q$ (cf. 
\ref{Rational Points}). $p$ is called the {\em source} or start point and 
$q$ is called the {\em target} or end point of $s$. A segment is called \emph{trivial} if its source is equal to its target.
}*/
 
  friend class rat_line;

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


public:

static int use_filter;

/*{\Mcreation s }*/

rat_segment() { PTR = new rat_segment_rep; }
/*{\Mcreate introduces a variable |\Mvar| of type |\Mname|. |\Mvar| is 
            initialized to the empty segment. }*/

rat_segment(const rat_point& p, const rat_point& q) 
  { PTR = new rat_segment_rep(p,q); }
/*{\Mcreate introduces a variable |\Mvar| of type |\Mname|. |\Mvar| is 
            initialized to the segment $(p,q)$. }*/

rat_segment(const rat_point& p, const rat_vector& v); 
/*{\Mcreate introduces a variable |\Mvar| of type |\Mname|. |\Mvar| is 
            initialized to the segment $(p,p+v)$. \precond $v.dim() = 2$. }*/


rat_segment(const rational& x1, const rational& y1,
            const rational& x2, const rational& y2)
{ PTR = new rat_segment_rep(rat_point(x1,y1), rat_point(x2,y2)); }
/*{\Mcreate introduces a variable |\Mvar| of type |\Mname|. |\Mvar| is 
            initialized to the segment $[(x1,y1),(x2,y2)]$. }*/

/*{\Moptions nextwarning=no }*/
rat_segment(int x1, int y1, int w1, int x2, int y2, int w2) 
{ PTR = new rat_segment_rep(rat_point(x1,y1,w1), rat_point(x2,y2,w2)); }

rat_segment(const integer& x1, const integer& y1, const integer& w1,
            const integer& x2, const integer& y2,const integer& w2) 
{ PTR = new rat_segment_rep(rat_point(x1,y1,w1), rat_point(x2,y2,w2)); }
/*{\Mcreate introduces a variable |\Mvar| of type |\Mname|. |\Mvar| is 
            initialized to the segment $[(x1,y1,w1),(x2,y2,w2)]$. }*/

/*{\Moptions nextwarning=no }*/
rat_segment(int x1, int y1, int x2, int y2) 
{ PTR = new rat_segment_rep(rat_point(x1,y1), rat_point(x2,y2)); }

rat_segment(const integer& x1, const integer& y1, 
            const integer& x2, const integer& y2) 
{ PTR = new rat_segment_rep(rat_point(x1,y1), rat_point(x2,y2)); }
/*{\Mcreate introduces a variable |\Mvar| of type |\Mname|. |\Mvar| is 
            initialized to the segment $[(x1,y1),(x2,y2)]$. }*/

  rat_segment(const rat_segment& s) : handle_base(s) {}     
 ~rat_segment()                {}

  rat_segment& operator=(const rat_segment& s) 
  { handle_base::operator=(s); return *this;}


/*{\Moperations 2 3.5 }*/


segment to_segment() const;
/*{\Mop       returns a floating point approximation of |\Mvar|. }*/


/*{\Moptions nextwarning=no }*/
rat_point start()  const { return ptr()->start; }
rat_point source() const { return ptr()->start; }
/*{\Mop       returns the source point of |\Mvar|.}*/

/*{\Moptions nextwarning=no }*/

rat_point end()    const { return ptr()->end; }
rat_point target() const { return ptr()->end; }
/*{\Mop       returns the target point of |\Mvar|.}*/

rat_segment reversal() const;
/*{\Mop       returns the segment |(target(),source())|. }*/


rational xcoord1() const { return ptr()->start.xcoord(); }
/*{\Mop       returns the $x$-coordinate of the source point of |\Mvar|.}*/

rational xcoord2() const { return ptr()->end.xcoord();   }
/*{\Mop       returns the $x$-coordinate of the target point of |\Mvar|.}*/

rational ycoord1() const { return ptr()->start.ycoord(); }
/*{\Mop       returns the $y$-coordinate of the source point of |\Mvar|.}*/

rational ycoord2() const { return ptr()->end.ycoord();   }
/*{\Mop       returns the $y$-coordinate of the target point of |\Mvar|.}*/


double xcoord1D() const { return ptr()->start.xcoordD(); }
/*{\Mop       returns a double precision approximation of |\Mvar.xcoord1()|.}*/

double xcoord2D() const { return ptr()->end.xcoordD();   }
/*{\Mop       returns a double precision approximation of |\Mvar.xcoord2()|.}*/

double ycoord1D() const { return ptr()->start.ycoordD(); }
/*{\Mop       returns a double precision approximation of |\Mvar.ycoord1()|.}*/

double ycoord2D() const { return ptr()->end.ycoordD();   }
/*{\Mop       returns a double precision approximation of |\Mvar.ycoord2()|.}*/

integer X1() const { return ptr()->start.X(); }
/*{\Mop       returns the first homogeneous coordinate of the source point 
              of |\Mvar|.}*/

integer X2() const { return ptr()->end.X();   }
/*{\Mop       returns the first homogeneous coordinate of the target point 
              of |\Mvar|.}*/

integer Y1() const { return ptr()->start.Y(); }
/*{\Mop       returns the second homogeneous coordinate of the source point 
              of |\Mvar|.}*/

integer Y2() const { return ptr()->end.Y();   }
/*{\Mop       returns the second homogeneous coordinate of the target point 
              of |\Mvar|.}*/

integer W1() const { return ptr()->start.W(); }
/*{\Mop       returns the third homogeneous coordinate of the source point 
              of |\Mvar|.}*/

integer W2() const { return ptr()->end.W();   }
/*{\Mop       returns the third homogeneous coordinate of the target point 
              of |\Mvar|.}*/

double XD1() const { return ptr()->start.XD(); }
/*{\Mop       returns a floating point approximation of |\Mvar.X1()|.}*/

double XD2() const { return ptr()->end.XD();   }
/*{\Mop       returns a floating point approximation of |\Mvar.X2()|.}*/

double YD1() const { return ptr()->start.YD(); }
/*{\Mop       returns a floating point approximation of |\Mvar.Y1()|.}*/

double YD2() const { return ptr()->end.YD();   }
/*{\Mop       returns a floating point approximation of |\Mvar.X2()|.}*/

double WD1() const { return ptr()->start.WD(); }
/*{\Mop       returns a floating point approximation of |\Mvar.W1()|.}*/

double WD2() const { return ptr()->end.WD();   }
/*{\Mop       returns a floating point approximation of |\Mvar.W2()|.}*/


integer dx() const { return ptr()->dx; }
/*{\Mop       returns the normalized $x$-difference $X2\cdot W1 - X1\cdot W2$
              of |\Mvar|. }*/

integer dy() const { return ptr()->dy; }
/*{\Mop       returns the normalized $y$-difference $Y2\cdot W1 - Y1\cdot W2$
              of |\Mvar|. }*/

double dxD() const { return ptr()->dxd; }
/*{\Mop       returns a floating point approximation of |\Mvar.dx()|.}*/

double dyD() const { return ptr()->dyd; }
/*{\Mop       returns a floating point approximation of |\Mvar.dy()|.}*/



bool is_trivial() const { return ( ptr()->dx == 0 && ptr()->dy == 0); }
/*{\Mopl    returns true if |\Mvar| is trivial. }*/


bool is_vertical()   const { return ptr()->dx == 0; }
/*{\Mopl    returns true if |\Mvar| is vertical. \\
\precond |\Mvar| is non-trivial.}*/

bool is_horizontal() const { return ptr()->dy == 0; }
/*{\Mopl    returns true if |\Mvar| is horizontal.\\
\precond |\Mvar| is non-trivial. }*/

int cmp_slope(const rat_segment& s1) const; 
/*{\Mopl       compares the slopes of |\Mvar| and $s_1$. \\
\precond |\Mvar| and $s_1$ are non-trivial.}*/


bool   contains(const rat_point& p) const;
/*{\Mopl    decides whether |\Mvar| contains $p$. }*/

bool intersection(const rat_segment& t) const;
/*{\Mopl    decides whether |\Mvar| and $t$ intersect. }*/

bool intersection(const rat_segment& t, rat_point& p) const;
/*{\Mopl    decides whether |\Mvar| and $t$ intersect. If so, some point of 
intersection is assigned to $p$.
 }*/

bool intersection(const rat_segment& t, rat_segment& inter) const;
/*{\Mopl    decides whether |\Mvar| and $t$ intersect. If so, the segment formed by the points of intersection is assigned to |inter|.
 }*/


bool intersection_of_lines(const rat_segment& t, rat_point& p) const;
/*{\Mopl    decides if the lines supporting |\Mvar| and $t$ intersect in s
            single point. If so, the point of intersection is assigned to |p|.
            \precond |\Mvar| and |t| are nontrivial. }*/


rat_segment translate(const rational& dx, const rational& dy) const;
/*{\Mopl    returns |\Mvar| translated by vector $(dx,dy)$.}*/


rat_segment translate(const integer& dx, const integer& dy, const integer& dw) const;
/*{\Mopl    returns |\Mvar| translated by vector $(dx/dw,dy/dw)$.}*/


rat_segment translate(const rat_vector& v) const;
/*{\Mopl    returns $s+v$, i.e.,  |\Mvar| translated by vector $v$.\\
            \precond $v$.dim() = 2.}*/ 

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

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


rat_segment rotate90(const rat_point& q) const;
/*{\Mopl    returns |\Mvar| rotated by an angle of 90 degrees 
            about point $q$.}*/
 
rat_segment rotate90() const;
/*{\Mop     returns |\Mvar.rotate90(s.source())|.}*/


rat_segment reflect(const rat_point& p, const rat_point& q) const;
/*{\Mop     returns |\Mvar| reflected  across the straight line passing
            through $p$ and $q$.}*/

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



rat_segment perpendicular(const rat_point& p) const;
/*{\Mop    returns the segment perpendicular to |\Mvar| with source $p$
           and target on $|line|(\Mvar)$.\\
\precond |\Mvar| is nontrivial.}*/

rational   sqr_length() const;
/*{\Mop    returns the square of the length of |\Mvar|. }*/

rational  sqr_dist(const rat_point& p) const;
/*{\Mopl   returns the squared Euclidean distance between $p$ and $|\Mvar|$.}*/


int operator==(const rat_segment& t) const
{ return (ptr()->start == t.ptr()->start && ptr()->end == t.ptr()->end); }
/*{\Mbinop returns true if |\Mvar| and |t| are equal as oriented segments}*/

int operator!=(const rat_segment& t) const { return !operator==(t);}

inline
friend
int equal_as_sets(const rat_segment& s, const rat_segment& t)
{return ( s == t || s == t.reversal() ); }
/*{\Mfunc returns true if |s| and |t| are equal as unoriented segments}*/



friend ostream& operator<<(ostream& O, const rat_segment& s);
/*{\Mbinopfunc writes [[ [s.source() === s.target()] ]]
               to output stream $O$.}*/

friend istream& operator>>(istream& I, rat_segment& s);
/*{\Mbinopfunc reads [[ {[} p {===} q {]} ]] from input stream $I$.}*/


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

friend int orientation(const rat_segment& s, const rat_point& p);
/*{\Mfuncl      computes orientation($a$, $b$, $p$), where $a \not= b$
and $a$ and $b$ appear in this order on segment $s$. }*/

friend int cmp_slopes(const rat_segment& s1, const rat_segment& s2);
/*{\Mfuncl      returns compare(slope($s_1$), slope($s_2$)).}*/

friend int cmp_segments_at_xcoord(const rat_segment& s1,
                                            const rat_segment& s2,
                                            const rat_point& p);
/*{\Mfuncl      compares points $l_1 \cap v$ and $l_2 \cap v$ where
                $l_i$ is the line underlying segment $s_i$ and $v$ is
                the vertical straight line passing through point $p$. }*/

friend unsigned long ID_Number(const rat_segment& s) { return s.ptr()->id; }

};



inline int parallel(const rat_segment& s1, const rat_segment& s2)
{ return cmp_slopes(s1,s2) == 0; }


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

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

#endif

