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_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>
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 void RWMesh_CafReader::SetDocument(const Handle(TDocStd_Document)& theDoc)
64 Standard_Real aScaleFactorM = 1.;
65 if (XCAFDoc_DocumentTool::GetLengthUnit(theDoc, aScaleFactorM))
67 SetSystemLengthUnit(aScaleFactorM);
71 // =======================================================================
72 // function : SingleShape
74 // =======================================================================
75 TopoDS_Shape RWMesh_CafReader::SingleShape() const
77 if (myRootShapes.Size() > 1)
79 BRep_Builder aBuilder;
80 TopoDS_Compound aCompound;
81 aBuilder.MakeCompound (aCompound);
82 for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next())
84 aBuilder.Add (aCompound, aRootIter.Value());
88 else if (!myRootShapes.IsEmpty())
90 return myRootShapes.First();
92 return TopoDS_Shape();
95 // =======================================================================
98 // =======================================================================
99 Standard_Boolean RWMesh_CafReader::perform (const TCollection_AsciiString& theFile,
100 const Message_ProgressRange& theProgress,
101 const Standard_Boolean theToProbe)
103 Standard_Integer aNewRootsLower = 1;
104 if (!myXdeDoc.IsNull())
106 TDF_LabelSequence aRootLabels;
107 XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main())->GetFreeShapes (aRootLabels);
108 aNewRootsLower = aRootLabels.Upper() + 1;
111 OSD_Timer aLoadingTimer;
112 aLoadingTimer.Start();
113 const Standard_Boolean isDone = performMesh (theFile, theProgress, theToProbe);
114 if (theToProbe || theProgress.UserBreak())
120 if (!myToFillIncomplete)
122 return Standard_False;
125 myExtraStatus |= RWMesh_CafReaderStatusEx_Partial;
128 TopLoc_Location aDummyLoc;
129 Standard_Integer aNbNodes = 0, aNbElems = 0, aNbFaces = 0;
130 for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next())
132 for (TopExp_Explorer aFaceIter (aRootIter.Value(), TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
134 const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Current());
135 if (const Handle(Poly_Triangulation)& aPolyTri = BRep_Tool::Triangulation (aFace, aDummyLoc))
138 aNbNodes += aPolyTri->NbNodes();
139 aNbElems += aPolyTri->NbTriangles();
143 if (!isDone && aNbElems < 100)
145 return Standard_False;
149 generateNames (theFile, aNewRootsLower, Standard_False);
151 aLoadingTimer.Stop();
153 Message::SendInfo (TCollection_AsciiString ("Mesh ") + theFile
154 + "\n[" + aNbNodes + " nodes] [" + aNbElems + " 2d elements]"
155 + "\n[" + (!isDone ? "PARTIALLY " : "") + "read in " + aLoadingTimer.ElapsedTime() + " s]");
156 return Standard_True;
159 // =======================================================================
160 // function : fillDocument
162 // =======================================================================
163 void RWMesh_CafReader::fillDocument()
167 || myRootShapes.IsEmpty())
173 Standard_Real aLengthUnit = 1.;
174 if (!XCAFDoc_DocumentTool::GetLengthUnit(myXdeDoc, aLengthUnit))
176 XCAFDoc_DocumentTool::SetLengthUnit(myXdeDoc, SystemLengthUnit());
178 else if (aLengthUnit != SystemLengthUnit())
180 Message::SendWarning("Warning: Length unit of document not equal to the system length unit");
183 const Standard_Boolean wasAutoNaming = XCAFDoc_ShapeTool::AutoNaming();
184 XCAFDoc_ShapeTool::SetAutoNaming (Standard_False);
185 const TCollection_AsciiString aRootName; // = generateRootName (theFile);
186 CafDocumentTools aTools;
187 aTools.ShapeTool = XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main());
188 aTools.ColorTool = XCAFDoc_DocumentTool::ColorTool (myXdeDoc->Main());
189 aTools.VisMaterialTool = XCAFDoc_DocumentTool::VisMaterialTool (myXdeDoc->Main());
190 for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next())
192 addShapeIntoDoc (aTools, aRootIter.Value(), TDF_Label(), aRootName);
194 XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main())->UpdateAssemblies();
195 XCAFDoc_ShapeTool::SetAutoNaming (wasAutoNaming);
198 // =======================================================================
199 // function : setShapeName
201 // =======================================================================
202 void RWMesh_CafReader::setShapeName (const TDF_Label& theLabel,
203 const TopAbs_ShapeEnum theShapeType,
204 const TCollection_AsciiString& theName,
205 const TDF_Label& theParentLabel,
206 const TCollection_AsciiString& theParentName)
208 if (!theName.IsEmpty())
210 TDataStd_Name::Set (theLabel, theName);
212 else if (!theParentLabel.IsNull())
214 TDataStd_Name::Set (theLabel, shapeTypeToString (theShapeType));
216 else if (theParentLabel.IsNull()
217 && !theParentName.IsEmpty())
219 TDataStd_Name::Set (theLabel, theParentName);
223 // =======================================================================
224 // function : setShapeStyle
226 // =======================================================================
227 void RWMesh_CafReader::setShapeStyle (const CafDocumentTools& theTools,
228 const TDF_Label& theLabel,
229 const XCAFPrs_Style& theStyle)
231 if (theStyle.IsSetColorSurf())
233 theTools.ColorTool->SetColor (theLabel, theStyle.GetColorSurfRGBA(), XCAFDoc_ColorSurf);
235 if (theStyle.IsSetColorCurv())
237 theTools.ColorTool->SetColor (theLabel, theStyle.GetColorCurv(), XCAFDoc_ColorCurv);
239 if (!theStyle.Material().IsNull())
241 TDF_Label aMaterialLabel = theStyle.Material()->Label();
242 if (aMaterialLabel.IsNull())
244 const TCollection_AsciiString aMatName = !theStyle.Material()->RawName().IsNull()
245 ? theStyle.Material()->RawName()->String()
247 aMaterialLabel = theTools.VisMaterialTool->AddMaterial (theStyle.Material(), aMatName);
249 theTools.VisMaterialTool->SetShapeMaterial (theLabel, aMaterialLabel);
253 // =======================================================================
254 // function : setShapeNamedData
256 // =======================================================================
257 void RWMesh_CafReader::setShapeNamedData (const CafDocumentTools& ,
258 const TDF_Label& theLabel,
259 const Handle(TDataStd_NamedData)& theNameData)
261 if (theNameData.IsNull())
266 const TDF_Label aNameDataLabel = theNameData->Label();
267 Handle(TDataStd_NamedData) anOtherNamedData;
268 if (theLabel.FindAttribute (theNameData->ID(), anOtherNamedData))
270 if (anOtherNamedData->Label() != aNameDataLabel)
272 Message::SendAlarm ("Error! Different NamedData is already set to shape");
277 if (aNameDataLabel.IsNull())
279 theLabel.AddAttribute (theNameData);
283 Message::SendAlarm ("Error! Skipped NamedData instance shared across shapes");
288 // =======================================================================
289 // function : addShapeIntoDoc
291 // =======================================================================
292 Standard_Boolean RWMesh_CafReader::addShapeIntoDoc (CafDocumentTools& theTools,
293 const TopoDS_Shape& theShape,
294 const TDF_Label& theLabel,
295 const TCollection_AsciiString& theParentName)
297 if (theShape.IsNull()
298 || myXdeDoc.IsNull())
300 return Standard_False;
303 const TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
304 TopoDS_Shape aShapeToAdd = theShape;
305 const TopoDS_Shape aShapeNoLoc = theShape.Located (TopLoc_Location());
306 Standard_Boolean toMakeAssembly = Standard_False;
307 if (theShape.ShapeType() == TopAbs_COMPOUND)
309 RWMesh_NodeAttributes aSubFaceAttribs;
310 for (TopoDS_Iterator aSubShapeIter (theShape, Standard_True, Standard_False); !toMakeAssembly && aSubShapeIter.More(); aSubShapeIter.Next())
312 if (aSubShapeIter.Value().ShapeType() != TopAbs_FACE)
314 toMakeAssembly = Standard_True;
318 const TopoDS_Face& aFace = TopoDS::Face (aSubShapeIter.Value());
319 toMakeAssembly = toMakeAssembly
320 || (myAttribMap.Find (aFace, aSubFaceAttribs) && !aSubFaceAttribs.Name.IsEmpty());
325 // create an empty Compound to add as assembly, so that we can add children one-by-one via AddComponent()
326 TopoDS_Compound aCompound;
327 BRep_Builder aBuilder;
328 aBuilder.MakeCompound (aCompound);
329 aCompound.Location (theShape.Location(), Standard_False);
330 aShapeToAdd = aCompound;
334 TDF_Label aNewLabel, anOldLabel;
335 if (theLabel.IsNull())
338 aNewLabel = theTools.ShapeTool->AddShape (aShapeToAdd, toMakeAssembly);
340 else if (theTools.ShapeTool->IsAssembly (theLabel))
342 // add shape as component
343 if (theTools.ComponentMap.Find (aShapeNoLoc, anOldLabel))
345 aNewLabel = theTools.ShapeTool->AddComponent (theLabel, anOldLabel, theShape.Location());
349 aNewLabel = theTools.ShapeTool->AddComponent (theLabel, aShapeToAdd, toMakeAssembly);
351 TDF_Label aRefLabel = aNewLabel;
352 theTools.ShapeTool->GetReferredShape (aNewLabel, aRefLabel);
353 if (!aRefLabel.IsNull())
355 theTools.ComponentMap.Bind (aShapeNoLoc, aRefLabel);
361 // add shape as sub-shape
362 aNewLabel = theTools.ShapeTool->AddSubShape (theLabel, theShape);
363 if (!aNewLabel.IsNull())
365 Handle(XCAFDoc_ShapeMapTool) aShapeMapTool = XCAFDoc_ShapeMapTool::Set (aNewLabel);
366 aShapeMapTool->SetShape (theShape);
369 if (aNewLabel.IsNull())
371 return Standard_False;
374 // if new label is a reference get referred shape
375 TDF_Label aNewRefLabel = aNewLabel;
376 theTools.ShapeTool->GetReferredShape (aNewLabel, aNewRefLabel);
378 RWMesh_NodeAttributes aRefShapeAttribs;
379 myAttribMap.Find (aShapeNoLoc, aRefShapeAttribs);
381 bool hasProductName = false;
382 if (aNewLabel != aNewRefLabel)
384 // put attributes to the Instance (overrides Product attributes)
385 RWMesh_NodeAttributes aShapeAttribs;
386 if (!theShape.Location().IsIdentity()
387 && myAttribMap.Find (theShape, aShapeAttribs))
389 if (!aShapeAttribs.Style.IsEqual (aRefShapeAttribs.Style))
391 setShapeStyle (theTools, aNewLabel, aShapeAttribs.Style);
393 if (aShapeAttribs.NamedData != aRefShapeAttribs.NamedData)
395 setShapeNamedData (theTools, aNewLabel, aShapeAttribs.NamedData);
397 setShapeName (aNewLabel, aShapeType, aShapeAttribs.Name, theLabel, theParentName);
398 if (aRefShapeAttribs.Name.IsEmpty()
399 && !aShapeAttribs.Name.IsEmpty())
401 // it is not nice having unnamed Product, so copy name from first Instance (probably the only one)
402 hasProductName = true;
403 setShapeName (aNewRefLabel, aShapeType, aShapeAttribs.Name, theLabel, theParentName);
405 else if (aShapeAttribs.Name.IsEmpty()
406 && !aRefShapeAttribs.Name.IsEmpty())
408 // copy name from Product
409 setShapeName (aNewLabel, aShapeType, aRefShapeAttribs.Name, theLabel, theParentName);
414 // copy name from Product
415 setShapeName (aNewLabel, aShapeType, aRefShapeAttribs.Name, theLabel, theParentName);
419 if (!anOldLabel.IsNull())
421 // already defined in the document
422 return Standard_True;
425 // put attributes to the Product (shared across Instances)
428 setShapeName (aNewRefLabel, aShapeType, aRefShapeAttribs.Name, theLabel, theParentName);
430 setShapeStyle (theTools, aNewRefLabel, aRefShapeAttribs.Style);
431 setShapeNamedData (theTools, aNewRefLabel, aRefShapeAttribs.NamedData);
433 if (theTools.ShapeTool->IsAssembly (aNewRefLabel))
435 // store sub-shapes (iterator is set to not inherit Location of parent object)
436 TCollection_AsciiString aDummyName;
437 for (TopoDS_Iterator aSubShapeIter (theShape, Standard_True, Standard_False); aSubShapeIter.More(); aSubShapeIter.Next())
439 addShapeIntoDoc (theTools, aSubShapeIter.Value(), aNewRefLabel, aDummyName);
444 // store a plain list of sub-shapes in case if they have custom attributes (usually per-face color)
445 for (TopoDS_Iterator aSubShapeIter (theShape, Standard_True, Standard_False); aSubShapeIter.More(); aSubShapeIter.Next())
447 addSubShapeIntoDoc(theTools, aSubShapeIter.Value(), aNewRefLabel);
450 return Standard_True;
453 // =======================================================================
454 // function : addSubShapeIntoDoc
456 // =======================================================================
457 Standard_Boolean RWMesh_CafReader::addSubShapeIntoDoc (CafDocumentTools& theTools,
458 const TopoDS_Shape& theShape,
459 const TDF_Label& theParentLabel)
461 if (theShape.IsNull()
462 || myXdeDoc.IsNull())
464 return Standard_False;
467 RWMesh_NodeAttributes aShapeAttribs;
468 const TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
469 const Standard_Boolean aHasAttribs = myAttribMap.Find(theShape.Located(TopLoc_Location()), aShapeAttribs);
471 // check for the attribute
472 // shell or wire may not contain an attribute, but its subshapes need to be checked
473 if (!aHasAttribs && aShapeType != TopAbs_SHELL &&
474 aShapeType != TopAbs_WIRE)
476 return Standard_False;
479 for (TopoDS_Iterator aSubShapeIter(theShape, Standard_True, Standard_False); aSubShapeIter.More(); aSubShapeIter.Next())
481 addSubShapeIntoDoc(theTools, aSubShapeIter.Value(), theParentLabel);
486 return Standard_False;
489 TDF_Label aNewLabel = theTools.ShapeTool->AddSubShape (theParentLabel, theShape);
490 if (aNewLabel.IsNull())
492 return Standard_False;
495 Handle(XCAFDoc_ShapeMapTool) aShapeMapTool = XCAFDoc_ShapeMapTool::Set(aNewLabel);
496 aShapeMapTool->SetShape(theShape);
498 // if new label is a reference get referred shape
499 TDF_Label aNewRefLabel = aNewLabel;
500 theTools.ShapeTool->GetReferredShape (aNewLabel, aNewRefLabel);
502 // put attributes to the Product (shared across Instances)
503 static const TCollection_AsciiString anEmptyString;
504 setShapeName (aNewRefLabel, aShapeType, aShapeAttribs.Name, TDF_Label(), anEmptyString);
505 setShapeStyle (theTools, aNewRefLabel, aShapeAttribs.Style);
506 setShapeNamedData (theTools, aNewRefLabel, aShapeAttribs.NamedData);
508 return Standard_True;
511 // =======================================================================
512 // function : generateNames
514 // =======================================================================
515 void RWMesh_CafReader::generateNames (const TCollection_AsciiString& theFile,
516 const Standard_Integer theRootLower,
517 const Standard_Boolean theWithSubLabels)
519 if (myXdeDoc.IsNull())
524 TCollection_AsciiString aDummyFolder, aFileName;
525 OSD_Path::FolderAndFileFromPath (theFile, aDummyFolder, aFileName);
526 const TCollection_AsciiString aRootName = myRootPrefix + aFileName;
528 Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main());
529 TDF_LabelSequence aRootLabels;
530 aShapeTool->GetFreeShapes (aRootLabels);
531 if (aRootLabels.Upper() < theRootLower)
536 // replace empty names
537 Handle(TDataStd_Name) aNodeName;
538 Standard_Integer aRootIndex = aRootLabels.Lower();
539 TDF_LabelSequence aNewRootLabels;
540 for (TDF_LabelSequence::Iterator aRootIter (aRootLabels); aRootIter.More(); ++aRootIndex, aRootIter.Next())
542 if (aRootIndex < theRootLower)
546 else if (theWithSubLabels)
548 aNewRootLabels.Append (aRootIter.Value());
551 const TDF_Label aLabel = aRootIter.Value();
552 TDF_Label aRefLab = aLabel;
553 XCAFDoc_ShapeTool::GetReferredShape (aLabel, aRefLab);
554 if (!aRefLab.FindAttribute (TDataStd_Name::GetID(), aNodeName))
556 TDataStd_Name::Set (aRefLab, aRootName);
558 if (aLabel != aRefLab
559 && !aLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName))
561 TDataStd_Name::Set (aLabel, aRootName);
565 if (theWithSubLabels)
567 for (XCAFPrs_DocumentExplorer aDocIter (myXdeDoc, aNewRootLabels, XCAFPrs_DocumentExplorerFlags_NoStyle);
568 aDocIter.More(); aDocIter.Next())
570 if (aDocIter.CurrentDepth() == 0
571 || aDocIter.Current().RefLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName))
576 const TopoDS_Shape aShape = XCAFDoc_ShapeTool::GetShape (aDocIter.Current().RefLabel);
577 if (!aShape.IsNull())
579 TDataStd_Name::Set (aDocIter.Current().RefLabel, shapeTypeToString (aShape.ShapeType()));