face normal direction

Could someone give my some hints about the followings pls?

Suppose a TopoDS_Shape aShape and aFace is one of its face. How to decide whether the normal direction of aFace is pointed inside of aShape?

Actually, aShape is a closed model built from a list faces as follows:

TopoDS_Shell aShell;
BRep_Builder aBuilder;
aBuilder.MakeShell(aShell);

Then could someone tell me how to set aShell as a valid model so that the normal directions of its faces are all pointed outside its interior?

Many thanks.

Ming's picture

The code on the construction of aShell.

TopTools_IndexedMapOfShape& aMap;
for(int i=1;i<=aMap.Extent();i++)
{
TopoDS_Shape aShape=aMap(i);
if(aShape.ShapeType()==TopAbs_FACE)
{
TopoDS_Face F=TopoDS::Face(aShape);
aBuilder.Add( aShell, F);
}
}

Any suggestions are highly appreciated. :)

jacobStoren's picture

Did you find the answear on how to "fix" the surface normals ?
I seem to have the same problem when reading an IGES or STEP file. The surface normals of the triangles produced by BRepMesh_IncrementalMesh MESH() is not "correct". Some faces have normal inwards, while others have it outwars.

Jacob

Ming_39674's picture

Sigh... I haven't got the answer till now. Hope someone might give some suggestions.

jacobStoren's picture

Did you find the answear on how to "fix" the surface normals ?
I seem to have the same problem when reading an IGES or STEP file. The surface normals of the triangles produced by BRepMesh_IncrementalMesh MESH() is not "correct". Some faces have normal inwards, while others have it outwars.

Jacob

Rob Bachrach's picture

If you use ShapeFix_Shell, you should be able to force all normals to the same direction (inward or outward). Granted, in many cases, this simply changes the Orientation flag on the face. When I interpret the results of BRepMesh, I get the triangle vertices in reverse order when the face is not oriented FORWARD. This has worked very well for me.

As for the normals pointing outward or inward, you can always draw a ray along the normal (and starting slightly behind the face) and see how many intersections you get. There may be a better way, but that's all I came up with at the moment.

Ling's picture

Dear Rob Bachrach
i am a student. i have a task to make IGES to STl , and have the same problem that some face's normal is reversed.
can you give me a example that how to Fix the normal .

Thanks

Ling's picture

This is the code :

Standard_Real aDeflection;
// aDeflection = ... ;

TopoDS_Shape aShape

// removes all the triangulations of the faces ,
//and all the polygons on the triangulations of the edges:
BRepTools::Clean(aShape);

// adds a triangulation of the shape aShape with the deflection aDeflection:
BRepMesh::Mesh(aShape,aDeflection);

TopExp_Explorer aExpFace,aExpEdge;
for(aExpFace.Init(aShape,TopAbs_FACE);aExpFace.More();aExpFace.Next())
{
TopoDS_Face aFace = TopoDS::Face(aExpFace.Current());
TopLoc_Location aLocation;

// takes the triangulation of the face aFace:
Handle_Poly_Triangulation aTr = BRep_Tool::Triangulation(aFace,aLocation);

if(!aTr.IsNull()) // if this triangulation is not NULL
{
// takes the array of nodes for this triangulation:
const TColgp_Array1OfPnt& aNodes = aTr->Nodes();
// takes the array of triangles for this triangulation:
const Poly_Array1OfTriangle& triangles = aTr->Triangles();

// create array of node points in absolute coordinate system
TColgp_Array1OfPnt aPoints(1, aNodes.Length());
for( Standard_Integer i = 1; i < aNodes.Length()+1; i++)
aPoints(i) = aNodes(i).Transformed(aLocation);

// Takes the node points of each triangle of this triangulation.
// takes a number of triangles:
Standard_Integer nnn = aTr->NbTriangles();
Standard_Integer nt,n1,n2,n3;
for( nt = 1 ; nt < nnn+1 ; nt++)
{
if(aFace.Orientation() == TopAbs_REVERSED)
{
// takes the node indices of each triangle in n1,n2,n3:
triangles(nt).Get(n1,n2,n3);
// takes the node points:
gp_Pnt aPnt1 = aPoints(n1);
gp_Pnt aPnt2 = aPoints(n2);
gp_Pnt aPnt3 = aPoints(n3);
}
else
{
// takes the node indices of each triangle in n1,n2,n3:
triangles(nt).Get(n1,n3,n2);
// takes the node points:
gp_Pnt aPnt1 = aPoints(n1);
gp_Pnt aPnt2 = aPoints(n3);
gp_Pnt aPnt3 = aPoints(n2);
}

}

// Takes the polygon associated to an edge.
aExpEdge.Init(aFace,TopAbs_EDGE);
TopoDS_Edge aEdge;
// for example,working with the first edge:
if(aExpEdge.More())
aEdge = TopoDS::Edge(aExpEdge.Current());

if(!aEdge.IsNull()) // if this edge is not NULL
{
// takes the polygon associated to the edge aEdge:
Handle_Poly_PolygonOnTriangulation aPol =
BRep_Tool::PolygonOnTriangulation(aEdge,aTr,aEdge.Location());

if(!aPol.IsNull()) // if this polygon is not NULL
// takes the array of nodes for this polygon
// (indexes in the array of nodes for triangulation of theFace):
const TColStd_Array1OfInteger& aNodesOfPol = aPol->Nodes();
}
}
}

The question is there: when read the iges file, the aFace.Orientation() is always TopAbs_FORWARD,
it make the normal wrong.

but when read step file , it's face normal is right

if(aFace.Orientation() == TopAbs_REVERSED)
{
// takes the node indices of each triangle in n1,n2,n3:
triangles(nt).Get(n1,n2,n3);
// takes the node points:
gp_Pnt aPnt1 = aPoints(n1);
gp_Pnt aPnt2 = aPoints(n2);
gp_Pnt aPnt3 = aPoints(n3);
}
else
{
// takes the node indices of each triangle in n1,n2,n3:
triangles(nt).Get(n1,n3,n2);
// takes the node points:
gp_Pnt aPnt1 = aPoints(n1);
gp_Pnt aPnt2 = aPoints(n3);
gp_Pnt aPnt3 = aPoints(n2);
}

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();
shape.Modified();
//shape.Checked();
double const deflection = 0.5;
double const angulardeflection = 0.5;
BRepTools::Clean(shape);
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)
{
triangles(j).Get(v1,v3,v2);
mesh.add_face( OpenMesh::VertexHandle(index+v1-1), OpenMesh::VertexHandle(index+v2-1), OpenMesh::VertexHandle(index+v3-1));
}
else
{
triangles(j).Get(v1,v2,v3);
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();
else
{
// 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;

}

}