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

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


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

//------------------------------------------------------------------------------
// circles
//------------------------------------------------------------------------------


class circle_rep : public handle_rep {

friend class circle;

  point a; 
  point b; 
  point c; 

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

  double D1;
  double D2;
  double D3;

  point*  cp; // pointer to center
  double* rp; // pointer to radius

  bool first_side_of;
  
public:

  circle_rep() {}
  circle_rep(const point&, const point&, const point&);
 ~circle_rep();

};


/*{\Manpage {circle} {} {Circles} }*/ 


/*{\Mdefinition
An instance $C$ of the data type $circle$ is an oriented circle in the 
plane passing through three points $p_1$, $p_2$, $p_3$. The orientation of 
$C$ is equal to the orientation of the three defining points, 
i.e. $orientation(p_1,p_2,p_3)$. 
If \Labs{\{p_1,p_2,p_3\}}$ = 1$ $C$ is the empty circle with center $p_1$. 
If $p_1,p_2,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. }*/

class circle   : public handle_base 
{

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

public:

/*{\Mcreation C }*/ 

circle(const point& a, const point& b, const point& c);
/*{\Mcreate introduces a variable $C$ of type $circle$. $C$ is initialized to 
            the oriented circle through points $a$, $b$, and $c$. }*/

circle(const point& a, const 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$.}*/

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

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

circle(const point& c, double r);
/*{\Mcreate introduces a variable $C$ of type $circle$. $C$ is initialized to 
            the circle with center $c$ and radius $r$ with positive (i.e.
            counter-clockwise) orientation.}*/

circle(double x, double y, double r);
/*{\Mcreate introduces a variable $C$ of type $circle$. $C$ is initialized to 
            the circle with center $(x,y)$ and radius $r$ with positive (i.e.
            counter-clockwise) orientation.}*/


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

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


/*{\Moperations 2.2 4.9 }*/

point center()  const;
/*{\Mop  returns the center of |\Mvar|.\\
         \precond The orientation of |\Mvar| is not $0$.}*/

double radius() const;
/*{\Mop  returns the radius of |\Mvar|.\\
         \precond The orientation of |\Mvar| is not $0$.}*/

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

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

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

circle to_circle() const { return *this; }
/*{\Xop for compatibility with |rat_circle|. }*/

point point_on_circle(double alpha, double=0) const;
/*{\Mop  returns  a point $p$ on |\Mvar| with angle of $alpha$. }*/


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.}*/

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

int side_of(const point& p) const;
/*{\Mop   MISSING.}*/

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

bool    outside(const point& p) const;
/*{\Mop     returns !|\Mvar|.inside($p$).}*/


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


circle  translate_by_angle(double a, double d) const;
/*{\Mop    returns |\Mvar| translated in direction $a$ by distance $d$.}*/

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

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

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

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

circle  rotate(const point& q, double a) const;
/*{\Mopl    returns |\Mvar| rotated  about point $q$ by angle $a$.}*/

circle  rotate(double a) const;
/*{\Mopl    returns |\Mvar| rotated about the origin $q$ by angle $a$.}*/

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

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

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


list<point> intersection(const circle& D) const;
/*{\Mop    returns $C \cap D$ as a list of points.}*/

list<point> intersection(const line& l) const;
/*{\Mop  returns $C \cap l$ as a list of points.}*/

list<point> intersection(const segment& s) const;
/*{\Mop   returns $C \cap s$ as a list of points.}*/

segment left_tangent(const point& p) const;
/*{\Mop   returns the line segment starting in $p$ tangent 
	  to |\Mvar| and left of segment $[p,C.center()]$.}*/

segment right_tangent(const point& p) const;
/*{\Mop   returns the line segment starting in $p$ tangent 
	  to |\Mvar| and right of segment $[p,C.center()]$.}*/

double  distance(const point& p) const;
/*{\Mop   returns the distance between |\Mvar| and $p$ 
	  (negative if $p$ inside \Mvar).}*/

double  distance(const line& l) const;
/*{\Mop    returns the distance between |\Mvar| and $l$  
	   (negative if $l$ intersects \Mvar).}*/

double  distance(const circle& D) const;
/*{\Mop    returns the distance between |\Mvar| and $D$ 
	   (negative if $D$ intersects \Mvar).}*/


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


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


};

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

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

#endif
