How to loft in the SDK with Match Start Tangent and Match End Tangent?

So we have 2 Brep Edges, and are trying to (in C#) loft between them with matching start and end tangent.

To demonstrate the results I am looking for, do the follow)
Create 2 planar surfaces in the top viewport (from 4 corner points SrfPt), rotate one of them in the front viewport, so that they are not both in the same plane.
Now run the command loft, pick 2 brep edges 1 from each surface with the mouse, press enter, and then in the dialog box that pops up click the boxes next to ‘Match start tangent’ & ‘Match end tangent’
Next click the Preview button, (or OK) and you get a nice smooth surface that flows between the original 2 surfaces.

How can this be done from C#? using either RhinoCommon or Rhino .NET SDK?

I have tried the example here:


adapted it to pick OnBrepEdge’s and then experimented with:

        args.m_bAllowStartTangent =true;
        args.m_bAllowEndTangent = true;

and also:

        args.m_start_condition = (int)IArgsRhinoLoft.eLoftEnds.leTangent;
        args.m_end_condition = (int)IArgsRhinoLoft.eLoftEnds.leTangent;

and other combinations, but cannot achieve the result described above from using the loft command.

Is this result possible? or am I out of luck?

in this image, you can see the black wireframe brep made from the Loft command, and the gold flat result is all I can get back from my C# code.

You must give the curves as BrepEdge (OnBrepEdge/ON_BrepEdge), and not as “just” a curve (don’t call .DuplicateCurve() or .ToNurbsCurve() on the brep edges).

The BrepEdge can refer to its parent Brep and get continuity information; if you pass only normal curves, this continuity information is not obtained.

I had the a similar problem when performing NetworkSrf from code a while ago, and for me the solution was to pass in unmodified BrepEdge objects.

I took out any curve duplicate but still cannot get it to work:

  // Fill in loft arguments class
            MArgsRhinoLoft args = new MArgsRhinoLoft();
            args.m_bAllowStartTangent = true;   //???
            args.m_bAllowEndTangent = true;   //???
            args.m_bUseStartpoint = false;
            args.m_bUseEndpoint = false;
            args.m_bClosed = false;
            args.m_loft_type = (int)IArgsRhinoLoft.eLoftType.ltNormal;   //???
            args.m_simplify_method = (int)IArgsRhinoLoft.eLoftSimplify.lsNone;
            args.m_start_condition = (int)IArgsRhinoLoft.eLoftEnds.leTangent;   //???
            args.m_end_condition = (int)IArgsRhinoLoft.eLoftEnds.leTangent;   //???
            args.m_rebuild_point_count = 10;
            args.m_refit_tolerance = 0.001;

            int object_count = go.ObjectCount();
            MRhinoLoftCurve[] loftcurves = new MRhinoLoftCurve[object_count];

            // Add loft curves
            for (int i = 0; i < object_count; i++)
            {
                // get the edge Instance from the GetObject
                IOnBrepEdge edge = go.Object(i).Edge();
                // get the OnBrep;
                OnBrep b = edge.Brep();
                // and get from that the OnBrepEdge. (No duplication here)
                OnBrepEdge curve = b.Edge(edge.m_edge_index);

                if (curve != null)
                {
                    loftcurves[i] = new MRhinoLoftCurve();
                    loftcurves[i].m_curve = curve;
                    loftcurves[i].m_pick_point = new On3dPoint(OnUtil.On_UNSET_POINT);
                    loftcurves[i].m_pick_t = OnUtil.On_UNSET_VALUE;
                    loftcurves[i].m_trim = null;
                    loftcurves[i].m_bClosed = loftcurves[i].m_curve.IsClosed();
                    loftcurves[i].m_bPlanar = loftcurves[i].m_curve.IsPlanar(loftcurves[i].m_plane);
                }
            }
            args.m_loftcurves = loftcurves;

            // Do the loft operation
            OnNurbsSurface[] surface_list = null;
            bool rc = RhUtil.RhinoSdkLoftSurface(args, out surface_list);

this is what I am doing after doing a MRhinoGetObject to get 2 edge curves:

    // Select curves to loft
            MRhinoGetObject go = new MRhinoGetObject();
            go.SetCommandPrompt("Select edge curves to loft");
            go.SetGeometryFilter(IRhinoGetObject.GEOMETRY_TYPE_FILTER.edge_object);
            go.EnableSubObjectSelect(true);
            go.GetObjects(2, 0);

I put //??? next to any values I have changed, as I have tried many combinations of these, and still cannot get the smooth result?
What else am I missing?

Ok, I’ve never seen these loft arguments before, but I have a suspicion about this line:

loftcurves[i].m_trim = null;

If the datatype of this m_trim is OnBrepTrim, try what happens when you can put the trim that is associated with the edge here. You should be able to get the trim like

IOnBrepTrim edgeTrim = b.Trim(curve.m_ti[0]); 

or something along those lines.

This is thinking along the lines that if you add the trim as well, this may impart the continuity information.

WOW, thank you, I don’t understand what that means, but it DOES work!!!

Now that I have a working example, I should be able to figure the rest out from here.

Thanks Again.

I always find this picture very insightful, http://wiki.mcneel.com/developer/brepstructure

Here you can see that each edge has its own trim(s). These are defined in the parameter space of the underlying surface, and so link the edge curve to the surface. The surface is needed to calculate the curvature which the loft needs to use. I hope it makes sense :smiley: