#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 invarient 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& 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); }