home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ledar34.zip / leda-r-3_4_tar / LEDA-3.4 / src / plane / _circle.c next >
C/C++ Source or Header  |  1996-09-03  |  8KB  |  319 lines

  1. /*******************************************************************************
  2. +
  3. +  LEDA 3.4
  4. +
  5. +  _circle.c
  6. +
  7. +  This file is part of the LEDA research version (LEDA-R) that can be 
  8. +  used free of charge in academic research and teaching. Any commercial
  9. +  use of this software requires a license which is distributed by the
  10. +  LEDA Software GmbH, Postfach 151101, 66041 Saarbruecken, FRG
  11. +  (fax +49 681 31104).
  12. +
  13. +  Copyright (c) 1991-1996  by  Max-Planck-Institut fuer Informatik
  14. +  Im Stadtwald, 66123 Saarbruecken, Germany     
  15. +  All rights reserved.
  16. *******************************************************************************/
  17.  
  18. #include <LEDA/circle.h>
  19. #include <math.h>
  20.  
  21.  
  22. //------------------------------------------------------------------------------
  23. // circles
  24. //
  25. // S. N"aher (1996)
  26. //------------------------------------------------------------------------------
  27.  
  28.  
  29. circle_rep::circle_rep(const point& p1, const point& p2, const point& p3) : 
  30. a(p1), b(p2), c(p3), cp(0), rp(0), first_side_of(true) 
  31. { orient = orientation(p1,p2,p3); }
  32.  
  33. circle_rep::~circle_rep() 
  34. { if (cp) delete cp;
  35.   if (rp) delete rp;
  36.  }
  37.  
  38.  
  39.  
  40. circle::circle(const point& a, const point& b, const point& c)
  41. { PTR = new circle_rep(a,b,c); 
  42.   if (a == b && a == c)
  43.   { ptr()->cp = new point(a);
  44.     ptr()->rp = new double(0);
  45.    }
  46. }
  47.  
  48.  
  49. circle::circle() 
  50. { PTR = new circle_rep(point(1,0),point(0,1),point(-1,0));
  51.   ptr()->cp = new point(0,0);
  52.   ptr()->rp = new double(1);
  53.  }
  54.  
  55. circle::circle(const point& m, double r)       
  56. { point a(m.xcoord(),  m.ycoord()+r); 
  57.   point b(m.xcoord(),  m.ycoord()-r); 
  58.   point c(m.xcoord()+r,m.ycoord()); 
  59.   PTR = new circle_rep(a,b,c); 
  60.   ptr()->cp = new point(m);
  61.   ptr()->rp = new double(r);
  62. }
  63.  
  64. circle::circle(double x, double y, double r)  
  65. { PTR = new circle_rep(point(x,y+r),point(x+r,y),point(x,y-r)); 
  66.   ptr()->cp = new point(x,y);
  67.   ptr()->rp = new double(r);
  68. }
  69.  
  70.  
  71.  
  72. point circle::center() const
  73. { if (ptr()->cp == 0)
  74.   { if (collinear(ptr()->a,ptr()->b,ptr()->c)) 
  75.        error_handler(1,"circle::center(): points are collinear.");
  76.     line l1 = p_bisector(ptr()->a,ptr()->b);
  77.     line l2 = p_bisector(ptr()->b,ptr()->c);
  78.     point m;
  79.     l1.intersection(l2,m);
  80.     ptr()->cp = new point(m);
  81.    }
  82.   return *(ptr()->cp);
  83.  }
  84.  
  85.  
  86. double circle::radius() const
  87. { if (ptr()->rp == 0)
  88.   { double r = center().distance(ptr()->a);
  89.     ptr()->rp = new double(r);
  90.    }
  91.  return *(ptr()->rp);
  92. }
  93.  
  94.   
  95.  
  96. bool circle::operator==(const circle& c)  const
  97. { if (!contains(c.ptr()->a)) return false;
  98.   if (!contains(c.ptr()->b)) return false;
  99.   if (!contains(c.ptr()->c)) return false;
  100.   return true;
  101. }
  102.  
  103.  
  104. double circle::distance(const point& p) const
  105. { double d = p.distance(center());
  106.   return (d - radius());
  107.  }
  108.  
  109.  
  110. double circle::distance(const line& l) const
  111. { double d = l.distance(center());
  112.   return (d - radius());
  113.  }
  114.  
  115. double circle::distance(const circle& c) const
  116. { double d = center().distance(c.center());
  117.   return (d - radius() - c.radius());
  118.  }
  119.  
  120. int circle::side_of(const point& p) const
  121.   double ax = ptr()->a.xcoord();
  122.   double ay = ptr()->a.ycoord();
  123.  
  124.   // compute D1 D2 D3 (if not done before)
  125.  
  126.   if (ptr()->first_side_of) 
  127.   { double bx = ptr()->b.xcoord() - ax;
  128.     double by = ptr()->b.ycoord() - ay;
  129.     double bw = bx*bx + by*by;
  130.  
  131.     double cx = ptr()->c.xcoord() - ax;
  132.     double cy = ptr()->c.ycoord() - ay;
  133.     double cw = cx*cx + cy*cy;
  134.  
  135.     ptr()->D1 = cy*bw - by*cw;
  136.     ptr()->D2 = bx*cw - cx*bw;
  137.     ptr()->D3 = by*cx - bx*cy;
  138.  
  139.     ptr()->first_side_of = false;
  140.    }
  141.  
  142.    double px = p.xcoord() - ax;
  143.    double py = p.ycoord() - ay;
  144.    double pw = px*px + py*py;
  145.  
  146.    double D  = px*ptr()->D1  + py*ptr()->D2 + pw*ptr()->D3;
  147.  
  148.    if (D != 0)
  149.       return (D > 0) ? 1 : -1;
  150.    else
  151.       return 0;
  152. }
  153.  
  154.  
  155.  
  156. bool circle::outside(const point& p) const 
  157. { return (ptr()->orient * side_of(p)) < 0; }
  158.  
  159.  
  160. bool circle::inside(const point& p) const 
  161. { return (ptr()->orient * side_of(p)) > 0; }
  162.  
  163.  
  164. bool circle::contains(const point& p) const 
  165. { return side_of(p) == 0; }
  166.  
  167.  
  168. circle circle::translate(double alpha, double d) const
  169. { point a1 = ptr()->a.translate(alpha,d);
  170.   point b1 = ptr()->b.translate(alpha,d);
  171.   point c1 = ptr()->c.translate(alpha,d);
  172.   return circle(a1,b1,c1);
  173.  }
  174.  
  175. circle circle::translate(const vector& v) const
  176. { point a1 = ptr()->a.translate(v);
  177.   point b1 = ptr()->b.translate(v);
  178.   point c1 = ptr()->c.translate(v);
  179.   return circle(a1,b1,c1);
  180.  }
  181.  
  182. circle  circle::rotate(const point& o, double alpha) const
  183. { point a1 = ptr()->a.rotate(o,alpha);
  184.   point b1 = ptr()->b.rotate(o,alpha);
  185.   point c1 = ptr()->c.rotate(o,alpha);
  186.   return circle(a1,b1,c1);
  187.  }
  188.  
  189. circle  circle::rotate(double alpha)  const
  190. { point o(0,0);
  191.   point a1 = ptr()->a.rotate(o,alpha);
  192.   point b1 = ptr()->b.rotate(o,alpha);
  193.   point c1 = ptr()->c.rotate(o,alpha);
  194.   return circle(a1,b1,c1);
  195. }
  196.  
  197.  
  198. circle  circle::rotate90(const point& o)  const
  199. { point a1 = ptr()->a.rotate90(o);
  200.   point b1 = ptr()->b.rotate90(o);
  201.   point c1 = ptr()->c.rotate90(o);
  202.   return circle(a1,b1,c1);
  203. }
  204.  
  205.  
  206. circle  circle::reflect(const point& p, const point& q)  const
  207. { point a1 = ptr()->a.reflect(p,q);
  208.   point b1 = ptr()->b.reflect(p,q);
  209.   point c1 = ptr()->c.reflect(p,q);
  210.   return circle(a1,b1,c1);
  211. }
  212.  
  213. circle  circle::reflect(const point& p)  const
  214. { point a1 = ptr()->a.reflect(p);
  215.   point b1 = ptr()->b.reflect(p);
  216.   point c1 = ptr()->c.reflect(p);
  217.   return circle(a1,b1,c1);
  218. }
  219.  
  220.  
  221.  
  222. list<point> circle::intersection(const line& l) const
  223. { list<point> result;
  224.  
  225.   segment s = l.perpendicular(center());
  226.   double  d = s.length();
  227.   double  r = radius();
  228.  
  229.   if (d==r) result.append(s.end());
  230.   
  231.   if (d < r)
  232.   { segment sl = l.ptr()->seg;
  233.     double t = sqrt(r*r - d*d)/sl.length();
  234.     double dx = t*sl.dx();
  235.     double dy = t*sl.dy();
  236.     result.append(s.end().translate(vector(dx,dy)));
  237.     result.append(s.end().translate(vector(-dx,-dy)));
  238.   }
  239.  
  240.   return result;
  241. }
  242.  
  243.  
  244. list<point> circle::intersection(const segment& s) const
  245. { list<point> result,L;
  246.  
  247.   L = intersection(line(s));
  248.  
  249.   point p;
  250.   double  d  = s.length();
  251.  
  252.   forall(p,L)
  253.   { double d1 = s.ptr()->start.distance(p);
  254.     double d2 = s.ptr()->end.distance(p);
  255.     if (d1 <= d && d2 <= d) result.append(p);
  256.    }
  257.  
  258.   return result;
  259. }
  260.  
  261. list<point> circle::intersection(const circle& c) const
  262. { list<point> result;
  263.   segment s(center(), c.center());
  264.   double d  = s.length();
  265.   double r1 = radius();
  266.   double r2 = c.radius();
  267.  
  268.   if (d > (r1+r2) || (d+r2) < r1 || (d+r1) < r2) return result;
  269.  
  270.  
  271.   double x = (d*d + r1*r1 - r2*r2)/(2*d);
  272.   double alpha = acos(x/r1);
  273.   double beta  = s.angle() + alpha;
  274.   double gamma = s.angle() - alpha;
  275.  
  276.   result.append(center().translate(beta,r1));
  277.   if (alpha!=0) result.append(center().translate(gamma,r1));
  278.  
  279.   return result;
  280.  }
  281.  
  282.  
  283. segment circle::left_tangent(const point& p) const
  284. { if (inside(p)) error_handler(1,"left_tangent:: point inside circle");
  285.   segment s(p,center());
  286.   double d = s.length();
  287.   double alpha = asin(radius()/d) + s.angle();
  288.   point touch = p.translate(alpha,sqrt(d*d - radius()*radius()));
  289.   return segment(p,touch);
  290. }
  291.  
  292. segment circle::right_tangent(const point& p) const
  293. { if (inside(p)) error_handler(1,"right_tangent:: point inside circle");
  294.   segment s(p,center());
  295.   double d = s.length();
  296.   double alpha = s.angle() - asin(radius()/d);
  297.   point touch = p.translate(alpha,sqrt(d*d - radius()*radius()));
  298.   return segment(p,touch);
  299. }
  300.  
  301.  
  302. ostream& operator<<(ostream& out, const circle& c) 
  303. { out << c.center() << " "<< c.radius(); 
  304.   return out;
  305.  } 
  306.  
  307. istream& operator>>(istream& in,  circle& c) 
  308. { point cent;
  309.   double rad;
  310.   if (in) in >> cent;
  311.   if (in) in >> rad;
  312.   c = circle(cent,rad);
  313.   return in;
  314. }
  315.  
  316.  
  317.