1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-04 13:13:25 +03:00

0026338: STL export (especially binary) needs a lot of time if selected export path is not local

Method StlAPI_Writer::Write() is reimplemented to write triangulation directly, without conversion to StlMesh_Mesh.

New DRAW command "tessellate" is added to generate rapidly triangulation of prescribed size (on surface).

Command "tricheck" is protected to deal correctly with triangulation without UV data.

New tests added: perf de bug26338_1 and _2; bugs stlvrml bug26338

Correction of testing environment
This commit is contained in:
abv
2016-02-25 07:30:18 +03:00
committed by bugmaster
parent 6396eacb4f
commit b508cbc59f
8 changed files with 406 additions and 35 deletions

View File

@@ -23,7 +23,8 @@ enum StlAPI_ErrorStatus
{
StlAPI_StatusOK,
StlAPI_MeshIsEmpty,
StlAPI_CannotOpenFile
StlAPI_CannotOpenFile,
StlAPI_WriteError
};
#endif // _StlAPI_ErrorStatus_HeaderFile

View File

@@ -15,11 +15,16 @@
#include <Bnd_Box.hxx>
#include <BRepBndLib.hxx>
#include <OSD_Path.hxx>
#include <OSD_OpenFile.hxx>
#include <RWStl.hxx>
#include <StlAPI_Writer.hxx>
#include <StlMesh_Mesh.hxx>
#include <StlTransfer.hxx>
#include <TopoDS_Shape.hxx>
#include <BRep_Tool.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Face.hxx>
#include <TopExp_Explorer.hxx>
#include <Poly_Triangulation.hxx>
StlAPI_Writer::StlAPI_Writer()
{
@@ -32,26 +37,172 @@ Standard_Boolean& StlAPI_Writer::ASCIIMode()
return theASCIIMode;
}
StlAPI_ErrorStatus StlAPI_Writer::Write(const TopoDS_Shape& theShape, const Standard_CString theFileName)
// Auxiliary tools
namespace
{
OSD_Path aFile(theFileName);
StlTransfer::RetrieveMesh(theShape, theStlMesh);
if (theStlMesh.IsNull() || theStlMesh->IsEmpty())
return StlAPI_MeshIsEmpty;
// Write the built mesh
Standard_Boolean wasFileOpened = Standard_False;
if (theASCIIMode) {
wasFileOpened = RWStl::WriteAscii(theStlMesh, aFile);
}
else {
wasFileOpened = RWStl::WriteBinary(theStlMesh, aFile);
// Tool to get triangles from triangulation taking into account face
// orientation and location
class TriangleAccessor
{
public:
TriangleAccessor (const TopoDS_Face& aFace)
{
TopLoc_Location aLoc;
myPoly = BRep_Tool::Triangulation (aFace, aLoc);
myTrsf = aLoc.Transformation();
myNbTriangles = (myPoly.IsNull() ? 0 : myPoly->Triangles().Length());
myInvert = (aFace.Orientation() == TopAbs_REVERSED);
if (myTrsf.IsNegative())
myInvert = ! myInvert;
}
if (!wasFileOpened)
return StlAPI_CannotOpenFile;
int NbTriangles () const { return myNbTriangles; }
return StlAPI_StatusOK;
// get i-th triangle and outward normal
void GetTriangle (int iTri, gp_Vec &theNormal, gp_Pnt &thePnt1, gp_Pnt &thePnt2, gp_Pnt &thePnt3)
{
// get positions of nodes
int iNode1, iNode2, iNode3;
myPoly->Triangles()(iTri).Get (iNode1, iNode2, iNode3);
thePnt1 = myPoly->Nodes()(iNode1);
thePnt2 = myPoly->Nodes()(myInvert ? iNode3 : iNode2);
thePnt3 = myPoly->Nodes()(myInvert ? iNode2 : iNode3);
// apply transormation if not identity
if (myTrsf.Form() != gp_Identity)
{
thePnt1.Transform (myTrsf);
thePnt2.Transform (myTrsf);
thePnt3.Transform (myTrsf);
}
// calculate normal
theNormal = (thePnt2.XYZ() - thePnt1.XYZ()) ^ (thePnt3.XYZ() - thePnt1.XYZ());
Standard_Real aNorm = theNormal.Magnitude();
if (aNorm > gp::Resolution())
theNormal /= aNorm;
}
private:
Handle(Poly_Triangulation) myPoly;
gp_Trsf myTrsf;
int myNbTriangles;
bool myInvert;
};
// convert to float and, on big-endian platform, to little-endian representation
inline float convertFloat (Standard_Real aValue)
{
#ifdef OCCT_BINARY_FILE_DO_INVERSE
return OSD_BinaryFile::InverseShortReal ((float)aValue);
#else
return (float)aValue;
#endif
}
}
StlAPI_ErrorStatus StlAPI_Writer::Write(const TopoDS_Shape& theShape, const Standard_CString theFileName)
{
// open file
FILE* aFile = OSD_OpenFile (theFileName, "wb");
if (!aFile)
return StlAPI_CannotOpenFile;
// write
if (theASCIIMode)
{
// header
Fprintf (aFile, "solid shape, STL ascii file, created with Open CASCADE Technology\n");
// facets
for (TopExp_Explorer exp (theShape, TopAbs_FACE); exp.More(); exp.Next())
{
TriangleAccessor aTool (TopoDS::Face (exp.Current()));
for (int iTri = 1; iTri <= aTool.NbTriangles(); iTri++)
{
gp_Vec aNorm;
gp_Pnt aPnt1, aPnt2, aPnt3;
aTool.GetTriangle (iTri, aNorm, aPnt1, aPnt2, aPnt3);
Fprintf (aFile,
" facet normal %12e %12e %12e\n"
" outer loop\n"
" vertex %12e %12e %12e\n"
" vertex %12e %12e %12e\n"
" vertex %12e %12e %12e\n"
" endloop\n"
" endfacet\n",
aNorm.X(), aNorm.Y(), aNorm.Z(),
aPnt1.X(), aPnt1.Y(), aPnt1.Z(),
aPnt2.X(), aPnt2.Y(), aPnt2.Z(),
aPnt3.X(), aPnt3.Y(), aPnt3.Z());
}
}
// footer
Fprintf (aFile, "endsolid shape\n");
}
else
{
// header block (meaningless 80 bytes)
Fprintf (aFile, "%-80.80s", "STL binary file, created with Open CASCADE Technology");
// number of facets
int32_t aNbTri = 0;
for (TopExp_Explorer exp (theShape, TopAbs_FACE); exp.More(); exp.Next())
{
TopLoc_Location aLoc;
Handle(Poly_Triangulation) aPoly =
BRep_Tool::Triangulation (TopoDS::Face (exp.Current()), aLoc);
if (! aPoly.IsNull())
aNbTri += aPoly->NbTriangles();
}
// suppose that number of triangles must be little endian...
#ifdef OCCT_BINARY_FILE_DO_INVERSE
aNbTri = OSD_BinaryFile::InverseInteger (aNbTri);
#endif
fwrite (&aNbTri, sizeof(int32_t), 1, aFile);
// facets
struct Facet {
float nx, ny, nz;
float x1, y1, z1;
float x2, y2, z2;
float x3, y3, z3;
uint16_t dummy;
} f;
f.dummy = 0;
for (TopExp_Explorer exp (theShape, TopAbs_FACE); exp.More(); exp.Next())
{
TriangleAccessor aTool (TopoDS::Face (exp.Current()));
for (int iTri = 1; iTri <= aTool.NbTriangles(); iTri++)
{
gp_Vec aNorm;
gp_Pnt aPnt1, aPnt2, aPnt3;
aTool.GetTriangle (iTri, aNorm, aPnt1, aPnt2, aPnt3);
f.nx = convertFloat (aNorm.X());
f.ny = convertFloat (aNorm.Y());
f.nz = convertFloat (aNorm.Z());
f.x1 = convertFloat (aPnt1.X());
f.y1 = convertFloat (aPnt1.Y());
f.z1 = convertFloat (aPnt1.Z());
f.x2 = convertFloat (aPnt2.X());
f.y2 = convertFloat (aPnt2.Y());
f.z2 = convertFloat (aPnt2.Z());
f.x3 = convertFloat (aPnt3.X());
f.y3 = convertFloat (aPnt3.Y());
f.z3 = convertFloat (aPnt3.Z());
fwrite (&f, 50 /* 50 bytes per facet */, 1, aFile);
}
}
}
fclose (aFile);
return ferror(aFile) ? StlAPI_WriteError : StlAPI_StatusOK;
}