1 // Author: Kirill Gavrilov
2 // Copyright (c) 2016-2019 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
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.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
15 #include <RWMesh_CafReader.hxx>
17 #include <XCAFPrs_DocumentExplorer.hxx>
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>
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>
37 IMPLEMENT_STANDARD_RTTIEXT(RWMesh_CafReader, Standard_Transient)
39 // =======================================================================
40 // function : RWMesh_CafReader
42 // =======================================================================
43 RWMesh_CafReader::RWMesh_CafReader()
44 : myToFillDoc (Standard_True),
45 myToFillIncomplete (Standard_True),
46 myMemoryLimitMiB (-1),
47 myExtraStatus (RWMesh_CafReaderStatusEx_NONE)
52 // =======================================================================
53 // function : ~RWMesh_CafReader
55 // =======================================================================
56 RWMesh_CafReader::~RWMesh_CafReader()
61 // =======================================================================
62 // function : SingleShape
64 // =======================================================================
65 TopoDS_Shape RWMesh_CafReader::SingleShape() const
67 if (myRootShapes.Size() > 1)
69 BRep_Builder aBuilder;
70 TopoDS_Compound aCompound;
71 aBuilder.MakeCompound (aCompound);
72 for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next())
74 aBuilder.Add (aCompound, aRootIter.Value());
78 else if (!myRootShapes.IsEmpty())
80 return myRootShapes.First();
82 return TopoDS_Shape();
85 // =======================================================================
88 // =======================================================================
89 Standard_Boolean RWMesh_CafReader::perform (const TCollection_AsciiString& theFile,
90 const Handle(Message_ProgressIndicator)& theProgress,
91 const Standard_Boolean theToProbe)
93 Standard_Integer aNewRootsLower = 1;
94 if (!myXdeDoc.IsNull())
96 TDF_LabelSequence aRootLabels;
97 XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main())->GetFreeShapes (aRootLabels);
98 aNewRootsLower = aRootLabels.Upper() + 1;
101 OSD_Timer aLoadingTimer;
102 aLoadingTimer.Start();
103 const Standard_Boolean isDone = performMesh (theFile, theProgress, theToProbe);
105 || (!theProgress.IsNull() && theProgress->UserBreak()))
111 if (!myToFillIncomplete)
113 return Standard_False;
116 myExtraStatus |= RWMesh_CafReaderStatusEx_Partial;
119 TopLoc_Location aDummyLoc;
120 Standard_Integer aNbNodes = 0, aNbElems = 0, aNbFaces = 0;
121 for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next())
123 for (TopExp_Explorer aFaceIter (aRootIter.Value(), TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
125 const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Current());
126 if (const Handle(Poly_Triangulation)& aPolyTri = BRep_Tool::Triangulation (aFace, aDummyLoc))
129 aNbNodes += aPolyTri->NbNodes();
130 aNbElems += aPolyTri->NbTriangles();
134 if (!isDone && aNbElems < 100)
136 return Standard_False;
140 generateNames (theFile, aNewRootsLower, Standard_False);
142 aLoadingTimer.Stop();
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;
150 // =======================================================================
151 // function : fillDocument
153 // =======================================================================
154 void RWMesh_CafReader::fillDocument()
158 || myRootShapes.IsEmpty())
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())
172 addShapeIntoDoc (aTools, aRootIter.Value(), TDF_Label(), aRootName);
174 XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main())->UpdateAssemblies();
175 XCAFDoc_ShapeTool::SetAutoNaming (wasAutoNaming);
178 // =======================================================================
179 // function : setShapeName
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)
188 if (!theName.IsEmpty())
190 TDataStd_Name::Set (theLabel, theName);
192 else if (!theParentLabel.IsNull())
194 TDataStd_Name::Set (theLabel, shapeTypeToString (theShapeType));
196 else if (theParentLabel.IsNull()
197 && !theParentName.IsEmpty())
199 TDataStd_Name::Set (theLabel, theParentName);
203 // =======================================================================
204 // function : setShapeStyle
206 // =======================================================================
207 void RWMesh_CafReader::setShapeStyle (const CafDocumentTools& theTools,
208 const TDF_Label& theLabel,
209 const XCAFPrs_Style& theStyle)
211 if (theStyle.IsSetColorSurf())
213 theTools.ColorTool->SetColor (theLabel, theStyle.GetColorSurfRGBA(), XCAFDoc_ColorSurf);
215 if (theStyle.IsSetColorCurv())
217 theTools.ColorTool->SetColor (theLabel, theStyle.GetColorCurv(), XCAFDoc_ColorCurv);
219 if (!theStyle.Material().IsNull())
221 TDF_Label aMaterialLabel = theStyle.Material()->Label();
222 if (aMaterialLabel.IsNull())
224 const TCollection_AsciiString aMatName = !theStyle.Material()->RawName().IsNull()
225 ? theStyle.Material()->RawName()->String()
227 aMaterialLabel = theTools.VisMaterialTool->AddMaterial (theStyle.Material(), aMatName);
229 theTools.VisMaterialTool->SetShapeMaterial (theLabel, aMaterialLabel);
233 // =======================================================================
234 // function : setShapeNamedData
236 // =======================================================================
237 void RWMesh_CafReader::setShapeNamedData (const CafDocumentTools& ,
238 const TDF_Label& theLabel,
239 const Handle(TDataStd_NamedData)& theNameData)
241 if (theNameData.IsNull())
246 const TDF_Label aNameDataLabel = theNameData->Label();
247 Handle(TDataStd_NamedData) anOtherNamedData;
248 if (theLabel.FindAttribute (theNameData->ID(), anOtherNamedData))
250 if (anOtherNamedData->Label() != aNameDataLabel)
252 Message::SendAlarm ("Error! Different NamedData is already set to shape");
257 if (aNameDataLabel.IsNull())
259 theLabel.AddAttribute (theNameData);
263 Message::SendAlarm ("Error! Skipped NamedData instance shared across shapes");
268 // =======================================================================
269 // function : addShapeIntoDoc
271 // =======================================================================
272 Standard_Boolean RWMesh_CafReader::addShapeIntoDoc (CafDocumentTools& theTools,
273 const TopoDS_Shape& theShape,
274 const TDF_Label& theLabel,
275 const TCollection_AsciiString& theParentName)
277 if (theShape.IsNull()
278 || myXdeDoc.IsNull())
280 return Standard_False;
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)
289 RWMesh_NodeAttributes aSubFaceAttribs;
290 for (TopoDS_Iterator aSubShapeIter (theShape, Standard_True, Standard_False); !toMakeAssembly && aSubShapeIter.More(); aSubShapeIter.Next())
292 if (aSubShapeIter.Value().ShapeType() != TopAbs_FACE)
294 toMakeAssembly = Standard_True;
298 const TopoDS_Face& aFace = TopoDS::Face (aSubShapeIter.Value());
299 toMakeAssembly = toMakeAssembly
300 || (myAttribMap.Find (aFace, aSubFaceAttribs) && !aSubFaceAttribs.Name.IsEmpty());
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;
314 TDF_Label aNewLabel, anOldLabel;
315 if (theLabel.IsNull())
318 aNewLabel = theTools.ShapeTool->AddShape (aShapeToAdd, toMakeAssembly);
320 else if (theTools.ShapeTool->IsAssembly (theLabel))
322 // add shape as component
323 if (theTools.ComponentMap.Find (aShapeNoLoc, anOldLabel))
325 aNewLabel = theTools.ShapeTool->AddComponent (theLabel, anOldLabel, theShape.Location());
329 aNewLabel = theTools.ShapeTool->AddComponent (theLabel, aShapeToAdd, toMakeAssembly);
331 TDF_Label aRefLabel = aNewLabel;
332 theTools.ShapeTool->GetReferredShape (aNewLabel, aRefLabel);
333 if (!aRefLabel.IsNull())
335 theTools.ComponentMap.Bind (aShapeNoLoc, aRefLabel);
341 // add shape as sub-shape
342 aNewLabel = theTools.ShapeTool->AddSubShape (theLabel, theShape);
343 if (!aNewLabel.IsNull())
345 Handle(XCAFDoc_ShapeMapTool) aShapeMapTool = XCAFDoc_ShapeMapTool::Set (aNewLabel);
346 aShapeMapTool->SetShape (theShape);
349 if (aNewLabel.IsNull())
351 return Standard_False;
354 // if new label is a reference get referred shape
355 TDF_Label aNewRefLabel = aNewLabel;
356 theTools.ShapeTool->GetReferredShape (aNewLabel, aNewRefLabel);
358 RWMesh_NodeAttributes aRefShapeAttribs;
359 myAttribMap.Find (aShapeNoLoc, aRefShapeAttribs);
361 bool hasProductName = false;
362 if (aNewLabel != aNewRefLabel)
364 // put attributes to the Instance (overrides Product attributes)
365 RWMesh_NodeAttributes aShapeAttribs;
366 if (!theShape.Location().IsIdentity()
367 && myAttribMap.Find (theShape, aShapeAttribs))
369 if (!aShapeAttribs.Style.IsEqual (aRefShapeAttribs.Style))
371 setShapeStyle (theTools, aNewLabel, aShapeAttribs.Style);
373 if (aShapeAttribs.NamedData != aRefShapeAttribs.NamedData)
375 setShapeNamedData (theTools, aNewLabel, aShapeAttribs.NamedData);
377 setShapeName (aNewLabel, aShapeType, aShapeAttribs.Name, theLabel, theParentName);
378 if (aRefShapeAttribs.Name.IsEmpty()
379 && !aShapeAttribs.Name.IsEmpty())
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);
388 // copy name from Product
389 setShapeName (aNewLabel, aShapeType, aRefShapeAttribs.Name, theLabel, theParentName);
393 if (!anOldLabel.IsNull())
395 // already defined in the document
396 return Standard_True;
399 // put attributes to the Product (shared across Instances)
402 setShapeName (aNewRefLabel, aShapeType, aRefShapeAttribs.Name, theLabel, theParentName);
404 setShapeStyle (theTools, aNewRefLabel, aRefShapeAttribs.Style);
405 setShapeNamedData (theTools, aNewRefLabel, aRefShapeAttribs.NamedData);
407 if (theTools.ShapeTool->IsAssembly (aNewRefLabel))
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())
413 addShapeIntoDoc (theTools, aSubShapeIter.Value(), aNewRefLabel, aDummyName);
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())
422 const TopoDS_Shape& aSubShape = aSubShapeIter.Value();
423 if (myAttribMap.Find (aSubShape.Located (TopLoc_Location()), aSubShapeAttribs))
425 addSubShapeIntoDoc (theTools, aSubShape, aNewRefLabel, aSubShapeAttribs);
429 return Standard_True;
432 // =======================================================================
433 // function : addSubShapeIntoDoc
435 // =======================================================================
436 Standard_Boolean RWMesh_CafReader::addSubShapeIntoDoc (CafDocumentTools& theTools,
437 const TopoDS_Shape& theShape,
438 const TDF_Label& theParentLabel,
439 const RWMesh_NodeAttributes& theAttribs)
441 if (theShape.IsNull()
442 || myXdeDoc.IsNull())
444 return Standard_False;
447 const TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
448 TDF_Label aNewLabel = theTools.ShapeTool->AddSubShape (theParentLabel, theShape);
449 if (aNewLabel.IsNull())
451 return Standard_False;
455 Handle(XCAFDoc_ShapeMapTool) aShapeMapTool = XCAFDoc_ShapeMapTool::Set (aNewLabel);
456 aShapeMapTool->SetShape (theShape);
459 // if new label is a reference get referred shape
460 TDF_Label aNewRefLabel = aNewLabel;
461 theTools.ShapeTool->GetReferredShape (aNewLabel, aNewRefLabel);
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);
469 RWMesh_NodeAttributes aSubShapeAttribs;
470 for (TopoDS_Iterator aSubShapeIter (theShape, Standard_True, Standard_False); aSubShapeIter.More(); aSubShapeIter.Next())
472 const TopoDS_Shape& aSubShape = aSubShapeIter.Value();
473 if (myAttribMap.Find (aSubShape.Located (TopLoc_Location()), aSubShapeAttribs))
475 addSubShapeIntoDoc (theTools, aSubShape, theParentLabel, aSubShapeAttribs);
478 return Standard_True;
481 // =======================================================================
482 // function : generateNames
484 // =======================================================================
485 void RWMesh_CafReader::generateNames (const TCollection_AsciiString& theFile,
486 const Standard_Integer theRootLower,
487 const Standard_Boolean theWithSubLabels)
489 if (myXdeDoc.IsNull())
494 TCollection_AsciiString aDummyFolder, aFileName;
495 OSD_Path::FolderAndFileFromPath (theFile, aDummyFolder, aFileName);
496 const TCollection_AsciiString aRootName = myRootPrefix + aFileName;
498 Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main());
499 TDF_LabelSequence aRootLabels;
500 aShapeTool->GetFreeShapes (aRootLabels);
501 if (aRootLabels.Upper() < theRootLower)
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())
512 if (aRootIndex < theRootLower)
516 else if (theWithSubLabels)
518 aNewRootLabels.Append (aRootIter.Value());
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))
526 TDataStd_Name::Set (aRefLab, aRootName);
528 if (aLabel != aRefLab
529 && !aLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName))
531 TDataStd_Name::Set (aLabel, aRootName);
535 if (theWithSubLabels)
537 for (XCAFPrs_DocumentExplorer aDocIter (myXdeDoc, aNewRootLabels, XCAFPrs_DocumentExplorerFlags_NoStyle);
538 aDocIter.More(); aDocIter.Next())
540 if (aDocIter.CurrentDepth() == 0
541 || aDocIter.Current().RefLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName))
546 const TopoDS_Shape aShape = XCAFDoc_ShapeTool::GetShape (aDocIter.Current().RefLabel);
547 if (!aShape.IsNull())
549 TDataStd_Name::Set (aDocIter.Current().RefLabel, shapeTypeToString (aShape.ShapeType()));