home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
yacl-012.zip
/
ui
/
lineseg.cxx
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-09
|
7KB
|
257 lines
/*
*
* Copyright (C) 1994, M. A. Sridhar
*
*
* This software is Copyright M. A. Sridhar, 1994. You are free
* to copy, modify or distribute this software as you see fit,
* and to use it for any purpose, provided this copyright
* notice and the following disclaimer are included with all
* copies.
*
* DISCLAIMER
*
* The author makes no warranties, either expressed or implied,
* with respect to this software, its quality, performance,
* merchantability, or fitness for any particular purpose. This
* software is distributed AS IS. The user of this software
* assumes all risks as to its quality and performance. In no
* event shall the author be liable for any direct, indirect or
* consequential damages, even if the author has been advised
* as to the possibility of such damages.
*
*/
#if defined(__GNUC__)
#pragma implementation
#endif
#include <math.h>
#include <limits.h>
#include "ui/lineseg.h"
#include "ui/dwgsurf.h"
UI_LineSegment::UI_LineSegment (const UI_Point& p1, const UI_Point& p2)
: _p1 (p1), _p2(p2)
{
}
UI_LineSegment::UI_LineSegment (const UI_Point& s, double slope, long length)
{
double angle = atan2 (slope, 1);
double xdist = length*cos (angle);
double ydist = length*sin (angle);
_p1 = s;
_p2 = UI_Point (_p1.XCoord() + (long) xdist, _p1.YCoord() + (long) ydist);
}
UI_LineSegment::UI_LineSegment ()
{
}
UI_PointPair UI_LineSegment::PointsAtDistance (const UI_Point& p, long dist)
{
double slope = Slope();
double angle = atan2 ((double) slope, 1);
double xdist = dist*cos (angle);
double ydist = dist*sin (angle);
return UI_PointPair
(UI_Point (p.XCoord() - (long) xdist, p.YCoord() + (long) ydist),
UI_Point (p.XCoord() + (long) xdist, p.YCoord() - (long) ydist));
}
static short Ccw (const UI_Point& p0, const UI_Point& p1,
const UI_Point& p2)
{
// This is from p. 350 of Sedgewick's book "Algorithms" (second
// edition).
long dx1, dx2, dy1, dy2;
dx1 = p1.XCoord() - p0.XCoord();
dy1 = p1.YCoord() - p0.YCoord();
dx2 = p2.XCoord() - p0.XCoord();
dy2 = p2.YCoord() - p0.YCoord();
long t = dx1 * dy2 - dy1 * dx2;
if (t < 0)
return 1;
if (t > 0)
return -1;
if (dx1 * dx2 < 0 || dy1 * dy2 < 0)
return -1;
return (dx1 * dx1 + dy1 * dy1 >= dx2 * dx2 + dy2 * dy2) ? 0 : 1;
}
bool UI_LineSegment::Intersects (const UI_LineSegment& l) const
{
// From Sedgewick's book "Algorithms" second edition, p. 350.
UI_PointPair l1 = EndPoints(), l2 = l.EndPoints();
return (Ccw (l1.p1, l1.p2, l2.p1) * Ccw (l1.p1, l1.p2, l2.p2) <= 0) &&
(Ccw (l2.p1, l2.p2, l1.p1) * Ccw (l2.p1, l2.p2, l1.p2) <= 0);
}
UI_HitTest UI_LineSegment::HitTest (const UI_Point& p) const
{
return OnBoundary (p) ? UIHit_Boundary : UIHit_Outside;
}
bool UI_LineSegment::DrawOn (UI_DrawingSurface& sfc, const UI_Point& p)
const
{
sfc.DrawLine (p + _p1, p + _p2);
return TRUE;
}
bool UI_LineSegment::ReshapeTo (const UI_Point& p1, const UI_Point& p2)
{
if (!PrepareToChange())
return FALSE;
_p1 = p1;
_p2 = p2;
Notify ();
return TRUE;
}
void UI_LineSegment::operator= (const CL_Object& o)
{
if (o.IsA (*this))
*this = (const UI_LineSegment&) o;
}
UI_LineSegment& UI_LineSegment::operator= (const UI_LineSegment& o)
{
if (PrepareToChange()) {
_p1 = o._p1;
_p2 = o._p2;
Notify();
}
return *this;
}
bool UI_LineSegment::OnBoundary (const UI_Point& p) const
{
long xx1 = p.XCoord() - _p1.XCoord();
long x2x1 = _p2.XCoord() - _p1.XCoord();
long yy1 = p.YCoord() - _p1.YCoord();
long y2y1 = _p2.YCoord() - _p1.YCoord();
return xx1 * y2y1 == x2x1 * yy1 &&
(xx1 * xx1 + yy1 * yy1 <= x2x1 * x2x1 + y2y1 * y2y1);
}
UI_Rectangle UI_LineSegment::BoundingRectangle() const
{
long x1 = _p1.XCoord();
long y1 = _p1.YCoord();
long x2 = _p2.XCoord();
long y2 = _p2.YCoord();
UI_Point origin (minl (x1, x2), minl (y1, y2));
return UI_Rectangle (origin, abs (x2 - x1 + 1), abs (y2 - y1 + 1));
}
inline bool IsBetween (long a, long m, long n)
{
// Check if a is between m and n
return a >= minl (m, n) && a <= maxl (m, n);
}
static bool _IntersectHorz (const UI_Point& p1, const UI_Point& p2,
long x1, long x2, long y)
{
// Check if the line segment between p1 and p2 intersects the
// horizontal line segment between (x1, y) and (x2, y). The idea is to
// use the parametric equation for the line segment between p1 and p2:
// x = x1 + t * (x2 - x1)
// y = y1 + t * (y2 - y1)
// where t is between 0 and 1.
long p1x = p1.XCoord(), p2x = p2.XCoord();
long p1y = p1.YCoord(), p2y = p2.YCoord();
if (p1y == p2y)
return (p1y == y && ((p1x == x1 && p2x == x2) ||
(p1x == x2 && p2x == x1)));
double t = (y - p1y) / ((double) (p2y - p1y));
if (t < 0 || t > 1)
return FALSE;
long x = p1x + t * (p2x - p1x);
return IsBetween (x, x1, x2) ? TRUE : FALSE;
}
static bool _IntersectVert (const UI_Point& p1, const UI_Point& p2,
long y1, long y2, long x)
{
// Check if the line segment between p1 and p2 intersects the
// vertical line segment between (x, y1) and (x, y2).
long p1x = p1.XCoord(), p2x = p2.XCoord();
long p1y = p1.YCoord(), p2y = p2.YCoord();
if (p1x == p2x)
return (p1x == x && ((p1y == y1 && p2y == y2) ||
(p1y == y2 && p2y == y1)));
double t = (x - p1x) / ((double) (p2x - p1x));
if (t < 0 || t > 1)
return FALSE;
long y = p1y + t * (p2y - p1y);
return IsBetween (y, y1, y2) ? TRUE : FALSE;
}
bool UI_LineSegment::IntersectsBoundary (const UI_Rectangle& r) const
{
long bottom = r.Bottom();
long top = r.Top ();
long left = r.Left ();
long right = r.Right ();
return _IntersectHorz (_p1, _p2, bottom, left, right) ||
_IntersectHorz (_p1, _p2, top, left, right) ||
_IntersectVert (_p1, _p2, left, top, bottom) ||
_IntersectVert (_p1, _p2, right, top, bottom);
}
bool UI_LineSegment::IsContainedIn (const UI_Rectangle& r) const
{
return (r.Includes (_p1) && r.Includes (_p2));
}
UI_PointPair UI_LineSegment::EndPoints () const
{
return UI_PointPair (_p1, _p2);
}
UI_Point UI_LineSegment::Center () const
{
return UI_Point ((_p1.XCoord() + _p2.XCoord())/2,
(_p1.YCoord() + _p2.YCoord())/2);
}
double UI_LineSegment::Slope() const
{
double xWidth = _p2.XCoord() - _p1.XCoord();
if (xWidth == 0)
return ULONG_MAX;
return (_p1.YCoord() -_p2.YCoord())/ xWidth;
}