int ON_Intersect( // returns 0 = no intersections, // 1 = one intersection, // 2 = 2 intersections // 3 = line lies on cylinder // If 0 is returned, first point is point // on line closest to cylinder and 2nd point is the point // on the sphere closest to the line. // If 1 is returned, first point is obtained by evaluating // the line and the second point is obtained by evaluating // the cylinder. const ON_Line& line, const ON_Cylinder& cylinder, // if cylinder.height[0]==cylinder.height[1], // then infinite cyl is used. Otherwise // finite cyl is used. ON_3dPoint& A, ON_3dPoint& B // intersection point(s) returned here ) { ON_BOOL32 bFiniteCyl = true; int rc = 0; const double cylinder_radius = fabs(cylinder.circle.radius); double tol = cylinder_radius*ON_SQRT_EPSILON; if ( tol < ON_ZERO_TOLERANCE ) tol = ON_ZERO_TOLERANCE; ON_Line axis; axis.from = cylinder.circle.plane.origin + cylinder.height[0]*cylinder.circle.plane.zaxis; axis.to = cylinder.circle.plane.origin + cylinder.height[1]*cylinder.circle.plane.zaxis; if ( axis.Length() <= tol ) { axis.to = cylinder.circle.plane.origin + cylinder.circle.plane.zaxis; bFiniteCyl = false; } //ON_BOOL32 bIsParallel = false; double line_t, axis_t; if ( !ON_Intersect(line,axis,&line_t,&axis_t) ) { axis.ClosestPointTo( cylinder.circle.plane.origin, &axis_t ); line.ClosestPointTo( cylinder.circle.plane.origin, &line_t ); } ON_3dPoint line_point = line.PointAt(line_t); ON_3dPoint axis_point = axis.PointAt(axis_t); double d = line_point.DistanceTo(axis_point); if ( bFiniteCyl ) { if ( axis_t < 0.0 ) axis_t = 0.0; else if ( axis_t > 1.0 ) axis_t = 1.0; axis_point = axis.PointAt(axis_t); } if ( d >= cylinder_radius-tol) { rc = ( d <= cylinder_radius+tol ) ? 1 : 0; A = line_point; ON_3dVector V = line_point - axis_point; if ( bFiniteCyl ) { V = V - (V*cylinder.circle.plane.zaxis)*cylinder.circle.plane.zaxis; } V.Unitize(); B = axis_point + cylinder_radius*V; if ( rc == 1 ) { // check for overlap ON_3dPoint P = axis.ClosestPointTo(line.from); d = P.DistanceTo(line.from); if ( fabs(d-cylinder_radius) <= tol ) { P = axis.ClosestPointTo(line.to); d = P.DistanceTo(line.to); if ( fabs(d-cylinder_radius) <= tol ) { rc = 3; A = cylinder.ClosestPointTo(line.from); B = cylinder.ClosestPointTo(line.to); } } } } else { // transform to coordinate system where equation of cyl // is x^2 + y^2 = R^2 and solve for line parameter(s). ON_Xform xform; xform.Rotation( cylinder.circle.plane, ON_xy_plane ); ON_Line L = line; L.Transform(xform); const double x0 = L.from.x; const double x1 = L.to.x; const double x1mx0 = x1-x0; double ax = x1mx0*x1mx0; double bx = 2.0*x1mx0*x0; double cx = x0*x0; const double y0 = L.from.y; const double y1 = L.to.y; const double y1my0 = y1-y0; double ay = y1my0*y1my0; double by = 2.0*y1my0*y0; double cy = y0*y0; double t0, t1; int qerc = ON_SolveQuadraticEquation(ax+ay, bx+by, cx+cy-cylinder_radius*cylinder_radius, &t0,&t1); if ( qerc == 2 ) { // complex roots - ignore (tiny) imaginary part caused by computational noise. t1 = t0; } A = cylinder.ClosestPointTo(line.PointAt(t0)); B = cylinder.ClosestPointTo(line.PointAt(t1)); d = A.DistanceTo(B); if ( d <= ON_ZERO_TOLERANCE ) { A = line_point; ON_3dVector V = line_point - axis_point; if ( bFiniteCyl ) { V = V - (V*cylinder.circle.plane.zaxis)*cylinder.circle.plane.zaxis; } V.Unitize(); B = axis_point + cylinder_radius*V; rc = 1; } else rc = 2; } return rc; }
CRhinoCommand::result CCommandSampleCageEdit::RunCommand( const CRhinoCommandContext& context ) { ON_Workspace ws; CRhinoCommand::result rc = CRhinoCommand::success; // Get the captive object CRhinoGetObject go; go.SetCommandPrompt( L"Select captive surface or polysurface" ); go.SetGeometryFilter( CRhinoGetObject::surface_object | CRhinoGetObject::polysrf_object ); go.GetObjects( 1, 1 ); rc = go.CommandResult(); if( CRhinoCommand::success != rc ) return rc; const CRhinoObject* captive = go.Object(0).Object(); if( 0 == captive ) return CRhinoCommand::failure; // Define the control line ON_Line line; CArgsRhinoGetLine args; rc = RhinoGetLine( args, line ); if( CRhinoCommand::success != rc ) return rc; // Get the curve parameters int degree = 3; int cv_count = 4; for(;;) { CRhinoGetOption gl; gl.SetCommandPrompt( L"NURBS Parameters" ); gl.AcceptNothing(); int d_opt = gl.AddCommandOptionInteger( RHCMDOPTNAME(L"Degree"), °ree, L"Curve degree", 1.0, 100.0 ); int p_opt = gl.AddCommandOptionInteger( RHCMDOPTNAME(L"PointCount"), &cv_count, L"Number of control points", 2.0, 100.0 ); gl.GetOption(); rc = gl.CommandResult(); if( CRhinoCommand::success != rc ) return rc; if( CRhinoGet::nothing == gl.Result() ) break; if( cv_count <= degree ) { if( CRhinoGet::option != gl.Result() ) continue; const CRhinoCommandOption* opt = go.Option(); if( 0 == opt ) continue; if( d_opt == opt->m_option_index ) cv_count = degree + 1; else degree = cv_count - 1; } } // Set up morph control ON_MorphControl* control = new ON_MorphControl(); control->m_varient = 1; // 1= curve // Specify the source line curve control->m_nurbs_curve0.Create( 3, false, 2, 2 ); control->m_nurbs_curve0.MakeClampedUniformKnotVector(); control->m_nurbs_curve0.SetCV( 0, line.from ); control->m_nurbs_curve0.SetCV( 1, line.to ); // Specify the destination NURBS curve control->m_nurbs_curve.Create( 3, false, degree + 1, cv_count ); control->m_nurbs_curve.MakeClampedUniformKnotVector(); double* g = ws.GetDoubleMemory( control->m_nurbs_curve.m_cv_count ); control->m_nurbs_curve.GetGrevilleAbcissae( g ); ON_Interval d = control->m_nurbs_curve.Domain(); double s = 0.0; int i; for( i = 0; i < control->m_nurbs_curve.m_cv_count; i++ ) { s = d.NormalizedParameterAt( g[i] ); control->m_nurbs_curve.SetCV( i, line.PointAt(s) ); } // Make sure domains match s = line.Length(); if( s > ON_SQRT_EPSILON ) control->m_nurbs_curve0.SetDomain( 0.0, s ); d = control->m_nurbs_curve0.Domain(); control->m_nurbs_curve.SetDomain( d[0], d[1] ); // Create the morph control object CRhinoMorphControl* control_object = new CRhinoMorphControl(); control_object->SetControl( control ); context.m_doc.AddObject( control_object ); // Set up the capture RhinoCaptureObject( control_object, const_cast<CRhinoObject*>(captive) ); // Clean up display context.m_doc.UnselectAll(); // Turn on the control grips control_object->EnableGrips( true ); context.m_doc.Redraw( CRhinoView::mark_display_hint ); return rc; }