Normals to Outside

Hi All,

I'd like to know if there's a way to set all faces of a shell to outside. E.g. all faces, of a cube without "cover", turned to outside. Is it possible? if yes, how can I get it?

Thanks in Advance.
Regards,

Paul Jimenez's picture

I'm also interested in the solution to that one. Right now I have an algorithm that extrudes a face (Prism does that already, but I have my reasons to reinvent the wheel here), and it is able to calculate the normals for all faces in such a way that they all point outwards. However, receiving a shell and re-calculating the normals so they all point outwards is something I've been unable to deduce yet. Hopefully, I won't need it, but I still would like to know the magic behind that. Maybe, just maybe, you could try fixing your shape with ShapeFix_Shell. I'm not sure if it takes care of making all normals point outwards, or just fixing orientation of adjacent faces (which may produce normals pointing all outwards or all inwards).

Knowing at which side of the edges of a wire is the face is another nice one, but it must be buried somewhere in OCC's code. After all, it always creates the face at the right side (as long as the wire is correct).

Once again, try ShapeFix_Shell.

tmacedo29's picture

Hi Paul Jimenez,

I already tried. But I had no success.
Maybe I used in a wrong way.

Regards,

Roman Lygin's picture

OCC has a notion of orientation that defines how *real* direction of a shape coincides with geometrical orientation. See TopoDS_Shape::Orientation() and documentation.

If TopoDS_Face has forward orientation (TopAbs_FORWARD) then its normal matches its underlying surface's normal, otherwise it is considered to be the opposite. Your algorithm should take orientations into account to achieve what you expect it to.
You can change orientation of the parent shape (e.g. shell or solid or compound) your face is part of. Then explorer TopExp_Explorer or TopoDS_Iterator (the latter with a proper flag CumOrientation) will explore taking into account parent's orientation.

Try this in DRAW:

Draw> pload ALL
Draw> box b 1 1 1 #this creates a box with edge of length 1
Draw> whatis b
b is a shape SOLID FORWARD Free Modified
Draw> normals b #will display normals to the surfaces with colors of the face orientation
Draw> vprops b #display volumic properties
Mass : 1

Center of gravity :
X = 0.5
Y = 0.5
Z = 0.5

Matrix of Inertia :
0.166667 -8.32667e-017 -8.32667e-017
-8.32667e-017 0.166667 -5.55112e-017
-8.32667e-017 -5.55112e-017 0.166667

Moments :
IX = 0.166667
IY = 0.166667
IZ = 0.166667

Draw> orientation b R #assigns Reversed orientation
Draw> what is b
b is a shape SOLID REVERSED Free Modified
Draw> normals b #normals will be in opposite colors
Draw> vprops b #data (except COG has opposite values)

Mass : -1

Center of gravity :
X = 0.5
Y = 0.5
Z = 0.5

Matrix of Inertia :
-0.166667 8.32667e-017 8.32667e-017
8.32667e-017 -0.166667 5.55112e-017
8.32667e-017 5.55112e-017 -0.166667

Moments :
IX = -0.166667
IY = -0.166667
IZ = -0.166667

Hope this helps.
Roman

tmacedo29's picture

Hi,

I'm trying to change just the normal from one face. I already tried to change the Orientation but it seems that I had no success with the normal.

Could someone help me, please?

Thank in Advance.
Regards,

Paul Jimenez's picture

The normal of a face is:

* The normal of its surface if the orientation of the face is FORWARD
* The reversed normal of its surface if the orientation of the face is REVERSED

That means that reversing a face won't change the normal of its surface.

Ling's picture

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

if use TopoDS_Iterator, how to modify this code ,,,i want to get the face(TopoDS_Face) from shap(TopoDS_Shape)

Thanks very much

Hennig's picture

you have to use it in a similar way:

TopoDS_Iterator it(shape);
for (; it.More(); it.Next())
{
const TopoDS_Face& aFace = TopoDS::Face(it.Value());
// do something with aFace
}

Ling's picture

Hello! Hennig
there is another question, I hope you can help me, Thanks!

The question is:
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;

}

}

Ling's picture

There is something wrong with this code:

This code is flow:

TopoDS_Shape shape = Reader.OneShape();
TopoDS_Iterator it(shape);
for(; it.More(); it.Next())
{
const TopoDS_Face& face = TopoDS::Face(it.Value());
// do something else

}
when debug , there is something wrong . look the file of jpg.

Paul Jimenez's picture

I just considered the original question, and designed an algorithm that does that. I'm using it right now, and it seems to work quite nicely. However, the algorithm is restricted to the kind of shapes I use, which simplifies it.

The restriction is that the whole shell must have a top and/or bottom faces with normal parallel to Z, and all other faces must be reachable by the edges of these faces.

The idea is as follows:

* Find the highest value of Z from all the vertices in all faces.
* Check the normal of every face. If it's parallel to ZDir and the Z of any of its vertices is at the highest Z value, then it's a top face. If it's parallel to ZDir and the Z of any of its vertices is NOT at the highest Z value, then it's a bottom face.
* All top faces' normals must be equal to ZDir (reverse face if NOT)
* All bottom faces' normals must be equal to -ZDir (reverse face if NOT)
* For each top and bottom face
** For each edge of the face
*** Find the other face connected by this edge and the orientation of the same edge in it
*** If the face was already checked, use the resulting face instead
*** If the orientation of both same edges is opposite, then it's OK
*** Else (the orientation is the same)
**** If the face was not checked before, then reverse it
**** Else, something's wrong with the shell
*** Add the face (which could have been reversed) to a list/map of checked faces

Build a new shell, or rebuild the original one, with those checked faces and voilà.

The idea can be extended even further. Consider this:

You take any face of the shell. You find a rotation that will make the face's normal to point in the Z direction. The transformation must be applied to the whole shape. Find the highest and lowest Z value for the whole transformed shape. If the face you chose, after transformation, has its Z values at the highest Z you found, then it's a top face. If its Z values are at the lowest Z you found, then it's a bottom face. If it's somewhere else, pick another face and try again. Once you have a face that you are sure is a top or bottom face, proceed like in the previous algorithm. Every new face that you check and fix becomes a new face to iterate over its edges and find more faces to fix from it. Being all faces of the shell sewed, you should end up with the right orientation for all faces.

I hope that information gives you some insights in how to do some things yourself.