bf85e8a8be7b58c45bf87ea30d4135ab41823d42
[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 <Message.hxx>
19 #include <Message_Messenger.hxx>
20 #include <OSD_Path.hxx>
21 #include <OSD_OpenFile.hxx>
22 #include <RWStl.hxx>
23 #include <BRep_Tool.hxx>
24 #include <TopoDS.hxx>
25 #include <TopoDS_Face.hxx>
26 #include <TopExp_Explorer.hxx>
27 #include <Poly_Triangulation.hxx>
28
29 //=============================================================================
30 //function : StlAPI_Writer
31 //purpose  :
32 //=============================================================================
33 StlAPI_Writer::StlAPI_Writer()
34 : myASCIIMode (Standard_True)
35 {
36   //
37 }
38
39 //=============================================================================
40 //function : Write
41 //purpose  :
42 //=============================================================================
43 Standard_Boolean StlAPI_Writer::Write (const TopoDS_Shape&    theShape,
44                                        const Standard_CString theFileName,
45                                        const Message_ProgressRange& theProgress)
46 {
47   Standard_Integer aNbNodes = 0;
48   Standard_Integer aNbTriangles = 0;
49
50   // calculate total number of the nodes and triangles
51   for (TopExp_Explorer anExpSF (theShape, TopAbs_FACE); anExpSF.More(); anExpSF.Next())
52   {
53     TopLoc_Location aLoc;
54     Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (TopoDS::Face (anExpSF.Current()), aLoc);
55     if (! aTriangulation.IsNull())
56     {
57       aNbNodes += aTriangulation->NbNodes ();
58       aNbTriangles += aTriangulation->NbTriangles ();
59     }
60   }
61
62   if (aNbTriangles == 0)
63   {
64     // No triangulation on the shape
65     return Standard_False;
66   }
67
68   // create temporary triangulation
69   Handle(Poly_Triangulation) aMesh = new Poly_Triangulation (aNbNodes, aNbTriangles, Standard_False);
70   // count faces missing triangulation
71   Standard_Integer aNbFacesNoTri = 0;
72   // fill temporary triangulation
73   Standard_Integer aNodeOffset = 0;
74   Standard_Integer aTriangleOffet = 0;
75   for (TopExp_Explorer anExpSF (theShape, TopAbs_FACE); anExpSF.More(); anExpSF.Next())
76   {
77     const TopoDS_Shape& aFace = anExpSF.Current();
78     TopLoc_Location aLoc;
79     Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (TopoDS::Face (aFace), aLoc);
80     if (aTriangulation.IsNull())
81     {
82       ++aNbFacesNoTri;
83       continue;
84     }
85
86     const TColgp_Array1OfPnt& aNodes = aTriangulation->Nodes();
87     const Poly_Array1OfTriangle& aTriangles = aTriangulation->Triangles();
88
89     // copy nodes
90     gp_Trsf aTrsf = aLoc.Transformation();
91     for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
92     {
93       gp_Pnt aPnt = aNodes (aNodeIter);
94       aPnt.Transform (aTrsf);
95       aMesh->ChangeNode (aNodeIter + aNodeOffset) = aPnt;
96     }
97
98     // copy triangles
99     const TopAbs_Orientation anOrientation = anExpSF.Current().Orientation();
100     for (Standard_Integer aTriIter = aTriangles.Lower(); aTriIter <= aTriangles.Upper(); ++aTriIter)
101     {
102       Poly_Triangle aTri = aTriangles (aTriIter);
103
104       Standard_Integer anId[3];
105       aTri.Get (anId[0], anId[1], anId[2]);
106       if (anOrientation == TopAbs_REVERSED)
107       {
108         // Swap 1, 2.
109         Standard_Integer aTmpIdx = anId[1];
110         anId[1] = anId[2];
111         anId[2] = aTmpIdx;
112       }
113
114       // Update nodes according to the offset.
115       anId[0] += aNodeOffset;
116       anId[1] += aNodeOffset;
117       anId[2] += aNodeOffset;
118
119       aTri.Set (anId[0], anId[1], anId[2]);
120       aMesh->ChangeTriangle (aTriIter + aTriangleOffet) =  aTri;
121     }
122
123     aNodeOffset += aNodes.Size();
124     aTriangleOffet += aTriangles.Size();
125   }
126
127   OSD_Path aPath (theFileName);
128   Standard_Boolean isDone = (myASCIIMode
129     ? RWStl::WriteAscii(aMesh, aPath, theProgress)
130     : RWStl::WriteBinary(aMesh, aPath, theProgress));
131
132   if (isDone && (aNbFacesNoTri > 0))
133   {
134     // Print warning with number of faces missing triangulation
135     TCollection_AsciiString aWarningMsg =
136       TCollection_AsciiString ("Warning: ") +
137       TCollection_AsciiString (aNbFacesNoTri) +
138       TCollection_AsciiString ((aNbFacesNoTri == 1) ? " face has" : " faces have") +
139       TCollection_AsciiString (" been skipped due to null triangulation");
140     Message::SendWarning (aWarningMsg);
141   }
142
143   return isDone;
144 }