// // 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 . // //////////////////////////////////////////////////////////////// #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; } */