0028840: Data Exchange - rewrite the STL Reader/Writer
[occt.git] / src / StlAPI / StlAPI_Writer.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
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.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <StlAPI_Writer.hxx>
15
16 #include <Bnd_Box.hxx>
17 #include <BRepBndLib.hxx>
18 #include <OSD_Path.hxx>
19 #include <OSD_OpenFile.hxx>
20 #include <RWStl.hxx>
21 #include <BRep_Tool.hxx>
22 #include <TopoDS.hxx>
23 #include <TopoDS_Face.hxx>
24 #include <TopExp_Explorer.hxx>
25 #include <Poly_Triangulation.hxx>
26
27 //=============================================================================
28 //function : StlAPI_Writer
29 //purpose  :
30 //=============================================================================
31 StlAPI_Writer::StlAPI_Writer()
32 : myASCIIMode (Standard_True)
33 {
34   //
35 }
36
37 //=============================================================================
38 //function : Write
39 //purpose  :
40 //=============================================================================
41 Standard_Boolean StlAPI_Writer::Write (const TopoDS_Shape&    theShape,
42                                        const Standard_CString theFileName)
43 {
44   Standard_Integer aNbNodes = 0;
45   Standard_Integer aNbTriangles = 0;
46
47   // calculate total number of the nodes and triangles
48   for (TopExp_Explorer anExpSF (theShape, TopAbs_FACE); anExpSF.More(); anExpSF.Next())
49   {
50     TopLoc_Location aLoc;
51     Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (TopoDS::Face (anExpSF.Current()), aLoc);
52     aNbNodes     += aTriangulation->NbNodes();
53     aNbTriangles += aTriangulation->NbTriangles();
54   }
55
56   // create temporary triangulation
57   Handle(Poly_Triangulation) aMesh = new Poly_Triangulation (aNbNodes, aNbTriangles, Standard_False);
58
59   // fill temporary triangulation
60   Standard_Integer aNodeOffset = 0;
61   Standard_Integer aTriangleOffet = 0;
62   for (TopExp_Explorer anExpSF (theShape, TopAbs_FACE); anExpSF.More(); anExpSF.Next())
63   {
64     TopLoc_Location aLoc;
65     Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (TopoDS::Face (anExpSF.Current()), aLoc);
66
67     const TColgp_Array1OfPnt& aNodes = aTriangulation->Nodes();
68     const Poly_Array1OfTriangle& aTriangles = aTriangulation->Triangles();
69
70     // copy nodes
71     gp_Trsf aTrsf = aLoc.Transformation();
72     for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
73     {
74       gp_Pnt aPnt = aNodes (aNodeIter);
75       aPnt.Transform (aTrsf);
76       aMesh->ChangeNode (aNodeIter + aNodeOffset) = aPnt;
77     }
78
79     // copy triangles
80     const TopAbs_Orientation anOrientation = anExpSF.Current().Orientation();
81     for (Standard_Integer aTriIter = aTriangles.Lower(); aTriIter <= aTriangles.Upper(); ++aTriIter)
82     {
83       Poly_Triangle aTri = aTriangles (aTriIter);
84
85       Standard_Integer anId[3];
86       aTri.Get (anId[0], anId[1], anId[2]);
87       if (anOrientation == TopAbs_REVERSED)
88       {
89         // Swap 1, 2.
90         Standard_Integer aTmpIdx = anId[1];
91         anId[1] = anId[2];
92         anId[2] = aTmpIdx;
93       }
94
95       // Update nodes according to the offset.
96       anId[0] += aNodeOffset;
97       anId[1] += aNodeOffset;
98       anId[2] += aNodeOffset;
99
100       aTri.Set (anId[0], anId[1], anId[2]);
101       aMesh->ChangeTriangle (aTriIter + aTriangleOffet) =  aTri;
102     }
103
104     aNodeOffset += aNodes.Size();
105     aTriangleOffet += aTriangles.Size();
106   }
107
108   OSD_Path aPath (theFileName);
109   return myASCIIMode
110        ? RWStl::WriteAscii  (aMesh, aPath)
111        : RWStl::WriteBinary (aMesh, aPath);
112 }