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