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

375 lines
9.3 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_Cylinder::ON_Cylinder()
{
height[0] = 0.0;
height[1] = 0.0;
}
ON_Cylinder::ON_Cylinder(
const ON_Circle& c
)
{
Create(c);
}
ON_Cylinder::ON_Cylinder(
const ON_Circle& c,
double h
)
{
Create(c,h);
}
ON_Cylinder::~ON_Cylinder()
{}
bool ON_Cylinder::Create(
const ON_Circle& c
)
{
return Create( c, 0.0 );
}
bool ON_Cylinder::Create(
const ON_Circle& c,
double h
)
{
circle = c;
if ( h > 0.0 ) {
height[0] = 0.0;
height[1] = h;
}
else {
height[0] = h;
height[1] = 0.0;
}
return IsValid();
}
bool ON_Cylinder::IsValid() const
{
return circle.IsValid();
}
bool ON_Cylinder::IsFinite() const
{
return height[0] != height[1];
}
const ON_3dVector& ON_Cylinder::Axis() const
{
return circle.plane.zaxis;
}
const ON_3dPoint& ON_Cylinder::Center() const
{
return circle.plane.origin;
}
double ON_Cylinder::Height() const
{
return height[1] - height[0];
}
ON_Circle ON_Cylinder::CircleAt(
double t // linear parameter
) const
{
ON_Circle c = circle;
if ( t != 0.0 )
c.Translate(t*circle.plane.zaxis);
return c;
}
ON_Line ON_Cylinder::LineAt(
double s // angular parameter
) const
{
ON_3dPoint p = circle.PointAt(s);
ON_Line line;
line.from = p + height[0]*circle.plane.zaxis;
line.to = p + height[1]*circle.plane.zaxis;
return line;
}
ON_3dPoint ON_Cylinder::PointAt( double s, double t ) const
{
return ( circle.PointAt(s) + t*circle.plane.zaxis );
}
ON_3dPoint ON_Cylinder::NormalAt( double s, double t ) const
{
ON_3dVector N = ON_CrossProduct( circle.TangentAt(s), circle.plane.zaxis );
N.Unitize();
return N;
}
// returns parameters of point on cylinder that is closest to given point
bool ON_Cylinder::ClosestPointTo(
ON_3dPoint point,
double* s, // angular parameter
double* t // linear parameter
) const
{
bool rc = true;
//const ON_3dVector v = point - circle.plane.origin;
double h = (point - circle.plane.origin)*circle.plane.zaxis;
if ( s )
rc = circle.ClosestPointTo( point - h*circle.plane.zaxis, s );
if ( t ) {
if ( height[0] < height[1] ) {
if ( h < height[0] ) h = height[0]; else if ( h > height[1] ) h = height[1];
}
else if ( height[0] > height[1] ) {
if ( h > height[0] ) h = height[0]; else if ( h < height[1] ) h = height[1];
}
*t = h;
}
return rc;
}
// returns point on cylinder that is closest to given point
ON_3dPoint ON_Cylinder::ClosestPointTo(
ON_3dPoint point
) const
{
double s, t;
ClosestPointTo( point, &s, &t );
return PointAt( s, t );
}
// rotate plane about its origin
bool ON_Cylinder::Rotate(
double sin_angle,
double cos_angle,
const ON_3dVector& axis // axis of rotation
)
{
return Rotate( sin_angle, cos_angle, axis, circle.plane.origin );
}
bool ON_Cylinder::Rotate(
double angle, // angle in radians
const ON_3dVector& axis // axis of rotation
)
{
return Rotate( sin(angle), cos(angle), axis, circle.plane.origin );
}
// rotate plane about a point and axis
bool ON_Cylinder::Rotate(
double sin_angle, // sin(angle)
double cos_angle, // cos(angle)
const ON_3dVector& axis, // axis of rotation
const ON_3dPoint& point // center of rotation
)
{
return circle.Rotate( sin_angle, cos_angle, axis, point );
}
bool ON_Cylinder::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_Cylinder::Translate(
const ON_3dVector& delta
)
{
return circle.Translate( delta );
}
int ON_Cylinder::GetNurbForm( ON_NurbsSurface& s ) const
{
int rc = 0;
if ( IsValid() && height[0] != height[1] ) {
ON_NurbsCurve n0, n1;
int i;
ON_Circle c0 = CircleAt(height[0]);
ON_Circle c1 = CircleAt(height[1]);
if ( height[0] <= height[1] ) {
c0.GetNurbForm(n0);
c1.GetNurbForm(n1);
}
else {
c0.GetNurbForm(n1);
c1.GetNurbForm(n0);
}
if ( n0.m_dim != n1.m_dim
|| n0.m_is_rat != n1.m_is_rat
|| n0.m_order != n1.m_order
|| n0.m_cv_count != n1.m_cv_count )
return 0;
s.Create(3,true, n0.m_order, 2, n0.m_cv_count, 2 );
if ( height[0] <= height[1] ) {
s.m_knot[1][0] = height[0];
s.m_knot[1][1] = height[1];
}
else {
s.m_knot[1][0] = height[1];
s.m_knot[1][1] = height[0];
}
for ( i = 0; i < n0.KnotCount(); i++ )
s.m_knot[0][i] = n0.m_knot[i];
for ( i = 0; i < n0.m_cv_count; i++ ) {
s.SetCV(i,0,ON::homogeneous_rational,n0.CV(i));
s.SetCV(i,1,ON::homogeneous_rational,n1.CV(i));
}
rc = 2;
}
return rc;
}
ON_RevSurface* ON_Cylinder::RevSurfaceForm( ON_RevSurface* srf ) const
{
if ( srf )
srf->Destroy();
ON_RevSurface* pRevSurface = nullptr;
if ( IsFinite() && IsValid() )
{
ON_Line line;
line.from = PointAt(0.0,height[0]);
line.to = PointAt(0.0,height[1]);
ON_Interval h(height[0],height[1]); // h = evaluation domain for line (must be increasing)
if ( h.IsDecreasing() )
h.Swap();
ON_LineCurve* line_curve = new ON_LineCurve( line, h[0], h[1] );
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_curve = line_curve;
pRevSurface->m_axis.from = circle.plane.origin;
pRevSurface->m_axis.to = circle.plane.origin + circle.plane.zaxis;
pRevSurface->m_bTransposed = false;
ON_Circle c0(circle);
c0.Translate(height[0]*circle.plane.zaxis);
ON_Circle c1(circle);
c1.Translate(height[1]*circle.plane.zaxis);
pRevSurface->m_bbox = c0.BoundingBox();
pRevSurface->m_bbox.Union(c1.BoundingBox());
}
return pRevSurface;
}
/*
// obsolete use ON_BrepCylinder
ON_Brep* ON_Cylinder::BrepForm( ON_Brep* brep ) const
{
if ( brep )
brep->Destroy();
ON_Brep* pBrep = 0;
ON_RevSurface* pRevSurface = RevSurfaceForm();
if ( pRevSurface )
{
if ( brep )
pBrep = brep;
else
pBrep = new ON_Brep();
if ( !pBrep->Create(pRevSurface) )
{
if ( !brep )
delete pBrep;
pBrep = 0;
if (pRevSurface)
{
delete pRevSurface;
pRevSurface = 0;
}
}
else
{
// add caps
for ( int capcount = 0; capcount < 2; capcount++ )
{
// capcount = 0 for bottom cap and 1 for top cap
ON_Circle circle = CircleAt(height[capcount]);
if ( capcount == 0 )
circle.Reverse();
double radius = circle.radius;
ON_NurbsSurface* pCapSurface = ON_NurbsSurfaceQuadrilateral(
circle.plane.PointAt(-radius,-radius),
circle.plane.PointAt(+radius,-radius),
circle.plane.PointAt(+radius,+radius),
circle.plane.PointAt(-radius,+radius)
);
pCapSurface->m_knot[0][0] = -fabs(radius);
pCapSurface->m_knot[0][1] = fabs(radius);
pCapSurface->m_knot[1][0] = pCapSurface->m_knot[0][0];
pCapSurface->m_knot[1][1] = pCapSurface->m_knot[0][1];
circle.Create( ON_xy_plane, ON_3dPoint::Origin, radius );
ON_NurbsCurve* c2 = new ON_NurbsCurve();
circle.GetNurbForm(*c2);
c2->ChangeDimension(2);
pBrep->m_S.Append(pCapSurface);
pBrep->m_C2.Append(c2);
ON_BrepFace& cap = pBrep->NewFace( pBrep->m_S.Count()-1 );
ON_BrepLoop& loop = pBrep->NewLoop( ON_BrepLoop::outer, cap );
ON_BrepEdge& edge = pBrep->m_E[capcount?0:2];
ON_BrepTrim& trim = pBrep->NewTrim( edge, true, loop, pBrep->m_C2.Count()-1 );
for ( int eti = 0; eti < edge.m_ti.Count(); eti++ )
pBrep->m_T[ edge.m_ti[eti] ].m_type = ON_BrepTrim::mated;
trim.m_tolerance[0] = 0.0;
trim.m_tolerance[1] = 0.0;
trim.m_pbox.m_min.x = -radius;
trim.m_pbox.m_min.y = -radius;
trim.m_pbox.m_min.z = 0.0;
trim.m_pbox.m_max.x = radius;
trim.m_pbox.m_max.y = radius;
trim.m_pbox.m_max.z = 0.0;
loop.m_pbox = trim.m_pbox;
pBrep->SetTrimTypeFlags(trim);
pBrep->SetTrimIsoFlags(trim);
}
if ( !pBrep->IsValid() )
{
if (brep)
brep->Destroy();
else
delete pBrep;
pBrep = 0;
}
}
}
return pBrep;
}
*/