Sweeping Surfaces with Sweep2
Windows only
Demonstrates how to use the CArgsRhinoSweep2 class and the RhinoSweep2 function. The definitions of these can be found in rhinoSdkSweep.h.
// Helper function to calculate rail parameters
bool GetShapeParameterOnRail(
const ON_Curve& shape,
const ON_Curve& rail,
double tol,
double& t
)
{
ON_Interval rail_domain = rail.Domain();
// Test start point
bool rc = rail.GetClosestPoint( shape.PointAtStart(), &t, tol );
if( rc )
{
if( rail.IsClosed() )
{
if( fabs(t - rail_domain.Max()) < ON_SQRT_EPSILON )
t = rail_domain.Min();
if( fabs(t - rail_domain.Min()) < ON_SQRT_EPSILON )
t = rail_domain.Min();
}
return true;
}
// Test end point
rc = rail.GetClosestPoint( shape.PointAtEnd(), &t, tol );
if( rc )
{
if( rail.IsClosed() )
{
if( fabs(t - rail_domain.Max()) < ON_SQRT_EPSILON )
t = rail_domain.Min();
if( fabs(t - rail_domain.Min()) < ON_SQRT_EPSILON )
t = rail_domain.Min();
}
return true;
}
// Try intersecting...
ON_SimpleArray<ON_X_EVENT> x;
if( 1 == rail.IntersectCurve(&shape, x, tol, 0.0) && x[0].IsPointEvent() )
{
t = x[0].m_a[0];
if( rail.IsClosed() )
{
if( fabs(t - rail_domain.Max()) < ON_SQRT_EPSILON )
t = rail_domain.Min();
}
return true;
}
return false;
}
// RhinoSweep2 wrapper function
bool MySweep2(
const ON_Curve* Rail1,
const CRhinoObject* Rail1_obj,
const ON_Curve* Rail2,
const CRhinoObject* Rail2_obj,
ON_SimpleArray<const ON_Curve*> sCurves,
ON_SimpleArray<ON_Brep*>& Sweep2_Breps
)
{
if( 0 == Rail1 | 0 == Rail1_obj )
return false;
if( 0 == Rail2 | 0 == Rail2_obj )
return false;
CRhinoDoc* doc = RhinoApp().ActiveDoc();
if( 0 == doc )
return false;
// Define a new class that contains sweep2 arguments
CArgsRhinoSweep2 args;
// Set the 2 rails
CRhinoPolyEdge Edge1, Edge2;
Edge1.Create( Rail1, Rail1_obj );
Edge2.Create( Rail2, Rail2_obj );
// Ok, we can at least do some rail direction matching
if( !RhinoDoCurveDirectionsMatch(&Edge1, &Edge2) )
Edge2.Reverse();
// Add rails to sweep arguments
args.m_rail_curves[0] = &Edge1;
args.m_rail_curves[1] = &Edge2;
args.m_rail_pick-points[0] = ON_UNSET_POINT;
args.m_rail_pick-points[1] = ON_UNSET_POINT;
// To create a closed sweep, you need to have:
// 1. Two closed rail curves and and a single shape curve, or
// 2. Set CArgsRhinoSweep2::m_bClosed = true
args.m_bClosed = false;
double tol = doc->AbsoluteTolerance();
// Loop through sections to set parameters
for( int i = 0; i < sCurves.Count(); i++ )
{
const ON_Curve* sCurve = sCurves[i];
if( 0 == sCurve )
continue;
// Add to shapes
args.m_shape_curves.Append( sCurve );
// Cook up some rail parameters
double t0 = 0.0;
if( !GetShapeParameterOnRail(*sCurve, Edge1, tol, t0) )
return false;
args.m_rail_params[0].Append( t0 );
double t1 = 0.0;
if( !GetShapeParameterOnRail(*sCurve, Edge2, tol, t1) )
return false;
args.m_rail_params[1].Append( t1 );
}
// Set the rest of parameters
args.m_simplify = 0;
args.m_bSimpleSweep = false;
args.m_bSameHeight = false;
args.m_rebuild_count = -1; //Sample point count for rebuilding shapes
args.m_refit_tolerance = tol;
args.m_sweep_tolerance = tol;
args.m_angle_tolerance = doc->AngleToleranceRadians();
// Sweep2
return RhinoSweep2(args, Sweep2_Breps) ? true : false;
}
// Test command that uses the above functions.
CRhinoCommand::result CCommandTest::RunCommand( const CRhinoCommandContext& context )
{
// Select first rail curve
CRhinoGetObject go1;
go1.SetCommandPrompt( L"Select first rail curve" );
go1.SetGeometryFilter( CRhinoGetObject::curve_object );
go1.EnablePreSelect( false );
go1.GetObjects( 1, 1 );
if( go1.CommandResult() != success )
return go1.CommandResult();
const CRhinoObject* Rail1_obj = go1.Object(0).Object();
const ON_Curve* Rail1 = go1.Object(0).Curve();
if( 0 == Rail1_obj | 0 == Rail1 )
return failure;
// Select second rail curve
CRhinoGetObject go2;
go2.SetCommandPrompt( L"Select second rail curve" );
go2.SetGeometryFilter( CRhinoGetObject::curve_object );
go2.EnablePreSelect( false );
go2.EnableDeselectAllBeforePostSelect( false );
go2.GetObjects( 1, 1 );
if( go2.CommandResult() != success )
return go2.CommandResult();
const CRhinoObject* Rail2_obj = go2.Object(0).Object();
const ON_Curve* Rail2 = go2.Object(0).Curve();
if( 0 == Rail2_obj | 0 == Rail2 )
return failure;
// Select cross section curves
CRhinoGetObject gx;
gx.SetCommandPrompt( L"Select cross section curves" );
gx.SetGeometryFilter( CRhinoGetObject::curve_object );
gx.EnablePreSelect( false );
gx.EnableDeselectAllBeforePostSelect( false );
gx.GetObjects( 1, 0 );
if( gx.CommandResult() != success )
return gx.CommandResult();
ON_SimpleArray<const ON_Curve*> sCurves;
int i;
for( i = 0; i < gx.ObjectCount(); i++ )
{
const ON_Curve* sCurve = gx.Object(i).Curve();
if( sCurve )
sCurves.Append( sCurve );
}
// Call MySweep2 function
ON_SimpleArray<ON_Brep*> Sweep2_Breps;
if( MySweep2(Rail1, Rail1_obj, Rail2, Rail2_obj, sCurves, Sweep2_Breps) )
{
// Add to context then delete
for( i = 0; i < Sweep2_Breps.Count(); i++ )
{
ON_Brep* brep = Sweep2_Breps[i];
if( brep )
{
context.m_doc.AddBrepObject( *brep );
delete Sweep2_Breps[i]; // Don't leak...
Sweep2_Breps[i] = 0;
}
}
context.m_doc.Redraw();
}
return success;
}