home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
yacl-012.zip
/
ui
/
ellipse.cxx
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-09
|
6KB
|
201 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>
#if defined(__MS_WINDOWS__)
#include <windows.h>
#endif
#include "ui/ellipse.h"
#include "ui/dwgsurf.h"
#include "ui/grutils.h"
#ifndef M_PI
#define M_PI 3.1415926535897932
#endif
UI_Ellipse::UI_Ellipse ()
{
_majorAxis = _minorAxis = 0;
}
UI_Ellipse::UI_Ellipse (const UI_Rectangle& r)
{
_majorAxis = r.Width();
_minorAxis = r.Height ();
_origin = UI_Point (r.Left() + _majorAxis/2, r.Top() + _minorAxis/2);
}
UI_Ellipse::UI_Ellipse (long major_axis, long minor_axis, UI_Point origin)
: _origin (origin)
{
_majorAxis = major_axis;
_minorAxis = minor_axis;
}
bool UI_Ellipse::DrawOn (UI_DrawingSurface& sfc, const UI_Point& p) const
{
UI_Rectangle e (p + _origin - UI_Point (_majorAxis/2, _minorAxis/2),
_majorAxis, _minorAxis);
sfc.DrawEllipse (e);
return TRUE;
}
bool UI_Ellipse::Fill (UI_DrawingSurface& s) const
{
s.DrawEllipse (BoundingRectangle(), UID_Fill);
return TRUE;
}
bool UI_Ellipse::ReshapeTo (const UI_Point& p1, const UI_Point& p2)
{
if (!PrepareToChange())
return FALSE;
UI_Rectangle r (p1, p2.XCoord() - p1.XCoord(), p2.YCoord() -
p1.YCoord());
long major = r.Width();
long minor = r.Height();
_origin = r.Origin() + UI_Point (major/2, minor/2);
_majorAxis = major;
_minorAxis = minor;
Notify();
return TRUE;
}
UI_Rectangle UI_Ellipse::BoundingRectangle() const
{
long x = _origin.XCoord();
long y = _origin.YCoord();
return UI_Rectangle (x -_majorAxis/2, y - _minorAxis/2, _majorAxis,
_minorAxis);
}
UI_Point UI_Ellipse::PointAtAngle (double deg) const
{
double semiMinor = _minorAxis/((double) 2.0);
// First, reduce deg modulo 360
long ldeg = (long) deg;
long reduced = ldeg % 360;
deg = reduced + deg - ldeg; // Add back fractional part
if (deg < 0)
deg += 360;
UI_Point pt; // Point computed assuming that ellipse center is origin
if (deg == 90)
pt = UI_Point (0, _origin.YCoord() - (long) semiMinor);
// ----------------------------------^--
// Remember that the origin of the co-ordinate system is at top
// left.
else if (deg == 270)
pt = UI_Point (0, _origin.YCoord() + (long) semiMinor);
else {
double theta = DegToRad (deg);
double semiMajor = _majorAxis/((double) 2.0);
double asq = semiMajor * semiMajor;
double bsq = semiMinor * semiMinor;
double cosTheta = cos (theta);
double sinTheta = sin (theta);
double csqTheta = cosTheta * cosTheta; // square of cos (theta)
double ssqTheta = sinTheta * sinTheta; // square of sin (theta)
double dist = sqrt (asq * bsq /
(bsq * csqTheta + asq * ssqTheta));
pt = UI_Point ((long) (dist * cosTheta), (long) (-dist * sinTheta));
// ----------------------------------------------^ -----
// We negate it, because the y co-ordinates increase downwards, not
// upwards
}
return pt + Center ();
}
UI_HitTest UI_Ellipse::HitTest (const UI_Point& p) const
{
double x = p.XCoord() - _origin.XCoord();
double y = p.YCoord() - _origin.YCoord();
// First check if p is on the Y axis
if (x == 0) {
double semiMinor = _minorAxis/((double) 2.0);
return (y > -semiMinor || y < semiMinor) ? UIHit_Outside
: ((y == -semiMinor || y == semiMinor) ? UIHit_Boundary :
UIHit_Inside);
}
// p is not on the Y axis. Translate the ellipse so that its center is
// at the origin. Then find the angle theta that the vector from the
// origin to p subtends wrt the X axis. Check the length of this vector
// against the distance of the point q on the ellipse's periphery at
// angle theta.
double theta = atan2 (-y, x);
// --------------------^--------
// Negate y, because angles are counterclockwise as usual, but the y
// co-ordinates increase downwards, not upwards
UI_Point q = PointAtAngle (RadToDeg (theta)) - Center();
double a = q.XCoord();
double b = q.YCoord();
double d1 = a*a + b*b;
double d2 = x*x + y*y;
return d1 > d2 ? UIHit_Inside
: ((long) d1 == (long) d2 ? UIHit_Boundary : UIHit_Outside);
}
bool UI_Ellipse::Includes (const UI_Point& p) const
{
UI_HitTest t = HitTest (p);
return t == UIHit_Boundary || t == UIHit_Inside;
}
bool UI_Ellipse::IntersectsBoundary (const UI_Rectangle& r) const
{
short count = 0;
if (Includes (r.TopLeft()))
count++;
if (Includes (r.TopRight()))
count++;
if (Includes (r.BottomLeft()))
count++;
if (Includes (r.BottomRight()))
count++;
return count != 0 && count != 4;
}