The following C# post illustrates how to retrieve a solid face normal through some of the functionalities of the BRep API:
// Returns normal vector to a solid3d face [Philippe Leefsma, 7/11/2012]
[CommandMethod("FaceNormal")]
public void FaceNormal()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptEntityOptions peo = new PromptEntityOptions(
"\nSelect a 3D solid: ");
peo.SetRejectMessage("\nInvalid selection…");
peo.AddAllowedClass(typeof(Solid3d), true);
PromptEntityResult per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK)
return;
PromptPointOptions ppo = new PromptPointOptions(
"\nSelect a point on a face: ");
ppo.AllowArbitraryInput = false;
PromptPointResult ppr = ed.GetPoint(ppo);
if (ppr.Status != PromptStatus.OK)
return;
Point3d point = ppr.Value;
using (Transaction Tx = db.TransactionManager.StartTransaction())
{
Solid3d solid = Tx.GetObject(per.ObjectId, OpenMode.ForRead)
as Solid3d;
ObjectId[] ids = new ObjectId[] { per.ObjectId };
FullSubentityPath path = new FullSubentityPath(
ids, new SubentityId(SubentityType.Null, IntPtr.Zero));
using (Brep brep = new Brep(path))
{
foreach (Autodesk.AutoCAD.BoundaryRepresentation.Face face in
brep.Faces)
{
PointContainment ptContainment = new PointContainment();
using (BrepEntity brepEnt = face.GetPointContainment(
point,
out ptContainment))
{
if (ptContainment == PointContainment.Inside ||
ptContainment == PointContainment.OnBoundary)
{
ed.WriteMessage("\nFace Normal at " +
PointToStr(point) + " = " +
VectToStr(GetFaceNormal(face, point)));
}
}
}
}
Tx.Commit();
}
}
// Small utility methods
private string VectToStr(Vector3d v)
{
return "[" +

0; v.X.ToString("F2") + ", " +
v.Y.ToString("F2") + ", " +
v.Z.ToString("F2")
+ "]";
}
Vector3d GetFaceNormal(
Autodesk.AutoCAD.BoundaryRepresentation.Face face,
Point3d point)
{
PointOnSurface ptOnSurf = face.Surface.GetClosestPointTo(point);
Point2d param = ptOnSurf.Parameter;
Vector3d normal = ptOnSurf.GetNormal(param);
// It seems we cannot trust the
// face.Surface.IsNormalReversed property,
// so I am applying a small offset to the point on surface
// and check if the offset point is inside the solid
// in case it is inside (or on boundary),
// the normal must be reversed
Vector3d normalTest = normal.MultiplyBy(1E-6 / normal.Length);
Point3d ptTest = point.Add(normalTest);
PointContainment ptContainment = new PointContainment();
bool reverse = false;
using(BrepEntity brepEnt =
face.Brep.GetPointContainment(
ptTest,
out ptContainment))
{
if(ptContainment != PointContainment.Outside)
{
reverse = true;
}
}
return normal.MultiplyBy(reverse ? -1.0 : 1.0);
}
<
p style=”line-height: normal;margin: 0in 0in 0pt” class=”MsoNormal”>

Leave a Reply to Philippe LeefsmaCancel reply