Sdk Loft Tangent
Last changed: dale@mcneel.com-204.177.179.144

.
DeveloperC++, .NET
VersionRhino 4.0

Also See

How To: Loft Surfaces using RhinoSdkLoftSurface

Summary

When trying to loft a surface with starting and/or ending tangency, it is not enough just to set a CArgsRhinoLoft object's m_start_condition and m_end_condition members to CArgsRhinoLoft::leTangent. You also need to tell Rhino's lofter what it is that this lofted surface need to be tangent to. You do this by setting the m_trim parameter of the starting and ending CRhinoLoftCurve objects. This is a constant ON_BrepTrim pointer. If you are lofting curves that you have picked using a CRhinoGetObject object, you can retrieve this pointer by simply calling CRhinoObjRef::Trim().

Example

The following sample code demonstrates how to loft surfaces that maintain tangency with adjacent surfaces using the CArgsRhinoLoft class and the RhinoSdkLoftSurface function. The definitions of these can be found in rhinoSdkLoft.h. Note, this example does not perform any curve sorting or direction matching. This is the responsibility of the the SDK developer.

  CRhinoCommand::result CCommandTest::RunCommand( const CRhinoCommandContext& context )
  {
    // Select curves to loft
    CRhinoGetObject go;
    go.SetCommandPrompt( L"Select curves to loft" );
    go.SetGeometryFilter( CRhinoGetObject::curve_object | CRhinoGetObject::edge_object);
    go.SetGeometryAttributeFilter( CRhinoGetObject::open_curve );
    go.EnablePreSelect( false );
    go.GetObjects( 2, 0 );
    if( go.CommandResult() != CRhinoCommand::success )
      return go.CommandResult();


    // Create loft arguments object
    const int obj_count = go.ObjectCount();
    CArgsRhinoLoft args;
    args.m_loftcurves.SetCapacity( obj_count );


    // Add curves to loft arguments object
    int i;
    for( i = 0; i < obj_count; i++ )
    {
      const CRhinoObjRef& ref = go.Object(i);
      const ON_Curve* crv = ref.Curve();
      if( crv )
      {
        // New loft curve
        CRhinoLoftCurve* lc = new CRhinoLoftCurve;


        // Duplicate the selected curve. Note,
        // the loft curve will delete this curve.
        lc->m_curve = crv->DuplicateCurve();
        lc->m_curve->RemoveShortSegments( ON_ZERO_TOLERANCE );


        // Set other loft curve parameters
        lc->m_bPlanar = ( lc->m_curve->IsPlanar(&lc->m_plane) ? true : false );


        // If referenced geometry is a surface edge,
        // assign associated brep trim.
        lc->m_trim = ref.Trim();


        // Append loft curve to loft argument
        args.m_loftcurves.Append( lc );
      }
    }


    // If we do not have enough loft curves,
    // clean up and bail.
    const int lc_count = args.m_loftcurves.Count();
    if( lc_count < 2 )
    {
      for( i = 0; i < lc_count; i++ )
        delete args.m_loftcurves[i];
      return failure;
    }


    // If the starting loft curve has a trim, 
    // set the start condition to tangent.
    if( args.m_loftcurves[0] && args.m_loftcurves[0]->m_trim )
    {
      args.m_start_condition = CArgsRhinoLoft::leTangent;
      args.m_bAllowStartTangent = TRUE;
    }


    // If the ending loft curve has a trim, 
    // set the end condition to tangent.
    if( args.m_loftcurves[lc_count-1] && args.m_loftcurves[lc_count-1]->m_trim )
    {
      args.m_end_condition = CArgsRhinoLoft::leTangent;
      args.m_bAllowEndTangent = TRUE;
    }


    // Do the loft calculation
    ON_SimpleArray<ON_NurbsSurface*> srf_list;
    bool rc = RhinoSdkLoftSurface( args, srf_list );


    // Delete the loft curves so we do not leak memory.
    for( i = 0; i < args.m_loftcurves.Count(); i++ )
      delete args.m_loftcurves[i];
    args.m_loftcurves.Empty();


    // If the loft operation failed, bail.
    if( !rc )
      return failure;


    // If only one surface was calculated, add it to Rhino
    if( srf_list.Count() == 1 )
    {
      context.m_doc.AddSurfaceObject( *srf_list[0] );


      // CRhinoDoc::AddSurfaceObject() make a copy.
      // So, delete original so memory is not leaked.
      delete srf_list[0];
    }
    else
    {
      // If more than one surface was calculated, 
      // create a list of breps.
      ON_SimpleArray<ON_Brep*> brep_list;
      for( i = 0; i < srf_list.Count(); i++)
      {
        if( srf_list[i]->IsValid() )
        {
          ON_Brep* brep = ON_Brep::New();
          brep->NewFace( *srf_list[i] );


          // ON_Brep::NewFace() make a copy.
          // So, delete original so memory is not leaked.
          delete srf_list[i];


          brep_list.Append( brep );
        }
      }


      // Try joining all breps
      double tol = context.m_doc.AbsoluteTolerance();
      ON_Brep* brep = RhinoJoinBreps( brep_list, tol );
      if( brep )
      {
        context.m_doc.AddBrepObject( *brep );


        // CRhinoDoc::AddBrepObject() make a copy.
        // So, delete original so memory is not leaked.
        delete brep;
      }
      else
      {
        // Othewise just add the individual breps to Rhino.
        for( i = 0; i < brep_list.Count(); i++ )
        {
          if( brep_list[i] )
          {
            context.m_doc.AddBrepObject( *brep_list[i] );


            // CRhinoDoc::AddBrepObject() make a copy.
            // So, delete original so memory is not leaked.
            delete brep_list[i];
          }
        }
      }
    }


    context.m_doc.Redraw();


    return success;
  }

VB.NET (Rhino 4)

  Public Overrides Function RunCommand(ByVal context As IRhinoCommandContext) _
    As RhinoCommand.result
    ' Select curves to loft
    Dim go As New MRhinoGetObject()
    go.SetCommandPrompt("Select curves to loft")
    go.SetGeometryFilter(IRhinoGetObject.GEOMETRY_TYPE_FILTER.curve_object _
                      Or IRhinoGetObject.GEOMETRY_TYPE_FILTER.edge_object)
    go.SetGeometryAttributeFilter(IRhinoGetObject.GEOMETRY_ATTRIBUTE_FILTER.open_curve)
    go.EnablePreSelect(False)
    go.GetObjects(2, 0)
    If (go.CommandResult() <> IRhinoCommand.result.success) Then
      Return go.CommandResult()
    End If


    ' Create loft arguments object
    Dim obj_count As Integer = go.ObjectCount()
    Dim args As New MArgsRhinoLoft()


    Dim curves As New System.Collections.Generic.List(Of MRhinoLoftCurve)()
    ' Add curves to loft arguments object
    For i As Integer = 0 To obj_count - 1
      Dim ref As MRhinoObjRef = go.Object(i)
      Dim crv As IOnCurve = ref.Curve()
      If (crv IsNot Nothing) Then
        ' New loft curve
        Dim lc As New MRhinoLoftCurve()
        ' Duplicate the selected curve.
        lc.m_curve = crv.DuplicateCurve()
        lc.m_curve.RemoveShortSegments(OnUtil.On_ZERO_TOLERANCE)
        ' Set other loft curve parameters
        lc.m_bPlanar = lc.m_curve.IsPlanar(lc.m_plane)
        ' If referenced geometry is a surface edge,
        ' assign associated brep trim.
        lc.m_trim = ref.Trim()
        ' Append loft curve to loft argument
        curves.Add(lc)
      End If
    Next
    args.m_loftcurves = curves.ToArray()


    ' If we do not have enough loft curves,
    ' clean up and bail.
    Dim lc_count As Integer = args.m_loftcurves.Length
    If (lc_count < 2) Then Return IRhinoCommand.result.failure


    ' If the starting loft curve has a trim, 
    ' set the start condition to tangent.
    If (curves(0).m_trim IsNot Nothing) Then
      args.m_start_condition = IArgsRhinoLoft.eLoftEnds.leTangent
      args.m_bAllowStartTangent = True
    End If


    ' If the ending loft curve has a trim, 
    ' set the end condition to tangent.
    If (curves(curves.Count - 1).m_trim IsNot Nothing) Then
      args.m_end_condition = IArgsRhinoLoft.eLoftEnds.leTangent
      args.m_bAllowEndTangent = True
    End If


    ' Do the loft calculation
    Dim srf_list(0) As OnNurbsSurface
    Dim rc As Boolean = RhUtil.RhinoSdkLoftSurface(args, srf_list)


    ' If the loft operation failed, bail.
    If (Not rc) Then Return IRhinoCommand.result.failure


    ' If only one surface was calculated, add it to Rhino
    If (srf_list.Length = 1) Then
      context.m_doc.AddSurfaceObject(srf_list(0))
    Else
      ' If more than one surface was calculated, 
      ' create a list of breps.
      Dim brep_list As New System.Collections.Generic.List(Of OnBrep)()
      For i As Integer = 0 To srf_list.Length - 1
        If (srf_list(i).IsValid()) Then
          Dim singlebrep As New OnBrep()
          singlebrep.NewFace(srf_list(i))
          brep_list.Add(singlebrep)
        End If
      Next


      ' Try joining all breps
      Dim tol As Double = context.m_doc.AbsoluteTolerance()
      Dim brep As OnBrep = RhUtil.RhinoJoinBreps(brep_list.ToArray(), tol)
      If (brep IsNot Nothing) Then
        context.m_doc.AddBrepObject(brep)
      Else
        ' Othewise just add the individual breps to Rhino.
        For i As Integer = 0 To brep_list.Count - 1
          If (brep_list(i) IsNot Nothing) Then
            context.m_doc.AddBrepObject(brep_list(i))
          End If
        Next
      End If
    End If
    context.m_doc.Redraw()
    Return IRhinoCommand.result.success
  End Function