Fix Orientation

I searched through the forums and couldn't find a good solution to this. I am using Patrik Müller's code from this thread: http://www.opencascade.org/org/forum/thread_3145/ as was suggested by PG in an earlier thread to read in an .stl file. Once the .stl file is read in however, the shape is incorrectly oriented. Some of the faces' normals face inward, some face outward.

I have been messing with ShapeFix_Shape and some of those functions to try and repair the orientation of my TopoDS_Compound but I can't seem to get it fixed.

Can anyone tell me how I can repair the orientation of the faces of a TopoDS_Compound or TopoDS_Shape?

I've attached Patrik Müller's code at the end of this message for eash of troubleshooting. I've encapsulated it as a function for use in my program, so a few lines are different.

Thank you,
Mike

----------------------------------------------------------------------
TopoDS_Shape
importedFile(string FileName)
{
OSD_Path aFile((char*)FileName.c_str());
Standard_Boolean ReturnValue = Standard_True;

Handle(StlMesh_Mesh) aSTLMesh = RWStl::ReadFile(aFile);

TopoDS_Compound ResultShape;
BRep_Builder CompoundBuilder;
CompoundBuilder.MakeCompound(ResultShape);

Standard_Integer NumberDomains = aSTLMesh->NbDomains();
Standard_Integer iND;
gp_XYZ p1, p2, p3;
TopoDS_Vertex Vertex1, Vertex2, Vertex3;
TopoDS_Face AktFace;
TopoDS_Wire AktWire;
BRep_Builder B;
Standard_Real x1, y1, z1;
Standard_Real x2, y2, z2;
Standard_Real x3, y3, z3;

StlMesh_MeshExplorer aMExp (aSTLMesh);

// BRepBuilderAPI_MakeWire WireCollector;
for (iND=1;iND {
for (aMExp.InitTriangle (iND); aMExp.MoreTriangle (); aMExp.NextTriangle ())
{
aMExp.TriangleVertices (x1,y1,z1,x2,y2,z2,x3,y3,z3);
p1.SetCoord(x1,y1,z1);
p2.SetCoord(x2,y2,z2);
p3.SetCoord(x3,y3,z3);

if ((!(p1.IsEqual(p2,0.0))) && (!(p1.IsEqual(p3,0.0))))
{
Vertex1 = BRepBuilderAPI_MakeVertex(p1);
Vertex2 = BRepBuilderAPI_MakeVertex(p2);
Vertex3 = BRepBuilderAPI_MakeVertex(p3);

AktWire = BRepBuilderAPI_MakePolygon( Vertex1, Vertex2, Vertex3, Standard_True);

if( !AktWire.IsNull())
{
AktFace = BRepBuilderAPI_MakeFace( AktWire);
if(!AktFace.IsNull())
CompoundBuilder.Add(ResultShape,AktFace);
}
}
}
}

ShapeFix_Shape FixShape;
FixShape.Init(ResultShape);
FixShape.Perform();
TopoDS_Shape newshape = FixShape.Shape();

return ResultShape;
}

----------------------------------------------------------------------

Stephane Routelous's picture

you should return newshape and not ResultShape.

Stephane

Michael Cook's picture

I fixed that right after I pressed the post button, my mistake.

But it still isn't working. The shape is still incorrectly oriented after running this.

Any other ideas? I am trying to convert the TopoDS_Compound to a TopoDS_Shell, then use the FixFaceOrientation() method, and then convert the TopoDS_Shell back to a TopoDS_Shape.

Is this possible? How can I convert from compound to shell, and then from shell to shape?

Mike

Stephane Routelous's picture

to make the shell, you can use BRepBuilder::MakeShell and add the faces.

you can also try BrepOffsetAPI_Sewing

HTH,

Stephane
http://www.exotk.org

Michael Cook's picture

I've been looking in the documentation and I don't see a MakeShell member function for BRepBuilder. The only available functions appear to be: Add, MakeCompound, MakeCompSolid, Remove, MakeEdge, MakeFace, MakeVertex, UpdateEdge, UpdateFace, UpdateVertex.

Also is there any way you could provide a more specific example of what you mean when you say use BRepBuilder::MakeShell and add the faces? I really don't know where to begin. Are there some samples you could point me toward? How much code/how long should it take me to get that done?

I have to go to work at 3pm until 8pm, but hopefully I'll be able to work on this stuff while I'm at work.

To everyone:
If anyone has already written an STL loader to load an STL file into a TopoDS_Shape I would greatly appreciate it if I could use it. I'm between sharp rocks and a lot of hard places right now, just a lot of due dates flying around plus im moving out of my apartment into a house. :-/

Michael Cook's picture

Stephane,

Thank you soooo much for all of your help. Once I used the BRepOffsetAPI_Sewing functionality it all worked, I then just have to Reverse the surface as it seems to be sewing them inside out. I appreciate your help more than you will ever know. But I am late to work so I need to go. Thanks!

I've attached the FINISHED function at the end of this reply. It should import an stl file located at 'FileName' and return its equivalent TopoDS_Shape.

Thanks to Stephane Routelous, PG, and Patrik Müller for making this happen.

----------------------------------------------------------------------
TopoDS_Shape
importedFile(string FileName)
{
OSD_Path aFile((char*)FileName.c_str());
Standard_Boolean ReturnValue = Standard_True;

Handle(StlMesh_Mesh) aSTLMesh = RWStl::ReadFile(aFile);

TopoDS_Shell ResultShell;
BRep_Builder ShellBuilder;
ShellBuilder.MakeShell(ResultShell);

Standard_Integer NumberDomains = aSTLMesh->NbDomains();
Standard_Integer iND;
gp_XYZ p1, p2, p3;
TopoDS_Vertex Vertex1, Vertex2, Vertex3;
TopoDS_Face AktFace;
TopoDS_Wire AktWire;
BRep_Builder B;
Standard_Real x1, y1, z1;
Standard_Real x2, y2, z2;
Standard_Real x3, y3, z3;

StlMesh_MeshExplorer aMExp (aSTLMesh);

// BRepBuilderAPI_MakeWire WireCollector;
for (iND=1;iND<=NumberDomains;iND++)
{
for (aMExp.InitTriangle (iND); aMExp.MoreTriangle (); aMExp.NextTriangle ())
{
aMExp.TriangleVertices (x1,y1,z1,x2,y2,z2,x3,y3,z3);
p1.SetCoord(x1,y1,z1);
p2.SetCoord(x2,y2,z2);
p3.SetCoord(x3,y3,z3);

if ((!(p1.IsEqual(p2,0.0))) && (!(p1.IsEqual(p3,0.0))))
{
Vertex1 = BRepBuilderAPI_MakeVertex(p1);
Vertex2 = BRepBuilderAPI_MakeVertex(p2);
Vertex3 = BRepBuilderAPI_MakeVertex(p3);

AktWire = BRepBuilderAPI_MakePolygon( Vertex1, Vertex2, Vertex3, Standard_True);

if( !AktWire.IsNull())
{
AktFace = BRepBuilderAPI_MakeFace( AktWire);
if(!AktFace.IsNull())
ShellBuilder.Add(ResultShell,AktFace);
}
}
}
}

BRepOffsetAPI_Sewing sew;
sew.Add(ResultShell);
sew.Perform();
TopoDS_Shape newshape = sew.SewedShape();

newshape.Reverse();

return newshape;
}
----------------------------------------------------------------------

Michael Cook's picture

I spoke just a wee bit too soon. For some reason I can't take the union of one of the stl files that I imported and a (BRepPrimAPI_MakeBox) box.

When I try and take the union it fails with the BRepAlgoAPI_BooleanOperation::ErrorStatus() of value 110. I looked in the documentation and it states that: If the error is more than 100 - The error is during second part of the operation.

The second part of the operation is aparently building the result of the operation after the interference has already been calculated.

There doesn't appear to be anything else in the documentation that says anything about why it would error in this second part of the operation. Do you know what might be happening?

PG's picture

Hi

Is it possible to reduce the no.of faces of the final shape created
from stlmesh data/sewing.
What I mean is that the shape becomes "heavy" on memory , I want to reduce the faces/edges on the final shape after sewing operation and still retain the topology of the object.

regards
- PG

Michael Cook's picture

PG

I don't know of any means of doing this personally. None of the work that I have done with OpenCASCADE has required that meshes be simplified. This doesn't mean that the functionality doesn't exist, but you may want to post a new topic so that more people have a better chance of seeing your question. Sorry I couldn't help,

Mike