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

  1.  
  2.  
  3.  
  4. /*
  5.  *
  6.  *          Copyright (C) 1994, M. A. Sridhar
  7.  *  
  8.  *
  9.  *     This software is Copyright M. A. Sridhar, 1994. You are free
  10.  *     to copy, modify or distribute this software  as you see fit,
  11.  *     and to use  it  for  any  purpose, provided   this copyright
  12.  *     notice and the following   disclaimer are included  with all
  13.  *     copies.
  14.  *
  15.  *                        DISCLAIMER
  16.  *
  17.  *     The author makes no warranties, either expressed or implied,
  18.  *     with respect  to  this  software, its  quality, performance,
  19.  *     merchantability, or fitness for any particular purpose. This
  20.  *     software is distributed  AS IS.  The  user of this  software
  21.  *     assumes all risks  as to its quality  and performance. In no
  22.  *     event shall the author be liable for any direct, indirect or
  23.  *     consequential damages, even if the  author has been  advised
  24.  *     as to the possibility of such damages.
  25.  *
  26.  */
  27.  
  28.  
  29. #if defined(__GNUC__)
  30. #pragma implementation
  31. #endif
  32.  
  33. #include <math.h>
  34. #include <limits.h>
  35.  
  36. #include "ui/lineseg.h"
  37. #include "ui/dwgsurf.h"
  38.  
  39. UI_LineSegment::UI_LineSegment (const UI_Point& p1, const UI_Point& p2)
  40. : _p1 (p1), _p2(p2)
  41. {
  42. }
  43.  
  44.  
  45. UI_LineSegment::UI_LineSegment (const UI_Point& s, double slope, long length)
  46. {
  47.     double angle = atan2 (slope, 1);
  48.     double xdist = length*cos (angle);
  49.     double ydist = length*sin (angle);
  50.     _p1 = s;
  51.     _p2 = UI_Point (_p1.XCoord() + (long) xdist, _p1.YCoord() + (long) ydist);
  52.  
  53. UI_LineSegment::UI_LineSegment ()
  54. {
  55. }
  56.  
  57.  
  58.  
  59. UI_PointPair UI_LineSegment::PointsAtDistance (const UI_Point& p, long dist)
  60. {
  61.     double slope = Slope();
  62.     double angle = atan2 ((double) slope, 1);
  63.  
  64.     double xdist = dist*cos (angle);     
  65.     double ydist = dist*sin (angle);     
  66.     return UI_PointPair
  67.         (UI_Point (p.XCoord() - (long) xdist, p.YCoord() + (long) ydist),
  68.          UI_Point (p.XCoord() + (long) xdist, p.YCoord() - (long) ydist));
  69.  
  70.  
  71.  
  72. static short Ccw (const UI_Point& p0, const UI_Point& p1,
  73.                   const UI_Point& p2)
  74. {
  75.     // This is from p. 350 of Sedgewick's book "Algorithms" (second
  76.     // edition).
  77.     long dx1, dx2, dy1, dy2;
  78.     dx1 = p1.XCoord() - p0.XCoord();
  79.     dy1 = p1.YCoord() - p0.YCoord();
  80.     dx2 = p2.XCoord() - p0.XCoord();
  81.     dy2 = p2.YCoord() - p0.YCoord();
  82.     long t = dx1 * dy2 - dy1 * dx2;
  83.     if (t < 0)
  84.         return 1;
  85.     if (t > 0)
  86.         return -1;
  87.     if (dx1 * dx2 < 0 || dy1 * dy2 < 0)
  88.         return -1;
  89.     return (dx1 * dx1 + dy1 * dy1 >= dx2 * dx2 + dy2 * dy2) ? 0 : 1;
  90. }
  91.  
  92. bool UI_LineSegment::Intersects (const UI_LineSegment& l) const
  93. {
  94.     // From Sedgewick's book "Algorithms" second edition, p. 350.
  95.     UI_PointPair l1 = EndPoints(), l2 = l.EndPoints();
  96.     return (Ccw (l1.p1, l1.p2, l2.p1) * Ccw (l1.p1, l1.p2, l2.p2) <= 0) &&
  97.         (Ccw (l2.p1, l2.p2, l1.p1) * Ccw (l2.p1, l2.p2, l1.p2) <= 0);
  98. }
  99.  
  100.  
  101. UI_HitTest UI_LineSegment::HitTest (const UI_Point& p) const
  102. {
  103.     return OnBoundary (p) ? UIHit_Boundary : UIHit_Outside;
  104. }
  105.  
  106. bool UI_LineSegment::DrawOn (UI_DrawingSurface& sfc, const UI_Point& p)
  107.     const
  108. {
  109.     sfc.DrawLine  (p + _p1, p + _p2);
  110.     return TRUE;
  111. }
  112.  
  113.  
  114.  
  115. bool UI_LineSegment::ReshapeTo (const UI_Point& p1, const UI_Point& p2)
  116. {
  117.     if (!PrepareToChange())
  118.         return FALSE;
  119.     _p1 = p1;
  120.     _p2 = p2;
  121.     Notify ();
  122.     return TRUE;
  123. }
  124.  
  125.  
  126. void UI_LineSegment::operator= (const CL_Object& o)
  127. {
  128.     if (o.IsA (*this))
  129.         *this = (const UI_LineSegment&) o;
  130. }
  131.  
  132.  
  133. UI_LineSegment& UI_LineSegment::operator= (const UI_LineSegment& o)
  134. {
  135.     if (PrepareToChange()) {
  136.         _p1 = o._p1;
  137.         _p2 = o._p2;
  138.         Notify();
  139.     }
  140.     return *this;
  141. }
  142.  
  143.  
  144. bool UI_LineSegment::OnBoundary (const UI_Point& p) const
  145. {
  146.     long xx1  = p.XCoord() - _p1.XCoord();
  147.     long x2x1 = _p2.XCoord() - _p1.XCoord();
  148.     long yy1  = p.YCoord() - _p1.YCoord();
  149.     long y2y1 = _p2.YCoord() - _p1.YCoord();
  150.     return xx1 * y2y1 == x2x1 * yy1 &&
  151.         (xx1 * xx1 + yy1 * yy1 <= x2x1 * x2x1 + y2y1 * y2y1);
  152. }
  153.  
  154.  
  155. UI_Rectangle UI_LineSegment::BoundingRectangle() const
  156. {
  157.     long x1 = _p1.XCoord();
  158.     long y1 = _p1.YCoord();
  159.     long x2 = _p2.XCoord();
  160.     long y2 = _p2.YCoord();
  161.     UI_Point origin (minl (x1, x2), minl (y1, y2));
  162.     return UI_Rectangle (origin, abs (x2 - x1 + 1), abs (y2 - y1 + 1));
  163. }
  164.  
  165.  
  166.  
  167. inline bool IsBetween (long a, long m, long n)
  168. {
  169.     // Check if a is between m and n
  170.     return a >= minl (m, n) && a <= maxl (m, n);
  171. }
  172.  
  173.  
  174. static bool _IntersectHorz (const UI_Point& p1, const UI_Point& p2,
  175.                             long x1, long x2, long y)
  176. {
  177.     // Check if the line segment between p1 and p2 intersects the
  178.     // horizontal line segment between (x1, y) and (x2, y). The idea is to
  179.     // use the parametric equation for the line segment between p1 and p2:
  180.     //     x = x1 + t * (x2 - x1)
  181.     //     y = y1 + t * (y2 - y1)
  182.     // where t is between 0 and 1.
  183.     long p1x = p1.XCoord(), p2x = p2.XCoord();
  184.     long p1y = p1.YCoord(), p2y = p2.YCoord();
  185.     if (p1y == p2y)
  186.         return (p1y == y && ((p1x == x1 && p2x == x2) ||
  187.                              (p1x == x2 && p2x == x1)));
  188.     double t = (y - p1y) / ((double) (p2y - p1y));
  189.     if (t < 0 || t > 1)
  190.         return FALSE;
  191.     long x = p1x + t * (p2x - p1x);
  192.     return IsBetween (x, x1, x2) ? TRUE : FALSE;
  193. }
  194.  
  195. static bool _IntersectVert (const UI_Point& p1, const UI_Point& p2,
  196.                             long y1, long y2, long x)
  197. {
  198.     // Check if the line segment between p1 and p2 intersects the
  199.     // vertical line segment between (x, y1) and (x, y2).
  200.     long p1x = p1.XCoord(), p2x = p2.XCoord();
  201.     long p1y = p1.YCoord(), p2y = p2.YCoord();
  202.     if (p1x == p2x)
  203.         return (p1x == x && ((p1y == y1 && p2y == y2) ||
  204.                              (p1y == y2 && p2y == y1)));
  205.     double t = (x - p1x) / ((double) (p2x - p1x));
  206.     if (t < 0 || t > 1)
  207.         return FALSE;
  208.     long y = p1y + t * (p2y - p1y);
  209.     return IsBetween (y, y1, y2) ? TRUE : FALSE;
  210. }
  211.  
  212.  
  213. bool UI_LineSegment::IntersectsBoundary (const UI_Rectangle& r) const
  214. {
  215.     long bottom = r.Bottom();
  216.     long top    = r.Top   ();
  217.     long left   = r.Left  ();
  218.     long right  = r.Right ();
  219.     return _IntersectHorz (_p1, _p2, bottom, left, right) ||
  220.            _IntersectHorz (_p1, _p2, top,    left, right) ||
  221.            _IntersectVert (_p1, _p2, left,   top,  bottom) ||
  222.            _IntersectVert (_p1, _p2, right,  top,  bottom);
  223. }
  224.  
  225.  
  226. bool UI_LineSegment::IsContainedIn (const UI_Rectangle& r) const
  227. {
  228.     return (r.Includes (_p1) && r.Includes (_p2));
  229. }
  230.  
  231.  
  232. UI_PointPair UI_LineSegment::EndPoints () const
  233. {
  234.     return UI_PointPair (_p1, _p2);
  235. }
  236.  
  237.  
  238.  
  239. UI_Point UI_LineSegment::Center () const
  240. {
  241.     return UI_Point ((_p1.XCoord() + _p2.XCoord())/2,
  242.                      (_p1.YCoord() + _p2.YCoord())/2);
  243. }
  244.  
  245.  
  246. double UI_LineSegment::Slope() const
  247. {
  248.     double xWidth = _p2.XCoord() - _p1.XCoord();
  249.     if (xWidth == 0)
  250.         return ULONG_MAX;
  251.     return (_p1.YCoord() -_p2.YCoord())/ xWidth;
  252. }
  253.  
  254.  
  255.