0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
[occt.git] / src / RWMesh / RWMesh_CafReader.cxx
1 // Author: Kirill Gavrilov
2 // Copyright (c) 2016-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 <RWMesh_CafReader.hxx>
16
17 #include <XCAFPrs_DocumentExplorer.hxx>
18
19 #include <Message.hxx>
20 #include <Message_Messenger.hxx>
21 #include <Message_ProgressIndicator.hxx>
22 #include <BRep_Builder.hxx>
23 #include <OSD_Path.hxx>
24 #include <OSD_Timer.hxx>
25 #include <TDataStd_Name.hxx>
26 #include <TDocStd_Document.hxx>
27 #include <TopExp_Explorer.hxx>
28 #include <TopoDS.hxx>
29 #include <TopoDS_Iterator.hxx>
30 #include <XCAFDoc_ColorTool.hxx>
31 #include <XCAFDoc_ColorType.hxx>
32 #include <XCAFDoc_DocumentTool.hxx>
33 #include <XCAFDoc_ShapeMapTool.hxx>
34 #include <XCAFDoc_ShapeTool.hxx>
35 #include <XCAFDoc_VisMaterialTool.hxx>
36
37 IMPLEMENT_STANDARD_RTTIEXT(RWMesh_CafReader, Standard_Transient)
38
39 // =======================================================================
40 // function : RWMesh_CafReader
41 // purpose  :
42 // =======================================================================
43 RWMesh_CafReader::RWMesh_CafReader()
44 : myToFillDoc (Standard_True),
45   myToFillIncomplete (Standard_True),
46   myMemoryLimitMiB (-1),
47   myExtraStatus (RWMesh_CafReaderStatusEx_NONE)
48 {
49   //
50 }
51
52 // =======================================================================
53 // function : ~RWMesh_CafReader
54 // purpose  :
55 // =======================================================================
56 RWMesh_CafReader::~RWMesh_CafReader()
57 {
58   //
59 }
60
61 // =======================================================================
62 // function : SingleShape
63 // purpose  :
64 // =======================================================================
65 TopoDS_Shape RWMesh_CafReader::SingleShape() const
66 {
67   if (myRootShapes.Size() > 1)
68   {
69     BRep_Builder aBuilder;
70     TopoDS_Compound aCompound;
71     aBuilder.MakeCompound (aCompound);
72     for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next())
73     {
74       aBuilder.Add (aCompound, aRootIter.Value());
75     }
76     return aCompound;
77   }
78   else if (!myRootShapes.IsEmpty())
79   {
80     return myRootShapes.First();
81   }
82   return TopoDS_Shape();
83 }
84
85 // =======================================================================
86 // function : perform
87 // purpose  :
88 // =======================================================================
89 Standard_Boolean RWMesh_CafReader::perform (const TCollection_AsciiString& theFile,
90                                             const Handle(Message_ProgressIndicator)& theProgress,
91                                             const Standard_Boolean theToProbe)
92 {
93   Standard_Integer aNewRootsLower = 1;
94   if (!myXdeDoc.IsNull())
95   {
96     TDF_LabelSequence aRootLabels;
97     XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main())->GetFreeShapes (aRootLabels);
98     aNewRootsLower = aRootLabels.Upper() + 1;
99   }
100
101   OSD_Timer aLoadingTimer;
102   aLoadingTimer.Start();
103   const Standard_Boolean isDone = performMesh (theFile, theProgress, theToProbe);
104   if (theToProbe
105    || (!theProgress.IsNull() && theProgress->UserBreak()))
106   {
107     return isDone;
108   }
109   else if (!isDone)
110   {
111     if (!myToFillIncomplete)
112     {
113       return Standard_False;
114     }
115
116     myExtraStatus |= RWMesh_CafReaderStatusEx_Partial;
117   }
118
119   TopLoc_Location aDummyLoc;
120   Standard_Integer aNbNodes = 0, aNbElems = 0, aNbFaces = 0;
121   for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next())
122   {
123     for (TopExp_Explorer aFaceIter (aRootIter.Value(), TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
124     {
125       const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Current());
126       if (const Handle(Poly_Triangulation)& aPolyTri = BRep_Tool::Triangulation (aFace, aDummyLoc))
127       {
128         ++aNbFaces;
129         aNbNodes += aPolyTri->NbNodes();
130         aNbElems += aPolyTri->NbTriangles();
131       }
132     }
133   }
134   if (!isDone && aNbElems < 100)
135   {
136     return Standard_False;
137   }
138
139   fillDocument();
140   generateNames (theFile, aNewRootsLower, Standard_False);
141
142   aLoadingTimer.Stop();
143
144   Message::SendInfo (TCollection_AsciiString ("Mesh ") + theFile
145                    + "\n[" + aNbNodes + " nodes] [" + aNbElems + " 2d elements]"
146                    + "\n[" + (!isDone ? "PARTIALLY " : "") + "read in " + aLoadingTimer.ElapsedTime() + " s]");
147   return Standard_True;
148 }
149
150 // =======================================================================
151 // function : fillDocument
152 // purpose  :
153 // =======================================================================
154 void RWMesh_CafReader::fillDocument()
155 {
156   if (!myToFillDoc
157     || myXdeDoc.IsNull()
158     || myRootShapes.IsEmpty())
159   {
160     return;
161   }
162
163   const Standard_Boolean wasAutoNaming = XCAFDoc_ShapeTool::AutoNaming();
164   XCAFDoc_ShapeTool::SetAutoNaming (Standard_False);
165   const TCollection_AsciiString aRootName; // = generateRootName (theFile);
166   CafDocumentTools aTools;
167   aTools.ShapeTool = XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main());
168   aTools.ColorTool = XCAFDoc_DocumentTool::ColorTool (myXdeDoc->Main());
169   aTools.VisMaterialTool = XCAFDoc_DocumentTool::VisMaterialTool (myXdeDoc->Main());
170   for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next())
171   {
172     addShapeIntoDoc (aTools, aRootIter.Value(), TDF_Label(), aRootName);
173   }
174   XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main())->UpdateAssemblies();
175   XCAFDoc_ShapeTool::SetAutoNaming (wasAutoNaming);
176 }
177
178 // =======================================================================
179 // function : setShapeName
180 // purpose  :
181 // =======================================================================
182 void RWMesh_CafReader::setShapeName (const TDF_Label& theLabel,
183                                      const TopAbs_ShapeEnum theShapeType,
184                                      const TCollection_AsciiString& theName,
185                                      const TDF_Label& theParentLabel,
186                                      const TCollection_AsciiString& theParentName)
187 {
188   if (!theName.IsEmpty())
189   {
190     TDataStd_Name::Set (theLabel, theName);
191   }
192   else if (!theParentLabel.IsNull())
193   {
194     TDataStd_Name::Set (theLabel, shapeTypeToString (theShapeType));
195   }
196   else if (theParentLabel.IsNull()
197        && !theParentName.IsEmpty())
198   {
199     TDataStd_Name::Set (theLabel, theParentName);
200   }
201 }
202
203 // =======================================================================
204 // function : setShapeStyle
205 // purpose  :
206 // =======================================================================
207 void RWMesh_CafReader::setShapeStyle (const CafDocumentTools& theTools,
208                                       const TDF_Label& theLabel,
209                                       const XCAFPrs_Style& theStyle)
210 {
211   if (theStyle.IsSetColorSurf())
212   {
213     theTools.ColorTool->SetColor (theLabel, theStyle.GetColorSurfRGBA(), XCAFDoc_ColorSurf);
214   }
215   if (theStyle.IsSetColorCurv())
216   {
217     theTools.ColorTool->SetColor (theLabel, theStyle.GetColorCurv(), XCAFDoc_ColorCurv);
218   }
219   if (!theStyle.Material().IsNull())
220   {
221     TDF_Label aMaterialLabel = theStyle.Material()->Label();
222     if (aMaterialLabel.IsNull())
223     {
224       const TCollection_AsciiString aMatName = !theStyle.Material()->RawName().IsNull()
225                                              ?  theStyle.Material()->RawName()->String()
226                                              :  "";
227       aMaterialLabel = theTools.VisMaterialTool->AddMaterial (theStyle.Material(), aMatName);
228     }
229     theTools.VisMaterialTool->SetShapeMaterial (theLabel, aMaterialLabel);
230   }
231 }
232
233 // =======================================================================
234 // function : setShapeNamedData
235 // purpose  :
236 // =======================================================================
237 void RWMesh_CafReader::setShapeNamedData (const CafDocumentTools& ,
238                                           const TDF_Label& theLabel,
239                                           const Handle(TDataStd_NamedData)& theNameData)
240 {
241   if (theNameData.IsNull())
242   {
243     return;
244   }
245
246   const TDF_Label aNameDataLabel = theNameData->Label();
247   Handle(TDataStd_NamedData) anOtherNamedData;
248   if (theLabel.FindAttribute (theNameData->ID(), anOtherNamedData))
249   {
250     if (anOtherNamedData->Label() != aNameDataLabel)
251     {
252       Message::SendAlarm ("Error! Different NamedData is already set to shape");
253     }
254   }
255   else
256   {
257     if (aNameDataLabel.IsNull())
258     {
259       theLabel.AddAttribute (theNameData);
260     }
261     else
262     {
263       Message::SendAlarm ("Error! Skipped NamedData instance shared across shapes");
264     }
265   }
266 }
267
268 // =======================================================================
269 // function : addShapeIntoDoc
270 // purpose  :
271 // =======================================================================
272 Standard_Boolean RWMesh_CafReader::addShapeIntoDoc (CafDocumentTools& theTools,
273                                                     const TopoDS_Shape& theShape,
274                                                     const TDF_Label& theLabel,
275                                                     const TCollection_AsciiString& theParentName)
276 {
277   if (theShape.IsNull()
278    || myXdeDoc.IsNull())
279   {
280     return Standard_False;
281   }
282
283   const TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
284   TopoDS_Shape aShapeToAdd = theShape;
285   const TopoDS_Shape aShapeNoLoc = theShape.Located (TopLoc_Location());
286   Standard_Boolean toMakeAssembly = Standard_False;
287   if (theShape.ShapeType() == TopAbs_COMPOUND)
288   {
289     RWMesh_NodeAttributes aSubFaceAttribs;
290     for (TopoDS_Iterator aSubShapeIter (theShape, Standard_True, Standard_False); !toMakeAssembly && aSubShapeIter.More(); aSubShapeIter.Next())
291     {
292       if (aSubShapeIter.Value().ShapeType() != TopAbs_FACE)
293       {
294         toMakeAssembly = Standard_True;
295         break;
296       }
297
298       const TopoDS_Face& aFace = TopoDS::Face (aSubShapeIter.Value());
299       toMakeAssembly = toMakeAssembly
300                     || (myAttribMap.Find (aFace, aSubFaceAttribs) && !aSubFaceAttribs.Name.IsEmpty());
301     }
302
303     if (toMakeAssembly)
304     {
305       // create an empty Compound to add as assembly, so that we can add children one-by-one via AddComponent()
306       TopoDS_Compound aCompound;
307       BRep_Builder aBuilder;
308       aBuilder.MakeCompound (aCompound);
309       aCompound.Location (theShape.Location());
310       aShapeToAdd = aCompound;
311     }
312   }
313
314   TDF_Label aNewLabel, anOldLabel;
315   if (theLabel.IsNull())
316   {
317     // add new shape
318     aNewLabel = theTools.ShapeTool->AddShape (aShapeToAdd, toMakeAssembly);
319   }
320   else if (theTools.ShapeTool->IsAssembly (theLabel))
321   {
322     // add shape as component
323     if (theTools.ComponentMap.Find (aShapeNoLoc, anOldLabel))
324     {
325       aNewLabel = theTools.ShapeTool->AddComponent (theLabel, anOldLabel, theShape.Location());
326     }
327     else
328     {
329       aNewLabel = theTools.ShapeTool->AddComponent (theLabel, aShapeToAdd, toMakeAssembly);
330
331       TDF_Label aRefLabel = aNewLabel;
332       theTools.ShapeTool->GetReferredShape (aNewLabel, aRefLabel);
333       if (!aRefLabel.IsNull())
334       {
335         theTools.ComponentMap.Bind (aShapeNoLoc, aRefLabel);
336       }
337     }
338   }
339   else
340   {
341     // add shape as sub-shape
342     aNewLabel = theTools.ShapeTool->AddSubShape (theLabel, theShape);
343     if (!aNewLabel.IsNull())
344     {
345       Handle(XCAFDoc_ShapeMapTool) aShapeMapTool = XCAFDoc_ShapeMapTool::Set (aNewLabel);
346       aShapeMapTool->SetShape (theShape);
347     }
348   }
349   if (aNewLabel.IsNull())
350   {
351     return Standard_False;
352   }
353
354   // if new label is a reference get referred shape
355   TDF_Label aNewRefLabel = aNewLabel;
356   theTools.ShapeTool->GetReferredShape (aNewLabel, aNewRefLabel);
357
358   RWMesh_NodeAttributes aRefShapeAttribs;
359   myAttribMap.Find (aShapeNoLoc, aRefShapeAttribs);
360
361   bool hasProductName = false;
362   if (aNewLabel != aNewRefLabel)
363   {
364     // put attributes to the Instance (overrides Product attributes)
365     RWMesh_NodeAttributes aShapeAttribs;
366     if (!theShape.Location().IsIdentity()
367       && myAttribMap.Find (theShape, aShapeAttribs))
368     {
369       if (!aShapeAttribs.Style.IsEqual (aRefShapeAttribs.Style))
370       {
371         setShapeStyle (theTools, aNewLabel, aShapeAttribs.Style);
372       }
373       if (aShapeAttribs.NamedData != aRefShapeAttribs.NamedData)
374       {
375         setShapeNamedData (theTools, aNewLabel, aShapeAttribs.NamedData);
376       }
377       setShapeName (aNewLabel, aShapeType, aShapeAttribs.Name, theLabel, theParentName);
378       if (aRefShapeAttribs.Name.IsEmpty()
379       && !aShapeAttribs.Name.IsEmpty())
380       {
381         // it is not nice having unnamed Product, so copy name from first Instance (probably the only one)
382         hasProductName = true;
383         setShapeName (aNewRefLabel, aShapeType, aShapeAttribs.Name, theLabel, theParentName);
384       }
385     }
386     else
387     {
388       // copy name from Product
389       setShapeName (aNewLabel, aShapeType, aRefShapeAttribs.Name, theLabel, theParentName);
390     }
391   }
392
393   if (!anOldLabel.IsNull())
394   {
395     // already defined in the document
396     return Standard_True;
397   }
398
399   // put attributes to the Product (shared across Instances)
400   if (!hasProductName)
401   {
402     setShapeName (aNewRefLabel, aShapeType, aRefShapeAttribs.Name, theLabel, theParentName);
403   }
404   setShapeStyle (theTools, aNewRefLabel, aRefShapeAttribs.Style);
405   setShapeNamedData (theTools, aNewRefLabel, aRefShapeAttribs.NamedData);
406
407   if (theTools.ShapeTool->IsAssembly (aNewRefLabel))
408   {
409     // store sub-shapes (iterator is set to not inherit Location of parent object)
410     TCollection_AsciiString aDummyName;
411     for (TopoDS_Iterator aSubShapeIter (theShape, Standard_True, Standard_False); aSubShapeIter.More(); aSubShapeIter.Next())
412     {
413       addShapeIntoDoc (theTools, aSubShapeIter.Value(), aNewRefLabel, aDummyName);
414     }
415   }
416   else
417   {
418     // store a plain list of sub-shapes in case if they have custom attributes (usually per-face color)
419     RWMesh_NodeAttributes aSubShapeAttribs;
420     for (TopoDS_Iterator aSubShapeIter (theShape, Standard_True, Standard_False); aSubShapeIter.More(); aSubShapeIter.Next())
421     {
422       const TopoDS_Shape& aSubShape = aSubShapeIter.Value();
423       if (myAttribMap.Find (aSubShape.Located (TopLoc_Location()), aSubShapeAttribs))
424       {
425         addSubShapeIntoDoc (theTools, aSubShape, aNewRefLabel, aSubShapeAttribs);
426       }
427     }
428   }
429   return Standard_True;
430 }
431
432 // =======================================================================
433 // function : addSubShapeIntoDoc
434 // purpose  :
435 // =======================================================================
436 Standard_Boolean RWMesh_CafReader::addSubShapeIntoDoc (CafDocumentTools& theTools,
437                                                        const TopoDS_Shape& theShape,
438                                                        const TDF_Label& theParentLabel,
439                                                        const RWMesh_NodeAttributes& theAttribs)
440 {
441   if (theShape.IsNull()
442    || myXdeDoc.IsNull())
443   {
444     return Standard_False;
445   }
446
447   const TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
448   TDF_Label aNewLabel = theTools.ShapeTool->AddSubShape (theParentLabel, theShape);
449   if (aNewLabel.IsNull())
450   {
451     return Standard_False;
452   }
453
454   {
455     Handle(XCAFDoc_ShapeMapTool) aShapeMapTool = XCAFDoc_ShapeMapTool::Set (aNewLabel);
456     aShapeMapTool->SetShape (theShape);
457   }
458
459   // if new label is a reference get referred shape
460   TDF_Label aNewRefLabel = aNewLabel;
461   theTools.ShapeTool->GetReferredShape (aNewLabel, aNewRefLabel);
462
463   // put attributes to the Product (shared across Instances)
464   static const TCollection_AsciiString anEmptyString;
465   setShapeName (aNewRefLabel, aShapeType, theAttribs.Name, TDF_Label(), anEmptyString);
466   setShapeStyle (theTools, aNewRefLabel, theAttribs.Style);
467   setShapeNamedData (theTools, aNewRefLabel, theAttribs.NamedData);
468
469   RWMesh_NodeAttributes aSubShapeAttribs;
470   for (TopoDS_Iterator aSubShapeIter (theShape, Standard_True, Standard_False); aSubShapeIter.More(); aSubShapeIter.Next())
471   {
472     const TopoDS_Shape& aSubShape = aSubShapeIter.Value();
473     if (myAttribMap.Find (aSubShape.Located (TopLoc_Location()), aSubShapeAttribs))
474     {
475       addSubShapeIntoDoc (theTools, aSubShape, theParentLabel, aSubShapeAttribs);
476     }
477   }
478   return Standard_True;
479 }
480
481 // =======================================================================
482 // function : generateNames
483 // purpose  :
484 // =======================================================================
485 void RWMesh_CafReader::generateNames (const TCollection_AsciiString& theFile,
486                                       const Standard_Integer theRootLower,
487                                       const Standard_Boolean theWithSubLabels)
488 {
489   if (myXdeDoc.IsNull())
490   {
491     return;
492   }
493
494   TCollection_AsciiString aDummyFolder, aFileName;
495   OSD_Path::FolderAndFileFromPath (theFile, aDummyFolder, aFileName);
496   const TCollection_AsciiString aRootName = myRootPrefix + aFileName;
497
498   Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main());
499   TDF_LabelSequence aRootLabels;
500   aShapeTool->GetFreeShapes (aRootLabels);
501   if (aRootLabels.Upper() < theRootLower)
502   {
503     return;
504   }
505
506   // replace empty names
507   Handle(TDataStd_Name) aNodeName;
508   Standard_Integer aRootIndex = aRootLabels.Lower();
509   TDF_LabelSequence aNewRootLabels;
510   for (TDF_LabelSequence::Iterator aRootIter (aRootLabels); aRootIter.More(); ++aRootIndex, aRootIter.Next())
511   {
512     if (aRootIndex < theRootLower)
513     {
514       continue;
515     }
516     else if (theWithSubLabels)
517     {
518       aNewRootLabels.Append (aRootIter.Value());
519     }
520
521     const TDF_Label aLabel = aRootIter.Value();
522     TDF_Label aRefLab = aLabel;
523     XCAFDoc_ShapeTool::GetReferredShape (aLabel, aRefLab);
524     if (!aRefLab.FindAttribute (TDataStd_Name::GetID(), aNodeName))
525     {
526       TDataStd_Name::Set (aRefLab, aRootName);
527     }
528     if (aLabel != aRefLab
529     && !aLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName))
530     {
531       TDataStd_Name::Set (aLabel, aRootName);
532     }
533   }
534
535   if (theWithSubLabels)
536   {
537     for (XCAFPrs_DocumentExplorer aDocIter (myXdeDoc, aNewRootLabels, XCAFPrs_DocumentExplorerFlags_NoStyle);
538          aDocIter.More(); aDocIter.Next())
539     {
540       if (aDocIter.CurrentDepth() == 0
541        || aDocIter.Current().RefLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName))
542       {
543         continue;
544       }
545
546       const TopoDS_Shape aShape = XCAFDoc_ShapeTool::GetShape (aDocIter.Current().RefLabel);
547       if (!aShape.IsNull())
548       {
549         TDataStd_Name::Set (aDocIter.Current().RefLabel, shapeTypeToString (aShape.ShapeType()));
550       }
551     }
552   }
553 }