Files
opennurbs/opennurbs_torus.cpp
2024-02-15 08:00:36 -08:00

309 lines
7.9 KiB
C++

//
// Copyright (c) 1993-2022 Robert McNeel & Associates. All rights reserved.
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
// McNeel & Associates.
//
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
//
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
//
////////////////////////////////////////////////////////////////
#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_Torus::ON_Torus() : major_radius(0.0), minor_radius(0.0)
{}
ON_Torus::ON_Torus( const ON_Plane& major_plane, double major__radius, double minor__radius )
{
Create(major_plane,major__radius,minor__radius);
}
ON_Torus::ON_Torus( const ON_Circle& major__circle, double minor__radius )
{
Create(major__circle,minor__radius);
}
ON_Torus::~ON_Torus()
{}
bool ON_Torus::IsValid( ON_TextLog* text_log ) const
{
bool rc=false;
if ( minor_radius <= 0.0 )
{
if ( text_log )
text_log->Print("ON_Torus.minor_radius = %g (should be > 0)\n",minor_radius);
}
else if ( major_radius <= minor_radius)
{
if ( text_log )
text_log->Print("ON_Torus.major_radius = %g (should be > minor_radius=%g)\n",major_radius,minor_radius);
}
else if ( !plane.IsValid() )
{
if ( text_log )
text_log->Print("ON_Torus.plane is not valid.\n");
}
else
rc = true;
return rc;
}
bool ON_Torus::Create( const ON_Plane& major_plane, double major__radius, double minor__radius )
{
plane = major_plane;
major_radius = major__radius;
minor_radius = minor__radius;
return IsValid();
}
bool ON_Torus::Create( const ON_Circle& major__circle, double minor__radius )
{
return Create( major__circle.plane, major__circle.radius, minor__radius );
}
#define EVAL_SETUP_MINOR \
const double sin_ma = sin(minor_angle_radians);\
const double cos_ma = cos(minor_angle_radians)
#define EVAL_SETUP_MAJOR \
const double sin_MA = sin(major_angle_radians);\
const double cos_MA = cos(major_angle_radians);\
const ON_3dVector raxis = cos_MA*plane.xaxis + sin_MA*plane.yaxis
ON_3dPoint ON_Torus::PointAt(double major_angle_radians, double minor_angle_radians) const
{
EVAL_SETUP_MINOR;
EVAL_SETUP_MAJOR;
return ((major_radius + cos_ma*minor_radius)*raxis + sin_ma*minor_radius*plane.zaxis + plane.origin);
}
ON_3dVector ON_Torus::NormalAt(double major_angle_radians, double minor_angle_radians) const
{
EVAL_SETUP_MINOR;
EVAL_SETUP_MAJOR;
return (cos_ma*raxis + sin_ma*plane.zaxis);
}
ON_Circle ON_Torus::MajorCircleRadians(double minor_angle_radians ) const
{
EVAL_SETUP_MINOR;
ON_Circle c(plane,major_radius);
c.radius = major_radius + cos_ma*minor_radius;
c.plane.origin += sin_ma*minor_radius*plane.zaxis;
c.plane.UpdateEquation();
return c;
}
ON_Circle ON_Torus::MajorCircleDegrees(double minor_angle_degrees ) const
{
return MajorCircleRadians(minor_angle_degrees*ON_PI/180.0);
}
ON_Circle ON_Torus::MinorCircleRadians(double major_angle_radians ) const
{
EVAL_SETUP_MAJOR;
ON_Circle c;
c.plane.xaxis = raxis;
c.plane.yaxis = plane.zaxis;
c.plane.zaxis = ON_CrossProduct( c.plane.xaxis, c.plane.yaxis );
c.plane.origin = plane.origin + major_radius*raxis;
c.plane.UpdateEquation();
c.radius = minor_radius;
return c;
}
ON_Circle ON_Torus::MinorCircleDegrees(double minor_angle_degrees ) const
{
return MinorCircleRadians(minor_angle_degrees*ON_PI/180.0);
}
ON_3dPoint ON_Torus::Center() const
{
return plane.origin;
}
ON_3dVector ON_Torus::Axis() const
{
return plane.zaxis;
}
double ON_Torus::MajorRadius() const
{
return major_radius;
}
double ON_Torus::MinorRadius() const
{
return minor_radius;
}
bool ON_Torus::ClosestPointTo(
ON_3dPoint test_point,
double* major__angle_radians,
double* minor__angle_radians
) const
{
double major_angle_radians, minor_angle_radians;
const ON_Circle major_circle(plane,major_radius);
bool rc = major_circle.ClosestPointTo( test_point, &major_angle_radians );
if ( rc && minor__angle_radians )
{
EVAL_SETUP_MAJOR;
ON_3dVector v = test_point - major_radius*raxis;
rc = v.Unitize();
if ( rc )
{
double sma = v*plane.zaxis;
double cma = v*raxis;
minor_angle_radians = atan2(sma,cma);
if ( minor_angle_radians < 0.0 )
minor_angle_radians += 2.0*ON_PI;
}
else
minor_angle_radians = 0.0;
*minor__angle_radians = minor_angle_radians;
}
if ( major__angle_radians )
*major__angle_radians = major_angle_radians;
return rc;
}
ON_3dPoint ON_Torus::ClosestPointTo( ON_3dPoint test_point ) const
{
const ON_Circle major_circle(plane,major_radius);
ON_3dPoint C = major_circle.ClosestPointTo( test_point );
ON_3dVector v = test_point - C;
if ( !v.Unitize() )
{
v = C - plane.origin;
v.Unitize();
}
return C + minor_radius*v;
}
// rotate cylinder about its origin
bool ON_Torus::Rotate(
double sin_angle,
double cos_angle,
const ON_3dVector& axis // axis of rotation
)
{
return Rotate(sin_angle, cos_angle, axis, plane.origin );
}
bool ON_Torus::Rotate(
double angle, // angle in radians
const ON_3dVector& axis // axis of rotation
)
{
return Rotate(sin(angle), cos(angle), axis, plane.origin );
}
bool ON_Torus::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_Torus::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_Torus::Translate( const ON_3dVector& delta )
{
return plane.Translate(delta);
}
bool ON_Torus::Transform( const ON_Xform& xform )
{
ON_Circle major_c(plane,major_radius);
bool rc = major_c.Transform(xform);
if (rc)
{
double s = (0.0==major_radius) ? 1.0 : major_c.radius/major_radius;
plane = major_c.plane;
major_radius = major_c.radius;
minor_radius *= s;
}
return rc;
}
int ON_Torus::GetNurbForm( ON_NurbsSurface& s ) const
{
int rc = 0;
ON_RevSurface revsrf;
if ( RevSurfaceForm(&revsrf) )
{
rc = revsrf.GetNurbForm(s);
}
else
s.Destroy();
return rc;
}
ON_RevSurface* ON_Torus::RevSurfaceForm( ON_RevSurface* srf ) const
{
if ( srf )
srf->Destroy();
ON_RevSurface* pRevSurface = nullptr;
if ( IsValid() )
{
ON_Circle circle = MinorCircleRadians(0.0);
ON_ArcCurve* circle_crv = new ON_ArcCurve(circle);
if ( srf )
pRevSurface = srf;
else
pRevSurface = new ON_RevSurface();
pRevSurface->m_angle.Set(0.0,2.0*ON_PI);
//pRevSurface->m_t = pRevSurface->m_angle;
pRevSurface->m_t[0] = 0.0;
pRevSurface->m_t[1] = 2.0*ON_PI*MajorRadius();
pRevSurface->m_curve = circle_crv;
pRevSurface->m_axis.from = plane.origin;
pRevSurface->m_axis.to = plane.origin + plane.zaxis;
pRevSurface->m_bTransposed = false;
double r[2], h[2];
h[0] = fabs(minor_radius);
h[1] = -h[0];
r[0] = fabs(major_radius) + h[0];
r[1] = -r[0];
int i, j, k, n=0;
ON_3dPoint pt[8];
for (i=0;i<2;i++)
{
for (j=0;j<2;j++)
{
for (k=0;k<2;k++)
{
pt[n++] = plane.PointAt( r[i], r[j], h[k] );
}
}
}
pRevSurface->m_bbox.Set( 3, 0, 8, 3, &pt[0].x );
}
return pRevSurface;
}