1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
15 #include <Bnd_Box.hxx>
16 #include <BRepBndLib.hxx>
17 #include <OSD_Path.hxx>
18 #include <OSD_OpenFile.hxx>
20 #include <StlAPI_Writer.hxx>
21 #include <StlMesh_Mesh.hxx>
22 #include <StlTransfer.hxx>
23 #include <BRep_Tool.hxx>
25 #include <TopoDS_Face.hxx>
26 #include <TopExp_Explorer.hxx>
27 #include <Poly_Triangulation.hxx>
29 StlAPI_Writer::StlAPI_Writer()
31 theStlMesh = new StlMesh_Mesh;
32 theASCIIMode = Standard_True;
35 Standard_Boolean& StlAPI_Writer::ASCIIMode()
43 // Tool to get triangles from triangulation taking into account face
44 // orientation and location
45 class TriangleAccessor
48 TriangleAccessor (const TopoDS_Face& aFace)
51 myPoly = BRep_Tool::Triangulation (aFace, aLoc);
52 myTrsf = aLoc.Transformation();
53 myNbTriangles = (myPoly.IsNull() ? 0 : myPoly->Triangles().Length());
54 myInvert = (aFace.Orientation() == TopAbs_REVERSED);
55 if (myTrsf.IsNegative())
56 myInvert = ! myInvert;
59 int NbTriangles () const { return myNbTriangles; }
61 // get i-th triangle and outward normal
62 void GetTriangle (int iTri, gp_Vec &theNormal, gp_Pnt &thePnt1, gp_Pnt &thePnt2, gp_Pnt &thePnt3)
64 // get positions of nodes
65 int iNode1, iNode2, iNode3;
66 myPoly->Triangles()(iTri).Get (iNode1, iNode2, iNode3);
67 thePnt1 = myPoly->Nodes()(iNode1);
68 thePnt2 = myPoly->Nodes()(myInvert ? iNode3 : iNode2);
69 thePnt3 = myPoly->Nodes()(myInvert ? iNode2 : iNode3);
71 // apply transormation if not identity
72 if (myTrsf.Form() != gp_Identity)
74 thePnt1.Transform (myTrsf);
75 thePnt2.Transform (myTrsf);
76 thePnt3.Transform (myTrsf);
80 theNormal = (thePnt2.XYZ() - thePnt1.XYZ()) ^ (thePnt3.XYZ() - thePnt1.XYZ());
81 Standard_Real aNorm = theNormal.Magnitude();
82 if (aNorm > gp::Resolution())
87 Handle(Poly_Triangulation) myPoly;
93 // convert to float and, on big-endian platform, to little-endian representation
94 inline float convertFloat (Standard_Real aValue)
96 #ifdef OCCT_BINARY_FILE_DO_INVERSE
97 return OSD_BinaryFile::InverseShortReal ((float)aValue);
104 StlAPI_ErrorStatus StlAPI_Writer::Write(const TopoDS_Shape& theShape, const Standard_CString theFileName)
107 FILE* aFile = OSD_OpenFile (theFileName, "wb");
109 return StlAPI_CannotOpenFile;
115 Fprintf (aFile, "solid shape, STL ascii file, created with Open CASCADE Technology\n");
118 for (TopExp_Explorer exp (theShape, TopAbs_FACE); exp.More(); exp.Next())
120 TriangleAccessor aTool (TopoDS::Face (exp.Current()));
121 for (int iTri = 1; iTri <= aTool.NbTriangles(); iTri++)
124 gp_Pnt aPnt1, aPnt2, aPnt3;
125 aTool.GetTriangle (iTri, aNorm, aPnt1, aPnt2, aPnt3);
128 " facet normal %12e %12e %12e\n"
130 " vertex %12e %12e %12e\n"
131 " vertex %12e %12e %12e\n"
132 " vertex %12e %12e %12e\n"
135 aNorm.X(), aNorm.Y(), aNorm.Z(),
136 aPnt1.X(), aPnt1.Y(), aPnt1.Z(),
137 aPnt2.X(), aPnt2.Y(), aPnt2.Z(),
138 aPnt3.X(), aPnt3.Y(), aPnt3.Z());
143 Fprintf (aFile, "endsolid shape\n");
147 // header block (meaningless 80 bytes)
148 Fprintf (aFile, "%-80.80s", "STL binary file, created with Open CASCADE Technology");
152 for (TopExp_Explorer exp (theShape, TopAbs_FACE); exp.More(); exp.Next())
154 TopLoc_Location aLoc;
155 Handle(Poly_Triangulation) aPoly =
156 BRep_Tool::Triangulation (TopoDS::Face (exp.Current()), aLoc);
157 if (! aPoly.IsNull())
158 aNbTri += aPoly->NbTriangles();
160 // suppose that number of triangles must be little endian...
161 #ifdef OCCT_BINARY_FILE_DO_INVERSE
162 aNbTri = OSD_BinaryFile::InverseInteger (aNbTri);
164 fwrite (&aNbTri, sizeof(int32_t), 1, aFile);
175 for (TopExp_Explorer exp (theShape, TopAbs_FACE); exp.More(); exp.Next())
177 TriangleAccessor aTool (TopoDS::Face (exp.Current()));
178 for (int iTri = 1; iTri <= aTool.NbTriangles(); iTri++)
181 gp_Pnt aPnt1, aPnt2, aPnt3;
182 aTool.GetTriangle (iTri, aNorm, aPnt1, aPnt2, aPnt3);
184 f.nx = convertFloat (aNorm.X());
185 f.ny = convertFloat (aNorm.Y());
186 f.nz = convertFloat (aNorm.Z());
188 f.x1 = convertFloat (aPnt1.X());
189 f.y1 = convertFloat (aPnt1.Y());
190 f.z1 = convertFloat (aPnt1.Z());
192 f.x2 = convertFloat (aPnt2.X());
193 f.y2 = convertFloat (aPnt2.Y());
194 f.z2 = convertFloat (aPnt2.Z());
196 f.x3 = convertFloat (aPnt3.X());
197 f.y3 = convertFloat (aPnt3.Y());
198 f.z3 = convertFloat (aPnt3.Z());
200 fwrite (&f, 50 /* 50 bytes per facet */, 1, aFile);
206 return ferror(aFile) ? StlAPI_WriteError : StlAPI_StatusOK;