/*******************************************************************************
+
+  LEDA 3.5
+
+  rat_circle.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_CIRCLE_H
#define LEDA_RAT_CIRCLE_H

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


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

//------------------------------------------------------------------------------
// rat_circle: circles with rational coordinates
//------------------------------------------------------------------------------


class rat_circle_rep : public handle_rep {

friend class rat_circle;

  rat_point  a; 
  rat_point  b; 
  rat_point  c; 

  int orient;    // orientation(a,b,c)

  integer D1;
  integer D2;
  integer D3;

  rat_point* cp;  // pointer to center

  bool    first_side_of;
  
public:

  rat_circle_rep() {}
  rat_circle_rep(const rat_point&, const rat_point&, const rat_point&);
 ~rat_circle_rep() { if (cp) delete cp; }

friend ostream& operator<<(ostream& out, const rat_circle& c);
friend istream& operator>>(istream& in, rat_circle& c);  
};


/*{\Manpage {rat_circle} {} {Rational Circles} }*/ 

class rat_circle   : public handle_base 
{
/*{\Mdefinition
An instance $C$ of data type |rat_circle| is an oriented circle in the 
plane. A circle is defined by three points $p_1$, $p_2$, $p_3$ with rational 
coordinates (|rat_points|). The orientation of $C$ is equal to the orientation 
of the three defining points, i.e., $|orientation|(p_1,p_2,p_3)$. Positive orientation corresponds to counterclockwise orientation and negative orientation corresponds to clockwise orientation. 

Some triples of points are unsuitable for defining a circle. A triple is \emph{admissable} if $\Labs{\{p_1,p_2,p_3\}} \not= 2$. Assume now that 
$p_1$, $p_2$, $p_3$ are admissable. 
If $\Labs{\{p_1,p_2,p_3\}} = 1$ they define the circle with center $p_1$
and radius zero. If $p_1$, $p_2$, and $p_3$ are collinear $C$ is a straight line passing through
$p_1$, $p_2$ and $p_3$ in this order and the center of $C$ is undefined.
If   $p_1$, $p_2$, and $p_3$ are not collinear, $C$ is the circle passing through them.
}*/


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

public:

/*{\Mcreation C }*/ 


rat_circle(const rat_point& a, const rat_point& b, const rat_point& c);
/*{\Mcreate introduces a variable $C$ of type $rat\_circle$. $C$ is 
            initialized to the circle through points $a$, $b$, and $c$.\\
\precond $a$, $b$, and $c$ are admissable.}*/

rat_circle(const rat_point& a, const rat_point& b);
/*{\Mcreate introduces a variable $C$ of type $circle$. $C$ is initialized to 
            the counter-clockwise oriented circle with center $a$  passing
            through $b$.}*/


rat_circle(const rat_point& a);
/*{\Mcreate introduces a variable $C$ of type $circle$. $C$ is initialized to 
            the trivial circle with center $a$. }*/

rat_circle();
/*{\Mcreate introduces a variable $C$ of type $rat\_circle$. 
            $C$ is initialized to the trivial circle centered at $(0,0)$.}*/


 rat_circle(const rat_circle& c) : handle_base(c) {}
~rat_circle() {}

 rat_circle& operator=(const rat_circle& C) { handle_base::operator=(C); return *this; }


/*{\Moperations 2.2 4.9 }*/

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

int orientation()  const { return ptr()->orient; }
/*{\Mop  returns the orientation of |\Mvar|.}*/

rat_point center()  const;
/*{\Mop  returns the center of |\Mvar|.\\
         \precond |\Mvar| has a center, i.e., it not a line. }*/


rat_point point1() const { return ptr()->a; }
/*{\Mop  returns $p_1$. }*/

rat_point point2() const { return ptr()->b; }
/*{\Mop  returns $p_2$. }*/

rat_point point3() const { return ptr()->c; }
/*{\Mop  returns $p_3$. }*/


rat_point point_on_circle(double alpha, double epsilon) const;
/*{\Mop  returns  a point $p$ on |\Mvar| such that the angle of $p$ 
         differs from alpha by at most a |eps|.}*/


bool  is_degenerate() const { return ptr()->orient == 0; }
/*{\Mop returns true if the defining points are collinear.}*/

bool is_trivial() const { return ptr()->a == ptr()->b; }
/*{\Mop returns true if |\Mvar| has radius zero.}*/

bool is_line() const { return ptr()->orient == 0 && !is_trivial(); }
/*{\Mop returns true if |\Mvar| is a line.}*/


int side_of(const rat_point& p) const;
/*{\Mop   returns $-1$, $+1$, or $0$ if $p$ lies right of, left of, or on 
          |\Mvar| respectively. }*/

bool    inside(const rat_point& p) const;
/*{\Mop   returns true if $p$ lies inside |\Mvar|, false otherwise.}*/

bool    outside(const rat_point& p) const;
/*{\Mop     returns true if  $p$ lies outside |\Mvar|.}*/

bool    contains(const rat_point& p) const;
/*{\Mop   returns true if $p$ lies on |\Mvar|, false otherwise.}*/


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

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

rat_circle translate(const rat_vector& v) const; 
/*{\Mop    returns |\Mvar| translated by vector $v$.}*/

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

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


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

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

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


bool operator==(const rat_circle& D) const;
/*{\Mbinop returns true if |\Mvar| and |D| are equal as oriented circles}*/

bool operator!=(const rat_circle& D) const { return !operator==(D); };

friend bool equal_as_sets(const rat_circle& C1,const rat_circle& C2);
/*{\Mop returns true if |C1| and |C2| are equal as unoriented circles}*/

friend ostream& operator<<(ostream& out, const rat_circle& c);
/*{\Mbinopfunc writes the three defining points }*/

friend istream& operator>>(istream& in, rat_circle& c);  
/*{\Mbinopfunc reads three points and assigns the circle defined by them to $c$. }*/


};



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

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

#endif



