Rhino orients objects onto a surface by defining a rotation transformation. With the Rhino SDK, you define transformations with the ON_Xform class. See opennurbs_xform.h for details. The transformation ths is defined rotates objects from one plane to another. The source plane is defined from the active view's construction plane and a user-selected base point. The target plane is defined by the location the user picks on the surface.
The following example code demonstrates how to orient objects on a surface. Note, this code does not contain all of the options available in the Rhino command, nor does it show the objects transforming dynamically. But, it is a good example on how to build the transformation.
CRhinoCommand::result CCommandTest::RunCommand( const CRhinoCommandContext& context )
{
// Select objects to orient
CRhinoGetObject go;
go.SetCommandPrompt( L"Select objects to orient" );
go.EnableSubObjectSelect( FALSE );
go.EnableGroupSelect( TRUE );
go.GetObjects( 1, 0 );
if( go.CommandResult() != success )
return go.CommandResult();
// Point to orient from
CRhinoGetPoint gp;
gp.SetCommandPrompt( L"Point to orient from" );
gp.GetPoint();
if( gp.CommandResult() != success )
return gp.CommandResult();
// Define source plane
CRhinoView* view = gp.View();
if( 0 == view )
{
view = RhinoApp().ActiveView();
if( 0 == view )
return failure;
}
ON_Plane source_plane( view->Viewport().ConstructionPlane().m_plane );
source_plane.SetOrigin( gp.Point() );
// Surface to orient on
CRhinoGetObject gs;
gs.SetCommandPrompt( L"Surface to orient on" );
gs.SetGeometryFilter( CRhinoGetObject::surface_object );
gs.EnableSubObjectSelect( TRUE );
gs.EnableDeselectAllBeforePostSelect( false );
gs.EnableOneByOnePostSelect();
gs.GetObjects( 1, 1 );
if( gs.CommandResult() != success )
return gs.CommandResult();
const CRhinoObjRef& ref = gs.Object(0);
// Get selected surface object
const CRhinoObject* obj = ref.Object();
if( 0 == obj )
return failure;
// Get selected surface (face)
const ON_BrepFace* face = ref.Face();
if( 0 == face )
return failure;
// Unselect surface
obj->Select( false );
// Point on surface to orient to
gp.SetCommandPrompt( L"Point on surface to orient to" );
gp.Constrain( *face );
gp.GetPoint();
if( gp.CommandResult() != success )
return gp.CommandResult();
// Do transformation
CRhinoCommand::result rc = failure;
double u = 0.0, v = 0.0;
if( face->GetClosestPoint(gp.Point(), &u, &v) )
{
ON_Plane target_plane;
if( face->FrameAt(u, v, target_plane) )
{
// If the face orientation is opposite
// of natural surface orientation, then
// flip the plane's zaxis.
if( face->m_bRev )
target_plane.CreateFromFrame(
target_plane.origin,
target_plane.xaxis,
-target_plane.zaxis
);
// Build transformation
ON_Xform xform;
xform.Rotation( source_plane, target_plane );
// Do the transformation. In this example,
// we will copy the original objects
bool bDeleteOriginal = false;
int i;
for( i = 0; i < go.ObjectCount(); i++ )
context.m_doc.TransformObject( go.Object(i), xform, bDeleteOriginal );
context.m_doc.Redraw();
rc = success;
}
}
return rc;
}
public override IRhinoCommand.result RunCommand(IRhinoCommandContext context)
{
// Select objects to orient
MRhinoGetObject go = new MRhinoGetObject();
go.SetCommandPrompt( "Select objects to orient" );
go.EnableSubObjectSelect(false);
go.EnableGroupSelect( true );
go.GetObjects( 1, 0 );
if( go.CommandResult() != IRhinoCommand.result.success )
return go.CommandResult();
// Point to orient from
MRhinoGetPoint gp = new MRhinoGetPoint();
gp.SetCommandPrompt( "Point to orient from" );
gp.GetPoint();
if( gp.CommandResult() != IRhinoCommand.result.success )
return gp.CommandResult();
// Define source plane
MRhinoView view = gp.View();
if( view == null )
{
view = RhUtil.RhinoApp().ActiveView();
if( view == null )
return IRhinoCommand.result.failure;
}
OnPlane source_plane = new OnPlane(view.ActiveViewport().ConstructionPlane().m_plane);
source_plane.SetOrigin( gp.Point() );
// Surface to orient on
MRhinoGetObject gs = new MRhinoGetObject();
gs.SetCommandPrompt( "Surface to orient on" );
gs.SetGeometryFilter( IRhinoGetObject.GEOMETRY_TYPE_FILTER.surface_object );
gs.EnableSubObjectSelect( true );
gs.EnableDeselectAllBeforePostSelect( false );
gs.EnableOneByOnePostSelect();
gs.GetObjects( 1, 1 );
if( gs.CommandResult() != IRhinoCommand.result.success )
return gs.CommandResult();
IRhinoObjRef objref = gs.Object(0);
// Get selected surface object
IRhinoObject obj = objref.Object();
if( obj == null )
return IRhinoCommand.result.failure;
// Get selected surface (face)
IOnBrepFace face = objref.Face();
if( face == null )
return IRhinoCommand.result.failure;
// Unselect surface
obj.Select( false );
// Point on surface to orient to
gp.SetCommandPrompt( "Point on surface to orient to" );
gp.Constrain( face );
gp.GetPoint();
if( gp.CommandResult() != IRhinoCommand.result.success )
return gp.CommandResult();
// Do transformation
IRhinoCommand.result rc = IRhinoCommand.result.failure;
double u = 0.0, v = 0.0;
if( face.GetClosestPoint( gp.Point(), ref u, ref v ) )
{
OnPlane target_plane = new OnPlane();
if( face.FrameAt(u, v, ref target_plane) )
{
// If the face orientation is opposite
// of natural surface orientation, then
// flip the plane's zaxis.
if( face.m_bRev )
target_plane.CreateFromFrame( target_plane.origin,
target_plane.xaxis,
-target_plane.zaxis );
// Build transformation
OnXform xform = new OnXform();
xform.Rotation( source_plane, target_plane );
// Do the transformation. In this example,
// we will copy the original objects
bool bDeleteOriginal = false;
for (int i = 0; i < go.ObjectCount(); i++)
{
MRhinoObjRef or = go.Object(i);
context.m_doc.TransformObject(ref or, xform, bDeleteOriginal);
}
context.m_doc.Redraw();
rc = IRhinoCommand.result.success;
}
}
return rc;
}
Public Overrides Function RunCommand(ByVal context As RMA.Rhino.IRhinoCommandContext) _
As RMA.Rhino.IRhinoCommand.result
' Select objects to orient
Dim go As New MRhinoGetObject()
go.SetCommandPrompt("Select objects to orient")
go.EnableSubObjectSelect(False)
go.EnableGroupSelect(True)
go.GetObjects(1, 0)
If (go.CommandResult() <> IRhinoCommand.result.success) Then
Return go.CommandResult()
End If
' Point to orient from
Dim gp As New MRhinoGetPoint()
gp.SetCommandPrompt("Point to orient from")
gp.GetPoint()
If (gp.CommandResult() <> IRhinoCommand.result.success) Then
Return gp.CommandResult()
End If
' Define source plane
Dim view As MRhinoView = gp.View()
If (view Is Nothing) Then
view = RhUtil.RhinoApp().ActiveView()
If (view Is Nothing) Then Return IRhinoCommand.result.failure
End If
Dim source_plane As New OnPlane(view.ActiveViewport().ConstructionPlane().m_plane)
source_plane.SetOrigin(gp.Point())
' Surface to orient on
Dim gs As New MRhinoGetObject()
gs.SetCommandPrompt("Surface to orient on")
gs.SetGeometryFilter(IRhinoGetObject.GEOMETRY_TYPE_FILTER.surface_object)
gs.EnableSubObjectSelect(True)
gs.EnableDeselectAllBeforePostSelect(False)
gs.EnableOneByOnePostSelect()
gs.GetObjects(1, 1)
If (gs.CommandResult() <> IRhinoCommand.result.success) Then
Return gs.CommandResult()
End If
Dim objref As IRhinoObjRef = gs.Object(0)
' Get selected surface object
Dim obj As IRhinoObject = objref.Object()
If (obj Is Nothing) Then Return IRhinoCommand.result.failure
' Get selected surface (face)
Dim face As IOnBrepFace = objref.Face()
If (face Is Nothing) Then Return IRhinoCommand.result.failure
' Unselect surface
obj.Select(False)
' Point on surface to orient to
gp.SetCommandPrompt("Point on surface to orient to")
gp.Constrain(face)
gp.GetPoint()
If (gp.CommandResult() <> IRhinoCommand.result.success) Then
Return gp.CommandResult()
End If
' Do transformation
Dim rc As IRhinoCommand.result = IRhinoCommand.result.failure
Dim u As Double = 0.0, v As Double = 0.0
If (face.GetClosestPoint(gp.Point(), u, v)) Then
Dim target_plane As New OnPlane()
If (face.FrameAt(u, v, target_plane)) Then
' If the face orientation is opposite
' of natural surface orientation, then
' flip the plane's zaxis.
If (face.m_bRev) Then
target_plane.CreateFromFrame(target_plane.origin, _
target_plane.xaxis, _
-target_plane.zaxis)
End If
' Build transformation
Dim xform As New OnXform()
xform.Rotation(source_plane, target_plane)
' Do the transformation. In this example,
' we will copy the original objects
Dim bDeleteOriginal As Boolean = False
For i As Integer = 0 To go.ObjectCount() - 1
Dim obr As MRhinoObjRef = go.Object(i)
context.m_doc.TransformObject(obr, xform, bDeleteOriginal)
Next
context.m_doc.Redraw()
rc = IRhinoCommand.result.success
End If
End If
Return rc
End Function