home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dream 52
/
Amiga_Dream_52.iso
/
Linux
/
Divers
/
freedraft.tar.gz
/
freedraft.tar
/
FREEdraft-050298
/
GEOMLIB2D
/
arc.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1998-05-01
|
6KB
|
202 lines
// arc.cpp
// Copyright (C) 1997 Cliff Johnson //
// //
// This program is free software; you can redistribute it and/or //
// modify it under the terms of the GNU General Public //
// License as published by the Free Software Foundation; either //
// version 2 of the License, or (at your option) any later version. //
// //
// This software is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU //
// General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this software (see COPYING.LIB); if not, write to the //
// Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. //
#include "arc.h"
#include "geom_enum.h"
#include <math.h>
#include "circle.h"
#include "geomexception.h"
//====================================================================================
// unit arc - default constructor
Arc::Arc():Geom(ARC) // default is unit radius arc at origin in quadrant 1
{
center = Point();
origin = Point(1,0);
endpoint = Point(0,1);
arcAngle = M_PI/2.;
}
//====================================================================================
// Arc by center ,origin, endpoint
// arcs are always interpreted right-handed from origin to endpoint
Arc::Arc(const Point& c, const Point& o, const Point& e)throw (GeomException)
:Geom(ARC),center(c), origin(o)
{
// c == o - degenerate circles are not allowed
if( c == origin )
throw GeomException("Arc::Arc(c,o,e) : center and origin are coincident");
// origin and endpoint equal means full arc
if( c == e )
{
endpoint = o;
arcAngle = 2 * M_PI; // closed arc
}
// regular case, are RH until intersection of arc with vector ce
else
{
Vector dir= e - c;
dir = dir.Normal(); // should never throw null vector
// exception because we know c != e from above :)
// gosh I hope that's true!
endpoint = c + ( c.Distance(origin) * dir);
if(endpoint == origin)
{
arcAngle = 2 * M_PI; // closed arc
}
else
{
Vector v = o - c;
arcAngle = Angle(dir,v); // open arc
// determine direction
Vector vx = Cross(v,dir);
if(vx[2] < 0)arcAngle = (2 * M_PI) - arcAngle;
}
}
}
//====================================================================================
double Arc::Radius() const
{
return center.Distance(origin);
}
//====================================================================================
Point Arc::U(double u) const
{
Vector v = origin - center;
double sine = sin(u * arcAngle);
double cosine = cos(u * arcAngle);
return center + Point( v[0]*cosine - v[1]*sine, v[0]*sine + v[1]*cosine);
}
//====================================================================================
ostream& operator<<(ostream& os, const Arc& c)
{
os << "Arc: center= " << c.center << " origin= " << c.origin << " endpoint= " << c.endpoint;
return os;
}
//====================================================================================
Point Arc::Project(const Point& p ) const throw (GeomException)
{
// return the point projected on the arc. Throw exception if projection is not within
// arc domain or point is at arc center
if(p == center) throw GeomException("Arc::Project() : Point is at Arc center");
Vector v1 = origin - center;
// vector from center to point
Vector v2 = p - center;
// determine the angle of the point with respect the v1
double ang = Angle(origin - center,v2);
Point cross = Cross(v1,v2);
if(cross[2] < 0)ang = ang + M_PI; // quadrant III and IV
if(ang > arcAngle)throw GeomException("Arc::Project() : Point does not project onto arc");
return center + ( v2.Normal() * Radius() ) ;
}
//====================================================================================
double Arc::UProject(const Point& p ) const throw (GeomException)
{
// return the u value of a projected point
// throw exception if point is not within the domain of the arc
// or point is at center
if(p == center) throw GeomException("Arc::UProject() : Point is at Arc center");
Vector v1 = origin - center;
// vector from center to point
Vector v2 = p - center;
// determine the angle of the point with respect the v1
double ang = Angle(origin - center,v2);
Point cross = Cross(v1,v2);
if(cross[2] < 0)ang = ang + M_PI; // quadrant III and IV
if(ang > arcAngle)throw GeomException("Arc::UProject() : Point does not project onto arc");
return ang / arcAngle; // return ratio dude.
}
//====================================================================================
Circle Arc::Support() const
{
return Circle(center,origin);
}
//====================================================================================
double Arc::Distance(const Point& p ) const
{
// you might think by the nature of selection, you should get the correct
// solution... but then consider arcs... oh oh. :(
if(p == center) return Radius();
// vector from center to point
Vector v = p - center;
// normalize v
v = v.Normal(); // should never throw null vector exception
// because of above check :)
// find a valid solution - or none.
Vector vco = origin - center;
// case 1
double ang = Angle(vco,v);
Vector px = Cross(vco,v);
if(px[2]<0)ang = 2 * M_PI - ang;
if ( 0 < ang && ang < ArcAngle()) return p.Distance(center + Radius() * v);
// case 2
double d0;
ang = ang + M_PI;
if(ang > (2*M_PI))ang = ang - 2 * M_PI;
if ( 0 < ang && ang < ArcAngle())d0 = p.Distance(center - Radius() * v);
else d0 = 1e+99;
// case 3,4
double d1 = p.Distance(origin);
double d2 = p.Distance(endpoint);
if(d0 < d1 && d0 < d2) return d0;
if(d1 < d2) return d1;
return d2;
}