]> OCCT Git - occt.git/commitdiff
0033737: Data Exchange, XCAF - Implementing filter tree functionality
authorPasukhin Dmitry <44947322+dpasukhi@users.noreply.github.com>
Fri, 5 Jul 2024 13:28:39 +0000 (15:28 +0200)
committerPasukhin Dmitry <44947322+dpasukhi@users.noreply.github.com>
Mon, 8 Jul 2024 15:28:00 +0000 (17:28 +0200)
Implemented base functionality to filter tree with input label to keep.

src/XCAFDoc/XCAFDoc_Editor.cxx
src/XCAFDoc/XCAFDoc_Editor.hxx
src/XDEDRAW/XDEDRAW_Common.cxx
tests/bugs/xde/bug33737 [new file with mode: 0644]

index e76fcedf4d728ed501a4ca0f3344932495cef2f2..8d3d5747983bbda0176bfdbfe3c375ed44434446 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <BRep_Builder.hxx>
 #include <BRepBuilderAPI_Transform.hxx>
+#include <NCollection_IncAllocator.hxx>
 #include <Message.hxx>
 #include <XCAFDoc.hxx>
 #include <XCAFDimTolObjects_DatumObject.hxx>
@@ -582,12 +583,115 @@ static Standard_Boolean shouldRescaleAndCheckRefLabels(
   return aShouldRescale;
 }
 
+//=======================================================================
+//function : GetChildShapeLabels
+//purpose  :
+//=======================================================================
+void XCAFDoc_Editor::GetChildShapeLabels(const TDF_Label& theLabel,
+                                         TDF_LabelMap& theRelatedLabels)
+{
+  if (theLabel.IsNull() || !XCAFDoc_ShapeTool::IsShape(theLabel))
+  {
+    return;
+  }
+  if (!theRelatedLabels.Add(theLabel))
+  {
+    return; // Label already processed
+  }
+  if (XCAFDoc_ShapeTool::IsAssembly(theLabel) ||
+      XCAFDoc_ShapeTool::IsSimpleShape(theLabel))
+  {
+    for(TDF_ChildIterator aChildIter(theLabel); aChildIter.More(); aChildIter.Next())
+    {
+      const TDF_Label& aChildLabel = aChildIter.Value();
+      GetChildShapeLabels(aChildLabel, theRelatedLabels);
+    }
+  }
+  if (XCAFDoc_ShapeTool::IsReference(theLabel))
+  {
+    TDF_Label aRefLabel;
+    XCAFDoc_ShapeTool::GetReferredShape(theLabel, aRefLabel);
+    GetChildShapeLabels(aRefLabel, theRelatedLabels);
+  }
+}
+
+//=======================================================================
+//function : GetParentShapeLabels
+//purpose  :
+//=======================================================================
+void XCAFDoc_Editor::GetParentShapeLabels(const TDF_Label& theLabel,
+                                          TDF_LabelMap& theRelatedLabels)
+{
+  if (theLabel.IsNull() || !XCAFDoc_ShapeTool::IsShape(theLabel))
+  {
+    return;
+  }
+  if (!theRelatedLabels.Add(theLabel))
+  {
+    return; // Label already processed
+  }
+  if (XCAFDoc_ShapeTool::IsSubShape(theLabel) ||
+      XCAFDoc_ShapeTool::IsComponent(theLabel))
+  {
+    TDF_Label aFatherLabel = theLabel.Father();
+    GetParentShapeLabels(aFatherLabel, theRelatedLabels);
+  }
+  else
+  {
+    TDF_LabelSequence aUsers;
+    XCAFDoc_ShapeTool::GetUsers(theLabel, aUsers);
+    if (!aUsers.IsEmpty())
+    {
+      for (TDF_LabelSequence::Iterator aUserIter(aUsers); aUserIter.More(); aUserIter.Next())
+      {
+        const TDF_Label& aUserLabel = aUserIter.Value();
+        GetParentShapeLabels(aUserLabel, theRelatedLabels);
+      }
+    }
+  }
+}
+
+//=======================================================================
+//function : FilterShapeTree
+//purpose  :
+//=======================================================================
+bool XCAFDoc_Editor::FilterShapeTree(const Handle(XCAFDoc_ShapeTool)& theShapeTool,
+                                     const TDF_LabelMap& theLabelsToKeep)
+{
+  if (theLabelsToKeep.IsEmpty())
+  {
+    return false;
+  }
+  Handle(NCollection_BaseAllocator) anAllocator = new NCollection_IncAllocator();
+  TDF_LabelMap aLabelsToKeep (theLabelsToKeep.Size(), anAllocator);
+  for (TDF_LabelMap::Iterator aLabelIter (theLabelsToKeep); aLabelIter.More(); aLabelIter.Next())
+  {
+    GetChildShapeLabels (aLabelIter.Key(), aLabelsToKeep);
+  }
+  TDF_LabelMap aInternalLabels (1, anAllocator);
+  for (TDF_LabelMap::Iterator aLabelIter (theLabelsToKeep); aLabelIter.More(); aLabelIter.Next())
+  {
+    GetParentShapeLabels (aLabelIter.Key(), aInternalLabels);
+    aLabelsToKeep.Unite(aInternalLabels);
+    aInternalLabels.Clear(false);
+  }
+  for(TDF_ChildIterator aLabelIter (theShapeTool->Label(), true); aLabelIter.More(); aLabelIter.Next())
+  {
+    const TDF_Label& aLabel = aLabelIter.Value();
+    if (!aLabelsToKeep.Contains (aLabel))
+    {
+      aLabel.ForgetAllAttributes (Standard_False);
+    }
+  }
+  theShapeTool->UpdateAssemblies();
+  return true;
+}
+
 //=======================================================================
 //function : RescaleGeometry
 //purpose  : Applies geometrical scale to all assembly parts, component
 //           locations and related attributes
 //=======================================================================
-
 Standard_Boolean XCAFDoc_Editor::RescaleGeometry(const TDF_Label& theLabel,
                                                  const Standard_Real theScaleFactor,
                                                  const Standard_Boolean theForceIfNotRoot)
index 832d522d2d297116c5834f4707f11e07ac38ed8c..5c7e38064fc5535e85a722bb2f85aa4b11825bfe 100644 (file)
@@ -19,6 +19,7 @@
 #include <TDataStd_Name.hxx>
 #include <TDF_Label.hxx>
 #include <TDF_LabelDataMap.hxx>
+#include <TDF_LabelMap.hxx>
 #include <TDF_LabelSequence.hxx>
 
 class XCAFDoc_VisMaterial;
@@ -95,6 +96,34 @@ public:
                                             const Standard_Boolean theToCopyVisMaterial = Standard_True,
                                             const Standard_Boolean theToCopyAttributes = Standard_True);
 
+  //! Gets shape labels that has down relation with the input label.
+  //! @param[in] theLabel input label
+  //! @param[out] theRelatedLabels output labels
+  Standard_EXPORT static void GetParentShapeLabels(const TDF_Label& theLabel,
+                                                   TDF_LabelMap& theRelatedLabels);
+
+  //! Gets shape labels that has up relation with the input label.
+  //! @param[in] theLabel input label
+  //! @param[out] theRelatedLabels output labels
+  Standard_EXPORT static void GetChildShapeLabels(const TDF_Label& theLabel,
+                                                  TDF_LabelMap& theRelatedLabels);
+
+  //! Filters original shape tree with keeping structure.
+  //! The result will include the full label hierarchy lower then input labels.
+  //! Any higher hierarchy labels will be filtered to keep only necessary labels.
+  //! All not related shape labels with input will be cleared (all attributes will be removed).
+  //!
+  //! The result impact directly into original document and existed shape labels.
+  //! Attributes related to removed shape can became invalide.
+  //! For example, GDT with relation on removed shape label(s) and without
+  //! attachment point(s) became invalid for visualization.
+  //!
+  //! @param[in] theShapeTool shape tool to extract from
+  //! @param[in] theLabelsToKeep labels to keep
+  //! @return true if the tree was filtered successfully.
+  Standard_EXPORT static bool FilterShapeTree(const Handle(XCAFDoc_ShapeTool)& theShapeTool,
+                                              const TDF_LabelMap& theLabelsToKeep);
+
   //! Applies geometrical scaling to the following assembly components:
   //! - part geometry
   //! - sub-assembly/part occurrence location
index d4f9e82d99dcd3321175db0201df4e62cc3c65ec..0cf4c5269371aa8e5e4ea0fa6ed4735f2f546507 100644 (file)
@@ -263,6 +263,53 @@ static Standard_Integer Extract(Draw_Interpretor& theDI,
   return 0;
 }
 
+//=======================================================================
+//function : Filter
+//purpose  :
+//=======================================================================
+static Standard_Integer Filter(Draw_Interpretor& theDI,
+                                Standard_Integer theNbArgs,
+                                const char** theArgVec)
+{
+  if (theNbArgs < 3)
+  {
+    theDI << "Use: " << theArgVec[0] << "Doc label1 label2 ...\n";
+    return 1;
+  }
+
+  Handle(TDocStd_Document) aDoc;
+  DDocStd::GetDocument(theArgVec[1], aDoc);
+  if (aDoc.IsNull())
+  {
+    theDI << "Error " << theArgVec[1] << " is not a document\n";
+    return 1;
+  }
+  TDF_LabelMap aSrcShapes;
+  for (Standard_Integer anArgInd = 2; anArgInd < theNbArgs; anArgInd++)
+  {
+    TDF_Label aSrcLabel;
+    TDF_Tool::Label(aDoc->GetData(), theArgVec[anArgInd], aSrcLabel);
+    if (aSrcLabel.IsNull() || !XCAFDoc_ShapeTool::IsShape(aSrcLabel))
+    {
+      theDI << "[" << theArgVec[anArgInd] << "] is not valid shape label\n";
+      return 1;
+    }
+    aSrcShapes.Add(aSrcLabel);
+  }
+  if (aSrcShapes.IsEmpty())
+  {
+    theDI << "Error: No Shapes to keep\n";
+    return 1;
+  }
+  Handle(XCAFDoc_ShapeTool) aShTool = XCAFDoc_DocumentTool::ShapeTool(aDoc->Main());
+  if (!XCAFDoc_Editor::FilterShapeTree(aShTool, aSrcShapes))
+  {
+    theDI << "Error: Cannot filter shape tree. Document can be corrupted\n";
+    return 1;
+  }
+  return 0;
+}
+
 //=======================================================================
 //function : InitCommands
 //purpose  :
@@ -288,7 +335,9 @@ void XDEDRAW_Common::InitCommands(Draw_Interpretor& theDI)
   theDI.Add("XExtract", "XExtract dstDoc [dstAssmblSh] srcDoc srcLabel1 srcLabel2 ...\t"
             "Extracts given srcLabel1 srcLabel2 ... from srcDoc into given Doc or assembly shape",
             __FILE__, Extract, aGroup);
-
+  theDI.Add("XShapeTreeFilter", "XShapeTreeFilter Doc label1 label2 ...\t"
+            "Removes not related labels with input labels from original document. Hierarchical structure is kept",
+            __FILE__, Filter, aGroup);
   // Load XSDRAW session for pilot activation
   XSDRAW::LoadDraw(theDI);
 }
diff --git a/tests/bugs/xde/bug33737 b/tests/bugs/xde/bug33737
new file mode 100644 (file)
index 0000000..563cf66
--- /dev/null
@@ -0,0 +1,61 @@
+puts "========"
+puts " 0033737: Data Exchange, XCAF - Implementing filter tree functionality"
+puts "========"
+
+pload DE OCAF
+
+Close D_orig D_part1 D_part2 D_part3 D_part4 D_part5 -silent
+
+# get original shape
+Close D_orig -silent
+XOpen [locate_data_file bug28905_as1-oc-214.xbf] D_orig
+XGetOneShape sh_orig D_orig
+
+# any bolt inside assembly
+Close D_orig D_part1 -silent
+XOpen [locate_data_file bug28905_as1-oc-214.xbf] D_part1
+XShapeTreeFilter D_part1 "0:1:1:7"
+XGetOneShape sh1 D_part1
+
+# rod
+Close D_part1 D_part2 -silent
+XOpen [locate_data_file bug28905_as1-oc-214.xbf] D_part2
+XShapeTreeFilter D_part2 "0:1:1:2:3"
+XGetOneShape sh2 D_part2
+
+# plate
+Close D_part2 D_part3 -silent
+XOpen [locate_data_file bug28905_as1-oc-214.xbf] D_part3
+XShapeTreeFilter D_part3 "0:1:1:1:3"
+XGetOneShape sh3 D_part3
+
+# any nuts
+Close D_part3 D_part4 -silent
+XOpen [locate_data_file bug28905_as1-oc-214.xbf] D_part4
+XShapeTreeFilter D_part4 "0:1:1:3"
+XGetOneShape sh4 D_part4
+
+# any nuts
+Close D_part4 D_part5 -silent
+XOpen [locate_data_file bug28905_as1-oc-214.xbf] D_part5
+XShapeTreeFilter D_part5 "0:1:1:8"
+XGetOneShape sh5 D_part5
+
+Close D_part5 -silent
+
+compound sh1 sh2 sh3 sh4 sh5 comp
+
+set props_orig [vprops sh_orig]
+set props_comp [vprops comp]
+
+checkprops sh_orig -equal comp
+
+if { ![regexp {Center of gravity[^0-9=]+= +([-0-9.+eE]+)[^0-9=]+= +([-0-9.+eE]+)[^0-9=]+= +([-0-9.+eE]+)} $props_orig full x_orig y_orig z_orig] } {
+  puts "Error: Problem with properties calculation"
+}
+if { ![regexp {Center of gravity[^0-9=]+= +([-0-9.+eE]+)[^0-9=]+= +([-0-9.+eE]+)[^0-9=]+= +([-0-9.+eE]+)} $props_comp full x_comp y_comp z_comp] } {
+  puts "Error: Problem with properties calculation"
+}
+if {$x_orig != $x_comp || $y_orig != $y_comp || $z_orig != $z_comp} {
+  puts "Error: Different center of gravity"
+}