Overview
When trying to loft a surface with starting or ending tangency, it is not enough just to set 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()
.
Sample
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 are in rhinoSdkLoft.h.
NOTE: This sample does not perform any curve sorting or direction matching. This is the responsibility of the plugin 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;
}