TopoDS_Face with REVERSED orientation

I'm writing some translation routines and I'm having difficulty interpreting the topology in those cases where a face has reversed orientation.

If we construct a very simple cylinder using BRepPrimAPI_MakeCylinder, the bottom face of the cylinder has REVERSED orientation. Does this mean the face or the surface normal points into the cylinder? If it's the surface normal, how does one find out the relationship between the surface and face normals?

In trying to find an example of how to deal with this case, I began reviewing the STEP interface code. The TopoDSToStep_MakeStepFace.cxx file has the following comment:

// CAS.CADE face orientation :
// when a face is reversed in a shell, the orientation of the underlying
// topology is implicitly reversed. This is not the case in Step.

Can someone please explain what this means? Also I noticed the face and wire TopoDS to STEP translation routines always orient the shapes in the FORWARD direction prior to exporting to STEP. Is this due a STEP requirement or to correct the implicit representation alluded to by the comment?

Thank you.

Roman Lygin's picture

There is some challenge with Face orientation in Open CASCADE, indeed !

Let's start with simple. Shape material is always on a side oposite to FACE(!) normal. I.e. for a ball, face normal should be outwards of the center.
If FACE orientation is FORWARD then its normal coincides with a surface normal. If REVERSED - then opposite to surface. For a vertical cylinder its bottom face has a plane with a normal along Z (i.e. inwards the cylinder). THat is why FACE has REVERSED orientation to have its normal to -Z.

Now to more complex :-). Unlike STEP format, in OCC you should ignore FACE orientation when exploring to lower level (wire, edges, vertices). I.e. you use TopExp_Explorer anExp (myFace.Oriented (TopAbs_FORWARD), TopAbs_EDGE) ...
This makes all geometry remain consistent - e.g. pcurves (2d curves in surface parametric space) use just edge orientation just like if edge would be stored from FORWARD face and in FORWARD wire.
Higher level shapes orientation is multiplied when exploring. So, if you took into account face's orientation when exploring then it would multiply with edge's. This is why an exception for faces was made to avoid reversing subshapes when changing face orientation.

So, the summary is - always use forward orientation when exploring a face. And face orientation is jsut used to understand where shape material is.

Hope this helps in some way.


blair_downie's picture


Thanks for the information!

I've got a related question.

I use the BRepLProp_SLProps class to retrieve face properties. However it seems that this class does not take into account the orientation of the face because my normal calculation for the cylinder's bottom face is along Z (matching the surface normal) In this case is it the application's responsiblity to reverse the result?


Rob Bachrach's picture

This is absolutely true. After all, this class takes a surface and has no information about the face it came from.

Ling's picture

hello , i am a student. and i have a task that iges/step to stl.

when iges to stl , i find that some face's normal is reversed, and the problem i think is flow:
face.Orientation() is always TopAbs_FORWARD,

but , when step to stl , it's fine. the face normal is right.
can you give me some advise ,,thank you very much.

this is my code:
TopoDS_Shape shape = Reader.OneShape();
double const deflection = 0.5;
double const angulardeflection = 0.5;
BRepMesh_IncrementalMesh discr(shape, deflection, false, angulardeflection); //shape or face

TopoDS_Face face;

for (TopExp_Explorer ex(shape, TopAbs_FACE); ex.More(); ex.Next())
TopoDS_Face face = TopoDS::Face(ex.Current());
TopLoc_Location loc;

BRepAdaptor_Surface sf(face, Standard_False);
BRepLProp_SLProps prop(sf, 1, 1e-5);

Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc);

//Handle(Poly_Triangulation) triangulation1 = BRepTools::Triangulation(face, 0.01);

if (!triangulation.IsNull())
gp_Pnt2d uv;
gp_Pnt pnt;
gp_Vec nn;

int ntriangles = triangulation -> NbTriangles();
int npoints = triangulation->NbNodes();

const TColgp_Array1OfPnt& aNodes = triangulation->Nodes();
int num = aNodes.Length();

TColgp_Array1OfPnt aPoints(1, aNodes.Length());
for( Standard_Integer i = 1; i < aNodes.Length()+1; i++)
aPoints(i) = aNodes(i).Transformed(loc);

mesh.add_vertex( TNOMS3D::OPoint( aPoints(i).X(), aPoints(i).Y(), aPoints(i).Z() ) );

const Poly_Array1OfTriangle& triangles =triangulation ->Triangles();

Standard_Integer v1,v2,v3;
for (int j = 1; j <= ntriangles; j++)
if (face.Orientation() == TopAbs_REVERSED)
mesh.add_face( OpenMesh::VertexHandle(index+v1-1), OpenMesh::VertexHandle(index+v2-1), OpenMesh::VertexHandle(index+v3-1));
mesh.add_face( OpenMesh::VertexHandle(index+v1-1), OpenMesh::VertexHandle(index+v2-1), OpenMesh::VertexHandle(index+v3-1));

//mesh.add_face( OpenMesh::VertexHandle(v1-1), OpenMesh::VertexHandle(v2-1), OpenMesh::VertexHandle(v3-1));

Poly_Triangle triangle = (triangulation -> Triangles())(j);
//gp_Vec nn[3];
for(int k=1; k<=3; k++)
uv = (triangulation -> UVNodes())(triangle(k));
prop.SetParameters (uv.X(), uv.Y());

if (prop.IsNormalDefined())
nn = prop.Normal();
// n = gp_Vec (0,0,0);
gp_Vec a(aPoints(v1),aPoints(v2));
gp_Vec b(aPoints(v1),aPoints(v3));
nn = b^a;
if (face.Orientation() == TopAbs_REVERSED) nn *= -1;

if( k==1 )
mesh.set_normal( OpenMesh::VertexHandle(index+v1-1),TNOMS3D::ONormal(nn.X(),nn.Y(),nn.Z()) );
if( k==2 )
mesh.set_normal( OpenMesh::VertexHandle(index+v2-1),TNOMS3D::ONormal(nn.X(),nn.Y(),nn.Z()) );
if( k==3 )
mesh.set_normal( OpenMesh::VertexHandle(index+v3-1),TNOMS3D::ONormal(nn.X(),nn.Y(),nn.Z()) );

index = index+npoints;



Anup's picture

Hi Ling,

Even i am trying a conversion of IGES to STL, Actually i am converting IGES to STL with all traingles in counter-clockwise order so tat i can visualize in coin3D.

CAn you please tell me how did you do it??

Thanks & Regards