To determine the normal direction of a surface, you can use one of the following functions:
ON_Surface::NormalAt ON_Surface::EvNormal
To determine the normal direction of a face which is part of a brep, you can also use the above functions, as an ON_BrepFace object is derived from ON_Surface. But, you will also need to take into account the orientation of the brep face. If the orientation of the brep face is opposite of the underlying, natural surface orientation, then you will need to reverse the direction of the calculated normal vector.
It should also be noted that most surface in Rhino are really breps with a single face.
The following sample code demonstrates how to interactively determine the normal direction of a selected surface or brep face.
CRhinoCommand::result CCommandNormal::RunCommand( const CRhinoCommandContext& context )
{
// Select a surface
CRhinoGetObject go;
go.SetCommandPrompt( L"Select surface" );
go.SetGeometryFilter( CRhinoGetObject::surface_object );
go.GetObjects( 1, 1 );
if( go.CommandResult() != success )
return go.CommandResult();
// Get the selected face
const CRhinoObjRef& ref = go.Object(0);
const ON_BrepFace* face = ref.Face();
if( 0 == face )
return failure;
// Pick a point on the surface. Constrain
// picking to the face.
CRhinoGetPoint gp;
gp.SetCommandPrompt( L"Select point on surface" );
gp.Constrain( *face );
gp.GetPoint();
if( gp.CommandResult() != success )
return gp.CommandResult();
ON_3dPoint pt = gp.Point();
// Get the parameters of the point on the
// surface that is closest to pt
double u, v;
if( face->GetClosestPoint(pt, &u, &v) )
{
ON_3dPoint pt;
ON_3dVector du, dv, dir;
if( face->EvNormal(u, v, pt, du, dv, dir) )
{
// if the face orientation is opposite of
// the natural surface orientation, then
// reverse the direction of the vector.
if( face->m_bRev )
dir.Reverse();
RhinoApp().Print(
L"Surface normal at uv(%.2f,%.2f) = (%.2f,%.2f,%.2f)\n",
u,
v,
dir.x,
dir.y,
dir.z
);
}
}
return success;
}
public override IRhinoCommand.result RunCommand(IRhinoCommandContext context)
{
// Select a surface
MRhinoGetObject go = new MRhinoGetObject();
go.SetCommandPrompt( "Select surface" );
go.SetGeometryFilter( IRhinoGetObject.GEOMETRY_TYPE_FILTER.surface_object );
go.GetObjects( 1, 1 );
if( go.CommandResult() != IRhinoCommand.result.success )
return go.CommandResult();
// Get the selected face
IRhinoObjRef objref = go.Object(0);
IOnBrepFace face = objref.Face();
if( face == null )
return IRhinoCommand.result.failure;
// Pick a point on the surface. Constrain
// picking to the face.
MRhinoGetPoint gp = new MRhinoGetPoint();
gp.SetCommandPrompt( "Select point on surface" );
gp.Constrain( face );
gp.GetPoint();
if( gp.CommandResult() != IRhinoCommand.result.success )
return gp.CommandResult();
On3dPoint pt = gp.Point();
// Get the parameters of the point on the
// surface that is closest to pt
double u=0.0, v=0.0;
if( face.GetClosestPoint(pt, ref u, ref v) )
{
On3dVector du = new On3dVector();
On3dVector dv = new On3dVector();
On3dVector dir = new On3dVector();
if( face.EvNormal( u, v, ref pt, ref du, ref dv, ref dir ) )
{
// if the face orientation is opposite of
// the natural surface orientation, then
// reverse the direction of the vector.
if( face.m_bRev )
dir.Reverse();
object[] args = {u,v,dir.x,dir.y,dir.z};
string msg = string.Format("Surface normal at uv({0:f},{1:f}) = ({2:f},{3:f},{4:f})\n", args);
RhUtil.RhinoApp().Print( msg );
}
}
return IRhinoCommand.result.success;
}
Public Overrides Function RunCommand(ByVal context As RMA.Rhino.IRhinoCommandContext) _
As RMA.Rhino.IRhinoCommand.result
' Select a surface
Dim go As New MRhinoGetObject()
go.SetCommandPrompt("Select surface")
go.SetGeometryFilter(IRhinoGetObject.GEOMETRY_TYPE_FILTER.surface_object)
go.GetObjects(1, 1)
If (go.CommandResult() <> IRhinoCommand.result.success) Then
Return go.CommandResult()
End If
' Get the selected face
Dim objref As IRhinoObjRef = go.Object(0)
Dim face As IOnBrepFace = objref.Face()
If (face Is Nothing) Then Return IRhinoCommand.result.failure
' Pick a point on the surface. Constrain
' picking to the face.
Dim gp As New MRhinoGetPoint()
gp.SetCommandPrompt("Select point on surface")
gp.Constrain(face)
gp.GetPoint()
If (gp.CommandResult() <> IRhinoCommand.result.success) Then
Return gp.CommandResult()
End If
Dim pt As On3dPoint = gp.Point()
' Get the parameters of the point on the
' surface that is closest to pt
Dim u As Double = 0.0, v As Double = 0.0
If (face.GetClosestPoint(pt, u, v)) Then
Dim du As New On3dVector()
Dim dv As New On3dVector()
Dim dir As New On3dVector()
If (face.EvNormal(u, v, pt, du, dv, dir)) Then
' if the face orientation is opposite of
' the natural surface orientation, then
' reverse the direction of the vector.
If (face.m_bRev) Then dir.Reverse()
Dim args() As Object = {u, v, dir.x, dir.y, dir.z}
Dim msg As String
msg = String.Format("Surface normal at uv({0:f},{1:f}) = ({2:f},{3:f},{4:f})", args)
RhUtil.RhinoApp().Print(msg + vbCrLf)
End If
End If
Return IRhinoCommand.result.success
End Function