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