0030692: Data Exchange - introduce base framework RWMesh for importing mesh data...
[occt.git] / src / RWMesh / RWMesh_CafReader.cxx
diff --git a/src/RWMesh/RWMesh_CafReader.cxx b/src/RWMesh/RWMesh_CafReader.cxx
new file mode 100644 (file)
index 0000000..6db946c
--- /dev/null
@@ -0,0 +1,387 @@
+// Author: Kirill Gavrilov
+// Copyright (c) 2016-2019 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <RWMesh_CafReader.hxx>
+
+#include <XCAFPrs_DocumentExplorer.hxx>
+
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <Message_ProgressIndicator.hxx>
+#include <BRep_Builder.hxx>
+#include <OSD_Path.hxx>
+#include <OSD_Timer.hxx>
+#include <TDataStd_Name.hxx>
+#include <TDocStd_Document.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Iterator.hxx>
+#include <XCAFDoc_ColorTool.hxx>
+#include <XCAFDoc_ColorType.hxx>
+#include <XCAFDoc_DocumentTool.hxx>
+#include <XCAFDoc_ShapeMapTool.hxx>
+#include <XCAFDoc_ShapeTool.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(RWMesh_CafReader, Standard_Transient)
+
+// =======================================================================
+// function : RWMesh_CafReader
+// purpose  :
+// =======================================================================
+RWMesh_CafReader::RWMesh_CafReader()
+: myToFillDoc (Standard_True),
+  myToFillIncomplete (Standard_True),
+  myMemoryLimitMiB (-1),
+  myExtraStatus (RWMesh_CafReaderStatusEx_NONE)
+{
+  //
+}
+
+// =======================================================================
+// function : ~RWMesh_CafReader
+// purpose  :
+// =======================================================================
+RWMesh_CafReader::~RWMesh_CafReader()
+{
+  //
+}
+
+// =======================================================================
+// function : SingleShape
+// purpose  :
+// =======================================================================
+TopoDS_Shape RWMesh_CafReader::SingleShape() const
+{
+  if (myRootShapes.Size() > 1)
+  {
+    BRep_Builder aBuilder;
+    TopoDS_Compound aCompound;
+    aBuilder.MakeCompound (aCompound);
+    for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next())
+    {
+      aBuilder.Add (aCompound, aRootIter.Value());
+    }
+    return aCompound;
+  }
+  else if (!myRootShapes.IsEmpty())
+  {
+    return myRootShapes.First();
+  }
+  return TopoDS_Shape();
+}
+
+// =======================================================================
+// function : perform
+// purpose  :
+// =======================================================================
+Standard_Boolean RWMesh_CafReader::perform (const TCollection_AsciiString& theFile,
+                                            const Handle(Message_ProgressIndicator)& theProgress,
+                                            const Standard_Boolean theToProbe)
+{
+  Standard_Integer aNewRootsLower = 1;
+  Handle(XCAFDoc_ShapeTool) aShapeTool = !myXdeDoc.IsNull()
+                                       ? XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main())
+                                       : Handle(XCAFDoc_ShapeTool)();
+  if (!myXdeDoc.IsNull())
+  {
+    TDF_LabelSequence aRootLabels;
+    aShapeTool->GetFreeShapes (aRootLabels);
+    aNewRootsLower = aRootLabels.Upper() + 1;
+  }
+
+  OSD_Timer aLoadingTimer;
+  aLoadingTimer.Start();
+  const Standard_Boolean isDone = performMesh (theFile, theProgress, theToProbe);
+  if (theToProbe
+   || (!theProgress.IsNull() && theProgress->UserBreak()))
+  {
+    return isDone;
+  }
+  else if (!isDone)
+  {
+    if (!myToFillIncomplete)
+    {
+      return Standard_False;
+    }
+
+    myExtraStatus |= RWMesh_CafReaderStatusEx_Partial;
+  }
+
+  BRep_Builder aBuilder;
+  TopoDS_Shape aShape;
+  if (myRootShapes.Size() > 1)
+  {
+    TopoDS_Compound aCompound;
+    aBuilder.MakeCompound (aCompound);
+    for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next())
+    {
+      aBuilder.Add (aCompound, aRootIter.Value());
+    }
+    aShape = aCompound;
+  }
+  else if (!myRootShapes.IsEmpty())
+  {
+    aShape = myRootShapes.First();
+  }
+
+  Standard_Integer aNbNodes = 0, aNbElems = 0, aNbFaces = 0;
+  if (!aShape.IsNull())
+  {
+    TopLoc_Location aDummyLoc;
+    for (TopExp_Explorer aFaceIter (aShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
+    {
+      const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Current());
+      if (const Handle(Poly_Triangulation)& aPolyTri = BRep_Tool::Triangulation (aFace, aDummyLoc))
+      {
+        ++aNbFaces;
+        aNbNodes += aPolyTri->NbNodes();
+        aNbElems += aPolyTri->NbTriangles();
+      }
+    }
+  }
+  if (!isDone && aNbElems < 100)
+  {
+    return Standard_False;
+  }
+
+  if (myToFillDoc
+  && !myXdeDoc.IsNull())
+  {
+    const Standard_Boolean wasAutoNaming = aShapeTool->AutoNaming();
+    aShapeTool->SetAutoNaming (Standard_False);
+    const TCollection_AsciiString aRootName; // = generateRootName (theFile);
+    for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next())
+    {
+      addShapeIntoDoc (aRootIter.Value(), TDF_Label(), aRootName);
+    }
+    aShapeTool->UpdateAssemblies();
+    aShapeTool->SetAutoNaming (wasAutoNaming);
+  }
+  if (!myXdeDoc.IsNull())
+  {
+    generateNames (theFile, aNewRootsLower, Standard_False);
+  }
+
+  aLoadingTimer.Stop();
+
+  TCollection_AsciiString aStats = TCollection_AsciiString("[") + aNbNodes + " nodes] [" + aNbElems + " 2d elements]";
+  if (!isDone)
+  {
+    Message::DefaultMessenger()->Send (TCollection_AsciiString ("Mesh ") + theFile
+                                     + "\n" + aStats
+                                     + "\n[PARTIALLY read in " + aLoadingTimer.ElapsedTime() + " s]", Message_Info);
+  }
+  else
+  {
+    Message::DefaultMessenger()->Send (TCollection_AsciiString ("Mesh ") + theFile
+                                     + "\n" + aStats
+                                     + "\n[read in " + aLoadingTimer.ElapsedTime() + " s]", Message_Info);
+  }
+  return Standard_True;
+}
+
+// =======================================================================
+// function : addShapeIntoDoc
+// purpose  :
+// =======================================================================
+Standard_Boolean RWMesh_CafReader::addShapeIntoDoc (const TopoDS_Shape& theShape,
+                                                    const TDF_Label& theLabel,
+                                                    const TCollection_AsciiString& theParentName)
+{
+  if (theShape.IsNull()
+   || myXdeDoc.IsNull())
+  {
+    return Standard_False;
+  }
+
+  Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main());
+
+  TopLoc_Location aDummyLoc;
+
+  const TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
+  TopoDS_Shape aShapeToAdd = theShape;
+  Standard_Boolean toMakeAssembly = Standard_False;
+  if (theShape.ShapeType() == TopAbs_COMPOUND)
+  {
+    TCollection_AsciiString aFirstName;
+    RWMesh_NodeAttributes aSubFaceAttribs;
+    for (TopoDS_Iterator aSubShapeIter (theShape, Standard_True, Standard_False); !toMakeAssembly && aSubShapeIter.More(); aSubShapeIter.Next())
+    {
+      if (aSubShapeIter.Value().ShapeType() != TopAbs_FACE)
+      {
+        toMakeAssembly = Standard_True;
+        break;
+      }
+
+      const TopoDS_Face& aFace = TopoDS::Face (aSubShapeIter.Value());
+      toMakeAssembly = toMakeAssembly
+                    || (myAttribMap.Find (aFace, aSubFaceAttribs) && !aSubFaceAttribs.Name.IsEmpty());
+    }
+
+    // create empty compound to add as assembly
+    if (toMakeAssembly)
+    {
+      TopoDS_Compound aCompound;
+      BRep_Builder aBuilder;
+      aBuilder.MakeCompound (aCompound);
+      aCompound.Location (theShape.Location());
+      aShapeToAdd = aCompound;
+    }
+  }
+
+  TDF_Label aNewLabel;
+  if (theLabel.IsNull())
+  {
+    // add new shape
+    aNewLabel = aShapeTool->AddShape (aShapeToAdd, toMakeAssembly);
+  }
+  else if (aShapeTool->IsAssembly (theLabel))
+  {
+    // add shape as component
+    aNewLabel = aShapeTool->AddComponent (theLabel, aShapeToAdd, toMakeAssembly);
+  }
+  else
+  {
+    // add shape as sub-shape
+    aNewLabel = aShapeTool->AddSubShape (theLabel, theShape);
+    if (!aNewLabel.IsNull())
+    {
+      Handle(XCAFDoc_ShapeMapTool) aShapeMapTool = XCAFDoc_ShapeMapTool::Set (aNewLabel);
+      aShapeMapTool->SetShape (theShape);
+    }
+  }
+  if (aNewLabel.IsNull())
+  {
+    return Standard_False;
+  }
+
+  // if new label is a reference get referred shape
+  TDF_Label aNewRefLabel = aNewLabel;
+  aShapeTool->GetReferredShape (aNewLabel, aNewRefLabel);
+
+  // store name
+  RWMesh_NodeAttributes aShapeAttribs;
+  myAttribMap.Find (theShape, aShapeAttribs);
+  if (aShapeAttribs.Name.IsEmpty())
+  {
+    if (theLabel.IsNull())
+    {
+      aShapeAttribs.Name = theParentName;
+    }
+    if (aShapeAttribs.Name.IsEmpty()
+    && !theLabel.IsNull())
+    {
+      aShapeAttribs.Name = shapeTypeToString (aShapeType);
+    }
+  }
+  if (!aShapeAttribs.Name.IsEmpty())
+  {
+    TDataStd_Name::Set (aNewRefLabel, aShapeAttribs.Name);
+  }
+
+  // store color
+  Handle(XCAFDoc_ColorTool) aColorTool = XCAFDoc_DocumentTool::ColorTool (myXdeDoc->Main());
+  if (aShapeAttribs.Style.IsSetColorSurf())
+  {
+    aColorTool->SetColor (aNewRefLabel, aShapeAttribs.Style.GetColorSurfRGBA(), XCAFDoc_ColorSurf);
+  }
+  if (aShapeAttribs.Style.IsSetColorCurv())
+  {
+    aColorTool->SetColor (aNewRefLabel, aShapeAttribs.Style.GetColorCurv(), XCAFDoc_ColorCurv);
+  }
+
+  // store sub-shapes (iterator is set to ignore Location)
+  TCollection_AsciiString aDummyName;
+  for (TopoDS_Iterator aSubShapeIter (theShape, Standard_True, Standard_False); aSubShapeIter.More(); aSubShapeIter.Next())
+  {
+    addShapeIntoDoc (aSubShapeIter.Value(), aNewRefLabel, aDummyName);
+  }
+  return Standard_True;
+}
+
+// =======================================================================
+// function : generateNames
+// purpose  :
+// =======================================================================
+void RWMesh_CafReader::generateNames (const TCollection_AsciiString& theFile,
+                                      const Standard_Integer theRootLower,
+                                      const Standard_Boolean theWithSubLabels)
+{
+  if (myXdeDoc.IsNull())
+  {
+    return;
+  }
+
+  TCollection_AsciiString aDummyFolder, aFileName;
+  OSD_Path::FolderAndFileFromPath (theFile, aDummyFolder, aFileName);
+  const TCollection_AsciiString aRootName = myRootPrefix + aFileName;
+
+  Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main());
+  TDF_LabelSequence aRootLabels;
+  aShapeTool->GetFreeShapes (aRootLabels);
+  if (aRootLabels.Upper() < theRootLower)
+  {
+    return;
+  }
+
+  // replace empty names
+  Handle(TDataStd_Name) aNodeName;
+  Standard_Integer aRootIndex = aRootLabels.Lower();
+  TDF_LabelSequence aNewRootLabels;
+  for (TDF_LabelSequence::Iterator aRootIter (aRootLabels); aRootIter.More(); ++aRootIndex, aRootIter.Next())
+  {
+    if (aRootIndex < theRootLower)
+    {
+      continue;
+    }
+    else if (theWithSubLabels)
+    {
+      aNewRootLabels.Append (aRootIter.Value());
+    }
+
+    const TDF_Label aLabel = aRootIter.Value();
+    TDF_Label aRefLab = aLabel;
+    XCAFDoc_ShapeTool::GetReferredShape (aLabel, aRefLab);
+    if (!aRefLab.FindAttribute (TDataStd_Name::GetID(), aNodeName))
+    {
+      TDataStd_Name::Set (aRefLab, aRootName);
+    }
+    if (aLabel != aRefLab
+    && !aLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName))
+    {
+      TDataStd_Name::Set (aLabel, aRootName);
+    }
+  }
+
+  if (theWithSubLabels)
+  {
+    for (XCAFPrs_DocumentExplorer aDocIter (myXdeDoc,
+                                            aNewRootLabels,
+                                            XCAFPrs_DocumentExplorerFlags_OnlyLeafNodes | XCAFPrs_DocumentExplorerFlags_NoStyle);
+         aDocIter.More(); aDocIter.Next())
+    {
+      if (aDocIter.CurrentDepth() == 0
+       || aDocIter.Current().RefLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName))
+      {
+        continue;
+      }
+
+      const TopoDS_Shape aShape = XCAFDoc_ShapeTool::GetShape (aDocIter.Current().RefLabel);
+      if (!aShape.IsNull())
+      {
+        TDataStd_Name::Set (aDocIter.Current().RefLabel, shapeTypeToString (aShape.ShapeType()));
+      }
+    }
+  }
+}