diff --git a/src/XCAFDoc/XCAFDoc_Editor.cxx b/src/XCAFDoc/XCAFDoc_Editor.cxx index e76fcedf4d..0a7b359be6 100644 --- a/src/XCAFDoc/XCAFDoc_Editor.cxx +++ b/src/XCAFDoc/XCAFDoc_Editor.cxx @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -582,12 +583,119 @@ static Standard_Boolean shouldRescaleAndCheckRefLabels( return aShouldRescale; } +//======================================================================= +//function : GetDownRelatedShapeLabels +//purpose : +//======================================================================= +bool XCAFDoc_Editor::GetDownRelatedShapeLabels(const TDF_Label& theLabel, + TDF_LabelMap& theRelatedLabels) +{ + if (theLabel.IsNull() || !XCAFDoc_ShapeTool::IsShape(theLabel)) + { + return false; + } + if (theRelatedLabels.Contains(theLabel)) + { + return true; + } + theRelatedLabels.Add(theLabel); + if (XCAFDoc_ShapeTool::IsAssembly(theLabel) || + XCAFDoc_ShapeTool::IsSimpleShape(theLabel)) + { + for(TDF_ChildIterator aChildIter(theLabel); aChildIter.More(); aChildIter.Next()) + { + const TDF_Label& aChildLabel = aChildIter.Value(); + GetDownRelatedShapeLabels(aChildLabel, theRelatedLabels); + } + } + if (XCAFDoc_ShapeTool::IsReference(theLabel)) + { + TDF_Label aRefLabel; + XCAFDoc_ShapeTool::GetReferredShape(theLabel, aRefLabel); + GetDownRelatedShapeLabels(aRefLabel, theRelatedLabels); + } + return true; +} + +//======================================================================= +//function : GetUpRelatedShapeLabels +//purpose : +//======================================================================= +bool XCAFDoc_Editor::GetUpRelatedShapeLabels(const TDF_Label& theLabel, + TDF_LabelMap& theRelatedLabels) +{ + if (theLabel.IsNull() || !XCAFDoc_ShapeTool::IsShape(theLabel)) + { + return false; + } + if (theRelatedLabels.Contains(theLabel)) + { + return true; + } + theRelatedLabels.Add(theLabel); + if (XCAFDoc_ShapeTool::IsSubShape(theLabel) || + XCAFDoc_ShapeTool::IsComponent(theLabel)) + { + TDF_Label aFatherLabel = theLabel.Father(); + GetUpRelatedShapeLabels(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(); + GetUpRelatedShapeLabels(aUserLabel, theRelatedLabels); + } + } + } + return true; +} + +//======================================================================= +//function : FilterTree +//purpose : +//======================================================================= +bool XCAFDoc_Editor::FilterTree(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()) + { + GetDownRelatedShapeLabels (aLabelIter.Key(), aLabelsToKeep); + } + TDF_LabelMap aInternalLabels (1, anAllocator); + for (TDF_LabelMap::Iterator aLabelIter (theLabelsToKeep); aLabelIter.More(); aLabelIter.Next()) + { + GetUpRelatedShapeLabels (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) diff --git a/src/XCAFDoc/XCAFDoc_Editor.hxx b/src/XCAFDoc/XCAFDoc_Editor.hxx index 832d522d2d..9873de31d6 100644 --- a/src/XCAFDoc/XCAFDoc_Editor.hxx +++ b/src/XCAFDoc/XCAFDoc_Editor.hxx @@ -19,6 +19,7 @@ #include #include #include +#include #include class XCAFDoc_VisMaterial; @@ -95,6 +96,32 @@ 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 + //! @return true if labels successfully extracted + Standard_EXPORT static bool GetUpRelatedShapeLabels(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 + //! @return true if labels successfully extracted + Standard_EXPORT static bool GetDownRelatedShapeLabels(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. + //! + //! @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 FilterTree(const Handle(XCAFDoc_ShapeTool)& theShapeTool, + const TDF_LabelMap& theLabelsToKeep); + //! Applies geometrical scaling to the following assembly components: //! - part geometry //! - sub-assembly/part occurrence location diff --git a/src/XDEDRAW/XDEDRAW_Common.cxx b/src/XDEDRAW/XDEDRAW_Common.cxx index d4f9e82d99..65ff968719 100644 --- a/src/XDEDRAW/XDEDRAW_Common.cxx +++ b/src/XDEDRAW/XDEDRAW_Common.cxx @@ -263,6 +263,53 @@ static Standard_Integer Extract(Draw_Interpretor& theDI, return 0; } +//======================================================================= +//function : Extract +//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::FilterTree(aShTool, aSrcShapes)) + { + theDI << "Error: Cannot filter 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("XFilter", "XFilter 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 index 0000000000..dde1d5fb10 --- /dev/null +++ b/tests/bugs/xde/bug33737 @@ -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 +XFilter 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 +XFilter 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 +XFilter 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 +XFilter 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 +XFilter 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" +}