Set normal of surface or face

Hello,

i'm facing some problems with the normals of my shape.
I have a cube with a cylindric hole on one side. I'm using the following code to get the normal of the surface
of a face:

Standard_Real uMin, uMax, vMin, vMax;
BRepTools::UVBounds (face, uMin, uMax, vMin, vMax);
Handle(Geom_Surface) surface = BRep_Tool::Surface(face);

GeomLProp_SLProps props (surface, uMin, vMin, 1, 0.001);
gp_Dir normal = props.Normal();

if (face.Orientation() == TopAbs_REVERSED)
{
normal.Reverse();
}

Every face has the orientation \"TopAbs_FORWARD\". But some of the normals are outward directed and some are
inward directed (see attached graphic). The highlighted faces all belong to the mantle of the cylindric hole, so all normals should be inward directed towards the axis of the cylinder.

I\'ve read this tutorial http://opencascade.blogspot.de/2009/02/continued.html but i don\'t really know what to do
to solve my problem. Should i use a different way to get the normal of a face of the mantle or is something
wrong with my shape?

For my written algorithm it\'s important that every normal of the mantle of the cylindric hole is inward directed towards the axis of the cylinder.

Possible solution:
I have all the correct normals in a stl file which i can access with the following code (shortened):

Standard_Real Xn, Yn, Zn;
StlMesh_MeshExplorer meshExplorer (stlMesh);
meshExplorer.TriangleOrientation(Xn, Yn, Zn);

Is there a way to set the normal of a surface or face? Or create a new face/surface with a specific normal (the one from the file)?

Thank you very much
Sven

Attachments: 
Alexander Luger's picture

To fix the orientation of all faces of a shell, use the class ShapeFix_Shell.

Regards,
Alex

skmCry's picture

Thanks for the replay. But ShapeFix_Shell doesn't seem to change something.
The result is still the same as seen in the attached picture of my start post.

AP's picture

Sven,

try this and let me know if it works.

const gp_Vec& getVectorNormaltoSurfaceatPoint(TopoDS_Shape SupportSurface, gp_Pnt point)
{

gp_Pnt projp = ProjectPoint(point,SupportSurface);
const TopoDS_Face& aFace = TopoDS::Face (SupportSurface);
// Get 2d UV data
gp_Pnt2d pUV = Get2dPntonSurfacefromPoint(SupportSurface,projp);

BRepAdaptor_Surface aSurface(aFace);
gp_Vec ut,vt;
gp_Pnt pt;
aSurface.D1(pUV.X(),pUV.Y(),pt,ut,vt);
gp_Vec V = ut.Crossed(vt);

Standard_Real mod = V.Magnitude();
if (mod < Precision::Confusion()) qDebug() << "Vector has no Magnitude" ;
// consider the face orientation
if (aFace.Orientation() == TopAbs_REVERSED ||
aFace.Orientation() == TopAbs_INTERNAL) {
V = -V;
}

return V;

}

const gp_Pnt& ProjectPoint(gp_Pnt p1 , TopoDS_Shape Surface)
{
gp_Pnt resultpoint;
if(Surface.ShapeType() != TopAbs_ShapeEnum::TopAbs_FACE)
{
return resultpoint;
}
TopoDS_Face aFace = TopoDS::Face(Surface);

Handle_Geom_Surface aSurf = BRep_Tool::Surface(aFace);
GeomAPI_ProjectPointOnSurf Proj (p1, aSurf);
if (Proj.NbPoints() > 0)
{
resultpoint = Proj.NearestPoint();
}

return resultpoint;

}

const gp_Pnt2d& Get2dPntonSurfacefromPoint(TopoDS_Shape SupportSurface, gp_Pnt point)
{

const TopoDS_Face& aFace = TopoDS::Face (SupportSurface);
Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);

Standard_Real u1, u2, v1, v2;
BRepTools::UVBounds(TopoDS::Face(aFace),u1,u2,v1,v2);

Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
gp_Pnt2d pUV = aSurfAna->ValueOfUV(point, Precision::Confusion());

double newx = map(pUV.X(),u1,u2,0,1);
double newy = map(pUV.Y(),v1,v2,0,1);
pUV.SetX(newx);
pUV.SetY(newy);
return pUV;

}

double map(double value, double low, double high, double tlow, double thigh)
{
double mapped = (((value - low) / (high - low)) * (thigh - tlow)) + tlow;
return mapped;
}

skmCry's picture

Thank you very much for this great help! But i think something is wrong with my
shape, because when i'm using the above code every normal points in the same direction, but
now every normal is also parallel to its surface thats clearly wrong.

I think the best solution would be to set the normal manually for each face, because the
exact normal for each triangle is already stored in the stl file.

Thanks again.

AP's picture

Can you share your TopoDS_Shape as an Iges, I'll try to test on my side.

Regards,

Alex

skmCry's picture

I think i have a solution and know the reason for my problem:
My object comes from a stl mesh and i'm first converting it to a TopoDS_Shape. It seems
that the direction of the normal depends on the order i'm connecting the vertices of a triangle to a face.
During the conversion i'm storing the exact normal from the stl mesh in an extra data structure that i can access easily later now. So calculation of the normal of a face is not needed anymore.

Thanks again for your help Alex. :)

AP's picture

Hi Sven,

No worries, thanks for posting the result. Just to close this wanted to add quickly a note:

to add to your comments for future readers. Sven's input surface was made of a tessellated or polyhedral geometry. So in theory, Sven's input data was not a surface, but rather a collection of triangles or other nth dimensional polygons. The problem you were facing was more of a mesh-based problem, there are other opensource libraries like CGAL(https://www.cgal.org/) and openMesh(http://www.openmesh.org/) that are more specifically used to process meshes and make useful operations on them. While opencascade has polygonal classes, it is best applied towards problems which require dealing with continuous surfaces made of Nurbs or BREP representations which can more accurately describe manufactured objects. tessellations in opencascade are used in two ways, one to take a continuous surface and discritize it for displaying it into a 3d viewport, since to this date graphic libraries like openGL are based on triangles, even though it can evaluate nurbs natively, its best to discretize the objects into triangles which are then rasterized into pixels by the library. The second use, is in converting the continuous surfaces or solids into Finite Element Analysis meshes which can be two dimensional (a face), three dimensional (a shell) or volumetric(space filling polyhedra) since to this date most of the FEA software is still based on this basic representations. The mesh based systems which you see in software's like 3dsmax, blender, maya that are more graphics oriented, are not the stronghold of these systems. opencascade does not produce FEA meshes natively, you need SALOME to produce FEA meshes from TopoDS_Shape geometries, it comes with a netgen plugin which generates FEA meshes.

Regards,

Alex