0030810: Data Exchange, RWObj_CafReader - fix material assignment
[occt.git] / src / RWObj / RWObj_TriangulationReader.cxx
1 // Author: Kirill Gavrilov
2 // Copyright (c) 2019 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #include <RWObj_TriangulationReader.hxx>
16
17 #include <BRep_Builder.hxx>
18 #include <TopoDS.hxx>
19 #include <TopoDS_Iterator.hxx>
20
21 IMPLEMENT_STANDARD_RTTIEXT(RWObj_TriangulationReader, RWObj_Reader)
22
23 //================================================================
24 // Function : addMesh
25 // Purpose  :
26 //================================================================
27 Standard_Boolean RWObj_TriangulationReader::addMesh (const RWObj_SubMesh& theMesh,
28                                                      const RWObj_SubMeshReason theReason)
29 {
30   if (!myToCreateShapes)
31   {
32     return Standard_False;
33   }
34
35   if (Handle(Poly_Triangulation) aTris = GetTriangulation())
36   {
37     myNodes.Clear();
38     myNodesUV.Clear();
39     myNormals.Clear();
40     myTriangles.Clear();
41     if (theMesh.Group != myLastGroupName)
42     {
43       // flush previous group and start a new one
44       if (addSubShape (myLastObjectShape, myLastGroupShape, Standard_False))
45       {
46         if (myShapeReceiver != NULL)
47         {
48           const RWObj_Material* aMaterial = myLastGroupShape.ShapeType() == TopAbs_FACE
49                                         && !myLastFaceMaterial.IsEmpty()
50                                           ? myMaterials.Seek (myLastFaceMaterial)
51                                           : NULL;
52           myShapeReceiver->BindNamedShape (myLastGroupShape, myLastGroupName, aMaterial, Standard_False);
53         }
54       }
55       myLastGroupShape = TopoDS_Shape();
56       myLastGroupName = theMesh.Group;
57     }
58
59     TopoDS_Face aNewFace;
60     BRep_Builder aBuilder;
61     aBuilder.MakeFace (aNewFace, aTris);
62     addSubShape (myLastGroupShape, aNewFace, Standard_True);
63     myLastFaceMaterial = theMesh.Material;
64     if (myShapeReceiver != NULL)
65     {
66       const RWObj_Material* aMaterial = myMaterials.Seek (theMesh.Material);
67       myShapeReceiver->BindNamedShape (aNewFace, "", aMaterial, Standard_False);
68     }
69   }
70
71   if (theReason == RWObj_SubMeshReason_NewObject)
72   {
73     // forced flush at the end of the object
74     if (addSubShape (myLastObjectShape, myLastGroupShape, Standard_False))
75     {
76       if (myShapeReceiver != NULL)
77       {
78         const RWObj_Material* aMaterial = myLastGroupShape.ShapeType() == TopAbs_FACE
79                                           && !myLastFaceMaterial.IsEmpty()
80                                             ? myMaterials.Seek (myLastFaceMaterial)
81                                             : NULL;
82         myShapeReceiver->BindNamedShape (myLastGroupShape, myLastGroupName, aMaterial, Standard_False);
83       }
84     }
85     myLastGroupShape = TopoDS_Shape();
86     myLastGroupName.Clear();
87
88     if (addSubShape (myResultShape, myLastObjectShape, Standard_False))
89     {
90       if (myShapeReceiver != NULL)
91       {
92         myShapeReceiver->BindNamedShape (myLastObjectShape, theMesh.Object, NULL, Standard_True);
93       }
94     }
95     myLastObjectShape = TopoDS_Compound();
96   }
97   return Standard_True;
98 }
99
100 // =======================================================================
101 // function : addSubShape
102 // purpose  :
103 // =======================================================================
104 Standard_Boolean RWObj_TriangulationReader::addSubShape (TopoDS_Shape& theParent,
105                                                          const TopoDS_Shape& theSubShape,
106                                                          const Standard_Boolean theToExpandCompound)
107 {
108   if (theSubShape.IsNull())
109   {
110     return Standard_False;
111   }
112
113   BRep_Builder aBuilder;
114   if (theParent.IsNull()
115    && theToExpandCompound)
116   {
117     theParent = theSubShape;
118     return Standard_True;
119   }
120
121   TopoDS_Compound aComp;
122   if (!theParent.IsNull()
123     && theParent.ShapeType() == TopAbs_COMPOUND)
124   {
125     aComp = TopoDS::Compound (theParent);
126   }
127   else
128   {
129     aBuilder.MakeCompound (aComp);
130     if (!theParent.IsNull())
131     {
132       aBuilder.Add (aComp, theParent);
133     }
134   }
135   aBuilder.Add (aComp, theSubShape);
136   theParent = aComp;
137   return Standard_True;
138 }
139
140 //=============================================================================
141 //function : GetTriangulation
142 //purpose  :
143 //=============================================================================
144 Handle(Poly_Triangulation) RWObj_TriangulationReader::GetTriangulation()
145 {
146   if (myTriangles.IsEmpty())
147   {
148     return Handle(Poly_Triangulation)();
149   }
150
151   const Standard_Boolean hasNormals = myNodes.Length() == myNormals.Length();
152   const Standard_Boolean hasUV      = myNodes.Length() == myNodesUV.Length();
153
154   Handle(Poly_Triangulation) aPoly = new Poly_Triangulation (myNodes.Length(), myTriangles.Length(), hasUV);
155   for (Standard_Integer aNodeIter = 0; aNodeIter < myNodes.Size(); ++aNodeIter)
156   {
157     const gp_Pnt& aNode = myNodes.Value (aNodeIter);
158     aPoly->ChangeNode (aNodeIter + 1) = aNode;
159   }
160   if (hasUV)
161   {
162     for (Standard_Integer aNodeIter = 0; aNodeIter < myNodes.Size(); ++aNodeIter)
163     {
164       const Graphic3d_Vec2& aNode = myNodesUV.Value (aNodeIter);
165       aPoly->ChangeUVNode (aNodeIter + 1).SetCoord (aNode.x(), aNode.y());
166     }
167   }
168   if (hasNormals)
169   {
170     const Handle(TShort_HArray1OfShortReal) aNormals = new TShort_HArray1OfShortReal (1, myNodes.Length() * 3);
171     Standard_ShortReal* aNormArr = &aNormals->ChangeFirst();
172     Standard_Integer aNbInvalid = 0;
173     for (Standard_Integer aNodeIter = 0; aNodeIter < myNodes.Size(); ++aNodeIter)
174     {
175       const Graphic3d_Vec3& aNorm = myNormals.Value (aNodeIter);
176       const float aMod2 = aNorm.SquareModulus();
177       if (aMod2 > 0.001f)
178       {
179         aNormArr[aNodeIter * 3 + 0] = aNorm.x();
180         aNormArr[aNodeIter * 3 + 1] = aNorm.y();
181         aNormArr[aNodeIter * 3 + 2] = aNorm.z();
182       }
183       else
184       {
185         ++aNbInvalid;
186         aNormArr[aNodeIter * 3 + 0] = 0.0f;
187         aNormArr[aNodeIter * 3 + 1] = 0.0f;
188         aNormArr[aNodeIter * 3 + 2] = 1.0f;
189       }
190     }
191     if (aNbInvalid != myNodes.Length())
192     {
193       aPoly->SetNormals (aNormals);
194     }
195   }
196
197   for (Standard_Integer aTriIter = 0; aTriIter < myTriangles.Size(); ++aTriIter)
198   {
199     aPoly->ChangeTriangle (aTriIter + 1) = myTriangles (aTriIter);
200   }
201
202   return aPoly;
203 }
204
205 //================================================================
206 // Function : ResultShape
207 // Purpose  :
208 //================================================================
209 TopoDS_Shape RWObj_TriangulationReader::ResultShape()
210 {
211   if (!myToCreateShapes)
212   {
213     if (Handle(Poly_Triangulation) aTris = GetTriangulation())
214     {
215       TopoDS_Face aFace;
216       BRep_Builder aBuilder;
217       aBuilder.MakeFace (aFace, aTris);
218       return aFace;
219     }
220     return TopoDS_Shape();
221   }
222
223   if (!myResultShape.IsNull()
224     && myResultShape.ShapeType() == TopAbs_COMPOUND
225     && myResultShape.NbChildren() == 1
226     && myActiveSubMesh.Object.IsEmpty())
227   {
228     TopoDS_Iterator aChildIter (myResultShape);
229     return aChildIter.Value();
230   }
231   return myResultShape;
232 }