mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-02-28 19:16:09 +08:00
267 lines
6.0 KiB
C++
267 lines
6.0 KiB
C++
#include "opennurbs.h"
|
|
|
|
#if !defined(ON_COMPILING_OPENNURBS)
|
|
// This check is included in all opennurbs source .c and .cpp files to insure
|
|
// ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled.
|
|
// When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined
|
|
// and the opennurbs .h files alter what is declared and how it is declared.
|
|
#error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs
|
|
#endif
|
|
|
|
ON_Box::ON_Box()
|
|
{}
|
|
|
|
ON_Box::ON_Box( const ON_BoundingBox& bbox )
|
|
{
|
|
Create(bbox);
|
|
}
|
|
|
|
ON_Box::~ON_Box()
|
|
{}
|
|
|
|
void ON_Box::Destroy()
|
|
{
|
|
plane = ON_xy_plane;
|
|
dx = ON_Interval::EmptyInterval;
|
|
dy = ON_Interval::EmptyInterval;
|
|
dz = ON_Interval::EmptyInterval;
|
|
}
|
|
|
|
bool ON_Box::IsValid() const
|
|
{
|
|
return ( dx.IsIncreasing()
|
|
&& dy.IsIncreasing()
|
|
&& dz.IsIncreasing()
|
|
&& plane.IsValid()
|
|
);
|
|
}
|
|
|
|
bool ON_Box::Create( const ON_BoundingBox& bbox )
|
|
{
|
|
plane = ON_xy_plane;
|
|
dx.Set(bbox.m_min.x,bbox.m_max.x);
|
|
dy.Set(bbox.m_min.y,bbox.m_max.y);
|
|
dz.Set(bbox.m_min.z,bbox.m_max.z);
|
|
return (dx.IsValid() && dy.IsValid() && dz.IsValid());
|
|
}
|
|
|
|
int ON_Box::IsDegenerate( double tolerance ) const
|
|
{
|
|
int rc = 0;
|
|
// 0 box is not degenerate
|
|
// 1 box is a rectangle (degenerate in one direction)
|
|
// 2 box is a line (degenerate in two directions)
|
|
// 3 box is a point (degenerate in three directions)
|
|
// 4 box is not valid
|
|
if ( !dx.IsIncreasing() || !dy.IsIncreasing() || !dz.IsIncreasing() )
|
|
{
|
|
rc = 4;
|
|
}
|
|
else
|
|
{
|
|
const ON_3dVector diag(dx.Length(),dy.Length(),dz.Length());
|
|
if ( !ON_IsValid(tolerance) || tolerance < 0.0 )
|
|
{
|
|
// compute scale invariant tolerance
|
|
tolerance = diag.MaximumCoordinate()*ON_SQRT_EPSILON;
|
|
}
|
|
if ( diag.x <= tolerance )
|
|
rc++;
|
|
if ( diag.y <= tolerance )
|
|
rc++;
|
|
if ( diag.z <= tolerance )
|
|
rc++;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
ON_3dPoint ON_Box::Center() const
|
|
{
|
|
return plane.PointAt(dx.Mid(),dy.Mid(),dz.Mid());
|
|
}
|
|
|
|
bool ON_Box::GetCorners( ON_3dPoint* corners ) const
|
|
{
|
|
int i,j,k,n=0;
|
|
double r,s,t;
|
|
for( i= 0; i < 2; i++ )
|
|
{
|
|
r = dx.m_t[i];
|
|
for ( j = 0; j < 2; j++ )
|
|
{
|
|
s = dy.m_t[j];
|
|
for ( k = 0; k < 2; k++ )
|
|
{
|
|
t = dz.m_t[k];
|
|
corners[n++] = plane.PointAt(r,s,t);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ON_Box::GetCorners( ON_SimpleArray<ON_3dPoint>& corners ) const
|
|
{
|
|
corners.Empty();
|
|
corners.Reserve(8);
|
|
bool rc = GetCorners(corners.Array());
|
|
if (rc)
|
|
corners.SetCount(8);
|
|
return rc;
|
|
}
|
|
|
|
ON_BoundingBox ON_Box::BoundingBox() const
|
|
{
|
|
ON_BoundingBox bbox;
|
|
ON_3dPoint corners[8];
|
|
if ( GetCorners(corners) )
|
|
bbox.Set(3,0,8,3,&corners[0].x,false);
|
|
return bbox;
|
|
}
|
|
|
|
ON_3dPoint ON_Box::PointAt(
|
|
double r,
|
|
double s,
|
|
double t
|
|
) const
|
|
{
|
|
// Do not validate - it is too slow.
|
|
return plane.PointAt(r,s,t);
|
|
}
|
|
|
|
// returns point on cylinder that is closest to given point
|
|
bool ON_Box::ClosestPointTo( ON_3dPoint point, double* r, double* s, double* t ) const
|
|
{
|
|
// Do not validate box - it is too slow.
|
|
const ON_3dVector v = point - plane.origin;
|
|
|
|
*r = v*plane.xaxis;
|
|
if ( *r < dx.m_t[0] )
|
|
*r = dx.m_t[0];
|
|
else if ( *r > dx.m_t[1] )
|
|
*r = dx.m_t[1];
|
|
|
|
*s = v*plane.yaxis;
|
|
if ( *s < dy.m_t[0] )
|
|
*s = dy.m_t[0];
|
|
else if ( *s > dy.m_t[1] )
|
|
*s = dy.m_t[1];
|
|
|
|
*t = v*plane.zaxis;
|
|
if ( *t < dz.m_t[0] )
|
|
*t = dz.m_t[0];
|
|
else if ( *t > dz.m_t[1] )
|
|
*t = dz.m_t[1];
|
|
|
|
return true;
|
|
}
|
|
|
|
ON_3dPoint ON_Box::ClosestPointTo( ON_3dPoint point ) const
|
|
{
|
|
// Do not validate - it is too slow.
|
|
double r,s,t;
|
|
ClosestPointTo(point,&r,&s,&t);
|
|
return PointAt(r,s,t);
|
|
}
|
|
|
|
// rotate box about its center
|
|
bool ON_Box::Rotate(
|
|
double sin_angle,
|
|
double cos_angle,
|
|
const ON_3dVector& axis // axis of rotation
|
|
)
|
|
{
|
|
return Rotate(sin_angle, cos_angle, axis, Center() );
|
|
}
|
|
|
|
bool ON_Box::Rotate(
|
|
double angle, // angle in radians
|
|
const ON_3dVector& axis // axis of rotation
|
|
)
|
|
{
|
|
return Rotate(sin(angle), cos(angle), axis, plane.origin );
|
|
}
|
|
|
|
// rotate box about a point and axis
|
|
bool ON_Box::Rotate(
|
|
double sin_angle,
|
|
double cos_angle,
|
|
const ON_3dVector& axis, // axis of rotation
|
|
const ON_3dPoint& point // center of rotation
|
|
)
|
|
{
|
|
return plane.Rotate( sin_angle, cos_angle, axis, point );
|
|
}
|
|
|
|
bool ON_Box::Rotate(
|
|
double angle, // angle in radians
|
|
const ON_3dVector& axis, // axis of rotation
|
|
const ON_3dPoint& point // center of rotation
|
|
)
|
|
{
|
|
return Rotate(sin(angle),cos(angle),axis,point);
|
|
}
|
|
|
|
bool ON_Box::Translate(
|
|
const ON_3dVector& delta
|
|
)
|
|
{
|
|
return plane.Translate(delta);
|
|
}
|
|
|
|
|
|
bool ON_Box::Transform( const ON_Xform& xform )
|
|
{
|
|
ON_3dPoint corners[8];
|
|
bool rc = GetCorners(corners);
|
|
if ( rc )
|
|
{
|
|
ON_Plane xplane(plane);
|
|
rc = xplane.Transform(xform);
|
|
if ( rc )
|
|
{
|
|
int i;
|
|
for ( i = 0; i < 8; i++ )
|
|
{
|
|
corners[i] = xform*corners[i];
|
|
}
|
|
double x0,x1,x,y0,y1,y,z0,z1,z;
|
|
ON_3dVector v = corners[7] - plane.origin;
|
|
x0 = x1 = v*plane.xaxis;
|
|
y0 = y1 = v*plane.yaxis;
|
|
z0 = z1 = v*plane.zaxis;
|
|
for ( i = 0; i < 7; i++ )
|
|
{
|
|
v = corners[i] - plane.origin;
|
|
x = v*plane.xaxis;
|
|
if ( x < x0 ) x0 = x; else if (x > x1 ) x1 = x;
|
|
y = v*plane.yaxis;
|
|
if ( y < y0 ) y0 = y; else if (y > y1 ) y1 = y;
|
|
z = v*plane.zaxis;
|
|
if ( z < z0 ) z0 = z; else if (z > z1 ) z1 = z;
|
|
}
|
|
double tol = ON_SQRT_EPSILON;
|
|
if ( fabs(dx.ParameterAt(x0)) > tol || fabs(dx.ParameterAt(x1)-1.0) > tol )
|
|
dx.Set(x0,x1);
|
|
if ( fabs(dy.ParameterAt(y0)) > tol || fabs(dy.ParameterAt(y1)-1.0) > tol )
|
|
dy.Set(y0,y1);
|
|
if ( fabs(dz.ParameterAt(z0)) > tol || fabs(dz.ParameterAt(z1)-1.0) > tol )
|
|
dz.Set(z0,z1);
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
double ON_Box::Volume() const
|
|
{
|
|
return dx.Length()*dy.Length()*dz.Length();
|
|
}
|
|
|
|
double ON_Box::Area() const
|
|
{
|
|
double a = dx.Length();
|
|
double b = dy.Length();
|
|
double c = dz.Length();
|
|
return 2.0*(a*b + b*c + c*a);
|
|
}
|