home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / yacl-012.zip / ui / ellipse.cxx < prev    next >
C/C++ Source or Header  |  1995-04-09  |  6KB  |  201 lines

  1.  
  2.  
  3. /*
  4.  *
  5.  *          Copyright (C) 1994, M. A. Sridhar
  6.  *  
  7.  *
  8.  *     This software is Copyright M. A. Sridhar, 1994. You are free
  9.  *     to copy, modify or distribute this software  as you see fit,
  10.  *     and to use  it  for  any  purpose, provided   this copyright
  11.  *     notice and the following   disclaimer are included  with all
  12.  *     copies.
  13.  *
  14.  *                        DISCLAIMER
  15.  *
  16.  *     The author makes no warranties, either expressed or implied,
  17.  *     with respect  to  this  software, its  quality, performance,
  18.  *     merchantability, or fitness for any particular purpose. This
  19.  *     software is distributed  AS IS.  The  user of this  software
  20.  *     assumes all risks  as to its quality  and performance. In no
  21.  *     event shall the author be liable for any direct, indirect or
  22.  *     consequential damages, even if the  author has been  advised
  23.  *     as to the possibility of such damages.
  24.  *
  25.  */
  26.  
  27.  
  28. #if defined(__GNUC__)
  29. #pragma implementation
  30. #endif
  31.  
  32.  
  33. #include <math.h>
  34.  
  35. #if defined(__MS_WINDOWS__)
  36. #include <windows.h>
  37. #endif
  38.  
  39.  
  40. #include "ui/ellipse.h"
  41. #include "ui/dwgsurf.h"
  42. #include "ui/grutils.h"
  43.  
  44.  
  45. #ifndef M_PI
  46. #define M_PI 3.1415926535897932
  47. #endif
  48.  
  49. UI_Ellipse::UI_Ellipse ()
  50. {
  51.     _majorAxis = _minorAxis = 0;
  52. }
  53.  
  54.  
  55. UI_Ellipse::UI_Ellipse (const UI_Rectangle& r)
  56. {
  57.     _majorAxis = r.Width();
  58.     _minorAxis = r.Height ();
  59.     _origin = UI_Point (r.Left() + _majorAxis/2, r.Top() + _minorAxis/2);
  60. }
  61.  
  62.  
  63. UI_Ellipse::UI_Ellipse (long major_axis, long minor_axis, UI_Point origin)
  64. : _origin (origin)
  65. {
  66.     _majorAxis = major_axis;
  67.     _minorAxis = minor_axis;
  68. }
  69.  
  70.  
  71. bool UI_Ellipse::DrawOn (UI_DrawingSurface& sfc, const UI_Point& p) const
  72. {
  73.     UI_Rectangle e (p + _origin - UI_Point (_majorAxis/2, _minorAxis/2),
  74.                     _majorAxis, _minorAxis);
  75.     sfc.DrawEllipse (e);
  76.     return TRUE;
  77. }
  78.  
  79. bool UI_Ellipse::Fill (UI_DrawingSurface& s) const
  80. {
  81.     s.DrawEllipse (BoundingRectangle(), UID_Fill);
  82.     return TRUE;
  83. }
  84.  
  85.  
  86.  
  87. bool UI_Ellipse::ReshapeTo (const UI_Point& p1, const UI_Point& p2)
  88. {
  89.     if (!PrepareToChange())
  90.         return FALSE;
  91.     UI_Rectangle r (p1, p2.XCoord() - p1.XCoord(), p2.YCoord() -
  92.                     p1.YCoord());
  93.     long major = r.Width();
  94.     long minor = r.Height();
  95.     _origin = r.Origin() + UI_Point (major/2, minor/2);
  96.     _majorAxis = major;
  97.     _minorAxis = minor;
  98.     Notify();
  99.     return TRUE;
  100. }
  101.  
  102.  
  103.  
  104. UI_Rectangle UI_Ellipse::BoundingRectangle() const
  105. {
  106.     long x = _origin.XCoord();
  107.     long y = _origin.YCoord();
  108.     return UI_Rectangle (x -_majorAxis/2, y - _minorAxis/2, _majorAxis,
  109.                          _minorAxis);
  110. }
  111.  
  112.  
  113. UI_Point UI_Ellipse::PointAtAngle (double deg) const
  114. {
  115.     double semiMinor = _minorAxis/((double) 2.0);
  116.     // First, reduce deg modulo 360
  117.     long ldeg = (long) deg;
  118.     long reduced = ldeg % 360;
  119.     deg = reduced + deg - ldeg; // Add back fractional part
  120.     if (deg < 0)
  121.         deg += 360;
  122.     UI_Point pt; // Point computed assuming that ellipse center is origin
  123.     if (deg == 90)
  124.         pt  =  UI_Point (0, _origin.YCoord() - (long) semiMinor);
  125.         // ----------------------------------^--
  126.         // Remember that the origin of the co-ordinate system is at top
  127.         // left.
  128.     else if (deg == 270)
  129.         pt = UI_Point (0, _origin.YCoord() + (long) semiMinor);
  130.     else {
  131.         double theta     = DegToRad (deg);
  132.         double semiMajor = _majorAxis/((double) 2.0);
  133.         double asq       = semiMajor * semiMajor;
  134.         double bsq       = semiMinor * semiMinor;
  135.         double cosTheta  = cos (theta);
  136.         double sinTheta  = sin (theta);
  137.         double csqTheta  = cosTheta * cosTheta;      // square of cos (theta)
  138.         double ssqTheta  = sinTheta * sinTheta;      // square of sin (theta)
  139.         double dist      = sqrt (asq * bsq /
  140.                                  (bsq * csqTheta + asq * ssqTheta));
  141.         pt = UI_Point ((long) (dist * cosTheta), (long) (-dist * sinTheta));
  142.         // ----------------------------------------------^ -----
  143.         // We negate it, because the y co-ordinates increase downwards, not
  144.         // upwards
  145.     }
  146.     return pt + Center ();
  147. }
  148.  
  149.  
  150.  
  151. UI_HitTest UI_Ellipse::HitTest (const UI_Point& p) const
  152. {
  153.     double x = p.XCoord() - _origin.XCoord();
  154.     double y = p.YCoord() - _origin.YCoord();
  155.     // First check if p is on the Y axis
  156.     if (x == 0)  {
  157.         double semiMinor = _minorAxis/((double) 2.0);
  158.         return (y > -semiMinor || y < semiMinor) ? UIHit_Outside
  159.             : ((y == -semiMinor || y == semiMinor) ? UIHit_Boundary :
  160.                UIHit_Inside);
  161.     }
  162.     // p is not on the Y axis. Translate the ellipse so that its center is
  163.     // at the origin. Then find the angle theta that the vector from the
  164.     // origin to p subtends wrt the X axis. Check the length of this vector
  165.     // against the distance of the point q on the ellipse's periphery at
  166.     // angle theta.
  167.     double theta  = atan2 (-y, x);
  168.     // --------------------^--------
  169.     // Negate y, because angles are counterclockwise as usual, but the y
  170.     // co-ordinates increase downwards, not upwards
  171.     UI_Point q    = PointAtAngle (RadToDeg (theta)) - Center();
  172.     double a      = q.XCoord();
  173.     double b      = q.YCoord();
  174.     double d1 = a*a + b*b;
  175.     double d2 = x*x + y*y;
  176.     return d1 > d2 ? UIHit_Inside
  177.         : ((long) d1 == (long) d2 ? UIHit_Boundary : UIHit_Outside);
  178. }
  179.  
  180.  
  181. bool UI_Ellipse::Includes (const UI_Point& p) const
  182. {
  183.     UI_HitTest t = HitTest (p);
  184.     return t == UIHit_Boundary || t == UIHit_Inside;
  185. }
  186.  
  187.  
  188. bool UI_Ellipse::IntersectsBoundary (const UI_Rectangle& r) const
  189. {
  190.     short count = 0;
  191.     if (Includes (r.TopLeft()))
  192.         count++;
  193.     if (Includes (r.TopRight()))
  194.         count++;
  195.     if (Includes (r.BottomLeft()))
  196.         count++;
  197.     if (Includes (r.BottomRight()))
  198.         count++;
  199.     return count != 0 && count != 4;
  200. }
  201.