mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-01 03:26:09 +08:00
419 lines
9.8 KiB
C++
419 lines
9.8 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_Cone::ON_Cone()
|
|
{
|
|
height = 0.0;
|
|
}
|
|
|
|
ON_Cone::ON_Cone(
|
|
const ON_Plane& p,
|
|
double h,
|
|
double r
|
|
)
|
|
{
|
|
Create(p,h,r);
|
|
}
|
|
|
|
ON_Cone::~ON_Cone()
|
|
{}
|
|
|
|
|
|
bool ON_Cone::Create(
|
|
const ON_Plane& p,
|
|
double h,
|
|
double r
|
|
)
|
|
{
|
|
plane = p;
|
|
height = h;
|
|
radius = r;
|
|
return IsValid();
|
|
}
|
|
|
|
bool ON_Cone::IsValid() const
|
|
{
|
|
return (plane.IsValid() && height != 0.0 && radius != 0.0);
|
|
}
|
|
|
|
|
|
const ON_3dVector& ON_Cone::Axis() const
|
|
{
|
|
return plane.zaxis;
|
|
}
|
|
|
|
const ON_3dPoint& ON_Cone::ApexPoint() const
|
|
{
|
|
return plane.origin;
|
|
}
|
|
|
|
ON_3dPoint ON_Cone::BasePoint() const
|
|
{
|
|
return plane.origin + height*plane.zaxis;
|
|
}
|
|
|
|
double ON_Cone::AngleInRadians() const
|
|
{
|
|
return height == 0.0 ? (radius!=0.0?ON_PI:0.0) : atan(radius/height);
|
|
}
|
|
|
|
double ON_Cone::AngleInDegrees() const
|
|
{
|
|
return 180.0*AngleInRadians()/ON_PI;
|
|
}
|
|
|
|
ON_Circle ON_Cone::CircleAt(
|
|
double height_parameter
|
|
) const
|
|
{
|
|
ON_Circle c(plane,radius);
|
|
c.Translate(height_parameter*plane.zaxis);
|
|
if ( height != 0.0 )
|
|
c.radius *= height_parameter/height;
|
|
else if (height_parameter==0.0)
|
|
c.radius = 0.0;
|
|
return c;
|
|
}
|
|
|
|
ON_Line ON_Cone::LineAt(
|
|
double radial_parameter
|
|
) const
|
|
{
|
|
return ON_Line(PointAt(radial_parameter,height),ApexPoint());
|
|
}
|
|
|
|
|
|
ON_3dPoint ON_Cone::PointAt( double radial_parameter, double height_parameter ) const
|
|
{
|
|
double r;
|
|
if ( height != 0.0 )
|
|
r = (radius/height)*height_parameter;
|
|
else
|
|
r = (height_parameter == 0.0)?0.0:radius;
|
|
return plane.PointAt(r*cos(radial_parameter),r*sin(radial_parameter)) + height_parameter*plane.zaxis;
|
|
}
|
|
|
|
ON_3dVector ON_Cone::NormalAt( double radial_parameter, double height_parameter ) const
|
|
{
|
|
double s = sin(radial_parameter);
|
|
double c = cos(radial_parameter);
|
|
if ( radius<0.) {
|
|
c = -c;
|
|
s = -s;
|
|
}
|
|
ON_3dVector ds = c*plane.yaxis - s*plane.xaxis;
|
|
ON_3dVector N = ON_CrossProduct( ((radius<0.0)?-ds:ds),
|
|
plane.PointAt(radius*c,radius*s,height) - plane.origin
|
|
);
|
|
N.Unitize();
|
|
return N;
|
|
}
|
|
|
|
bool ON_Cone::Transform( const ON_Xform& xform )
|
|
{
|
|
ON_Circle xc(plane,radius);
|
|
bool rc = xc.Transform(xform);
|
|
if (rc)
|
|
{
|
|
ON_3dPoint xH = xform*(plane.origin + height*plane.zaxis);
|
|
double xh = (xH-xc.plane.origin)*xc.plane.zaxis;
|
|
plane = xc.plane;
|
|
radius = xc.radius;
|
|
height = xh;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
bool ON_Cone::ClosestPointTo(
|
|
ON_3dPoint point,
|
|
double* radial_parameter,
|
|
double* height_parameter
|
|
) const
|
|
{
|
|
// untested code
|
|
|
|
bool rc = false;
|
|
|
|
ON_3dVector v = (point-plane.origin);
|
|
double x = v*plane.xaxis;
|
|
double y = v*plane.yaxis;
|
|
double z = v*plane.zaxis;
|
|
|
|
if ( radial_parameter )
|
|
{
|
|
double a = ( 0.0 == y && 0.0 == x ) ? 0.0 : atan2(y,x);
|
|
|
|
if (a > 2.0*ON_PI )
|
|
{
|
|
a -= 2.0*ON_PI;
|
|
}
|
|
|
|
if (a < 0.0 )
|
|
{
|
|
a += 2.0*ON_PI;
|
|
}
|
|
|
|
*radial_parameter = a;
|
|
}
|
|
|
|
if (height_parameter)
|
|
{
|
|
point.x -= plane.origin.x;
|
|
point.y -= plane.origin.y;
|
|
point.z -= plane.origin.z;
|
|
v.x = x;
|
|
v.y = y;
|
|
v.z = 0.0;
|
|
v.Unitize();
|
|
v.x *= radius;
|
|
v.y *= radius;
|
|
ON_Line line(ON_3dPoint::Origin, v.x*plane.xaxis + v.y*plane.yaxis + height*plane.zaxis );
|
|
rc = line.ClosestPointTo(point,&z);
|
|
if (rc)
|
|
{
|
|
*height_parameter = z*height;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
// returns point on cylinder that is closest to given point
|
|
ON_3dPoint ON_Cone::ClosestPointTo(
|
|
ON_3dPoint point
|
|
) const
|
|
{
|
|
// untested code
|
|
|
|
ON_3dVector v = (point-plane.origin);
|
|
double x = v*plane.xaxis;
|
|
double y = v*plane.yaxis;
|
|
//double z = v*plane.zaxis;
|
|
|
|
point.x -= plane.origin.x;
|
|
point.y -= plane.origin.y;
|
|
point.z -= plane.origin.z;
|
|
v.x = x;
|
|
v.y = y;
|
|
v.z = 0.0;
|
|
v.Unitize();
|
|
v.x *= radius;
|
|
v.y *= radius;
|
|
ON_Line line(ON_3dPoint::Origin, v.x*plane.xaxis + v.y*plane.yaxis + height*plane.zaxis );
|
|
return line.ClosestPointTo(point);
|
|
}
|
|
|
|
bool ON_Cone::Rotate(
|
|
double sin_angle,
|
|
double cos_angle,
|
|
const ON_3dVector& axis_of_rotation
|
|
)
|
|
{
|
|
return Rotate( sin_angle, cos_angle, axis_of_rotation, plane.origin );
|
|
}
|
|
|
|
bool ON_Cone::Rotate(
|
|
double angle,
|
|
const ON_3dVector& axis_of_rotation
|
|
)
|
|
{
|
|
return Rotate( sin(angle), cos(angle), axis_of_rotation, plane.origin );
|
|
}
|
|
|
|
// rotate plane about a point and axis
|
|
bool ON_Cone::Rotate(
|
|
double sin_angle,
|
|
double cos_angle,
|
|
const ON_3dVector& axis_of_rotation,
|
|
const ON_3dPoint& center_of_rotation
|
|
)
|
|
{
|
|
return plane.Rotate( sin_angle, cos_angle, axis_of_rotation, center_of_rotation );
|
|
}
|
|
|
|
bool ON_Cone::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_Cone::Translate(
|
|
const ON_3dVector& delta
|
|
)
|
|
{
|
|
return plane.Translate( delta );
|
|
}
|
|
|
|
int ON_Cone::GetNurbForm( ON_NurbsSurface& s ) const
|
|
{
|
|
int rc = 0;
|
|
if ( IsValid() ) {
|
|
ON_Circle c = CircleAt(height);
|
|
ON_NurbsCurve n;
|
|
c.GetNurbForm(n);
|
|
ON_3dPoint apex = ApexPoint();
|
|
ON_4dPoint cv;
|
|
int i, j0, j1;
|
|
|
|
s.Create(3,true,3,2,9,2);
|
|
for ( i = 0; i < 10; i++ )
|
|
s.m_knot[0][i] = n.m_knot[i];
|
|
|
|
if ( height >= 0.0 ) {
|
|
s.m_knot[1][0] = 0.0;
|
|
s.m_knot[1][1] = height;
|
|
j0 = 0;
|
|
j1 = 1;
|
|
}
|
|
else {
|
|
s.m_knot[1][0] = height;
|
|
s.m_knot[1][1] = 0.0;
|
|
j0 = 1;
|
|
j1 = 0;
|
|
}
|
|
|
|
for ( i = 0; i < 9; i++ ) {
|
|
cv = n.CV(i);
|
|
s.SetCV(i, j1, ON::homogeneous_rational, &cv.x );
|
|
cv.x = apex.x*cv.w;
|
|
cv.y = apex.y*cv.w;
|
|
cv.z = apex.z*cv.w;
|
|
s.SetCV(i, j0, cv);
|
|
}
|
|
rc = 2;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
ON_RevSurface* ON_Cone::RevSurfaceForm( ON_RevSurface* srf ) const
|
|
{
|
|
if ( srf )
|
|
srf->Destroy();
|
|
ON_RevSurface* pRevSurface = nullptr;
|
|
if ( IsValid() )
|
|
{
|
|
ON_Line line;
|
|
ON_Interval line_domain;
|
|
if ( height >= 0.0 )
|
|
line_domain.Set(0.0,height);
|
|
else
|
|
line_domain.Set(height,0.0);
|
|
line.from = PointAt(0.0,line_domain[0]);
|
|
line.to = PointAt(0.0,line_domain[1]);
|
|
ON_LineCurve* line_curve = new ON_LineCurve( line, line_domain[0], line_domain[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 = plane.origin;
|
|
pRevSurface->m_axis.to = plane.origin + plane.zaxis;
|
|
pRevSurface->m_bTransposed = false;
|
|
pRevSurface->m_bbox.m_min = plane.origin;
|
|
pRevSurface->m_bbox.m_max = plane.origin;
|
|
pRevSurface->m_bbox.Union(CircleAt(height).BoundingBox());
|
|
}
|
|
return pRevSurface;
|
|
}
|
|
|
|
/*
|
|
// obsolete use ON_BrepCone
|
|
ON_Brep* ON_Cone::BrepForm( ON_Brep* brep ) const
|
|
{
|
|
ON_Brep* pBrep = 0;
|
|
if ( brep )
|
|
brep->Destroy();
|
|
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 cap
|
|
ON_Circle circle = CircleAt(height);
|
|
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[1];
|
|
ON_BrepTrim& trim = pBrep->NewTrim( edge, true, loop, pBrep->m_C2.Count()-1 );
|
|
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->SetTrimIsoFlags(trim);
|
|
for ( int eti = 0; eti < edge.m_ti.Count(); eti++ )
|
|
pBrep->m_T[ edge.m_ti[eti] ].m_type = ON_BrepTrim::mated;
|
|
if ( !pBrep->IsValid() )
|
|
{
|
|
if (brep)
|
|
brep->Destroy();
|
|
else
|
|
delete pBrep;
|
|
pBrep = 0;
|
|
}
|
|
}
|
|
}
|
|
return pBrep;
|
|
}
|
|
*/
|