From 433bd375f35a109ece7f42f7255d6970d4085cc6 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Fri, 5 Aug 2016 23:49:11 +0300 Subject: [PATCH] Part: make Fusion and Common able to fuse arrays If Fusion or Common features get only one argument, and the shape is a compound, the children of the compound are treated as list of arguments. --- src/Mod/Part/App/FeaturePartCommon.cpp | 42 +++++++++++++++++++++ src/Mod/Part/App/FeaturePartFuse.cpp | 43 ++++++++++++++++++++++ src/Mod/Part/App/PropertyTopoShape.h | 4 ++ src/Mod/Part/Gui/Command.cpp | 51 +++++++++++++++++++++++--- 4 files changed, 134 insertions(+), 6 deletions(-) diff --git a/src/Mod/Part/App/FeaturePartCommon.cpp b/src/Mod/Part/App/FeaturePartCommon.cpp index cb1338e05..61d03fb4f 100644 --- a/src/Mod/Part/App/FeaturePartCommon.cpp +++ b/src/Mod/Part/App/FeaturePartCommon.cpp @@ -27,6 +27,9 @@ # include # include # include +# include +# include +# include #endif @@ -84,6 +87,23 @@ App::DocumentObjectExecReturn *MultiCommon::execute(void) } } + bool argumentsAreInCompound = false; + TopoDS_Shape compoundOfArguments; + + //if only one source shape, and it is a compound - fuse children of the compound + if (s.size() == 1){ + compoundOfArguments = s[0]; + if (compoundOfArguments.ShapeType() == TopAbs_COMPOUND){ + s.clear(); + TopoDS_Iterator it(compoundOfArguments); + for (; it.More(); it.Next()) { + const TopoDS_Shape& aChild = it.Value(); + s.push_back(aChild); + } + argumentsAreInCompound = true; + } + } + if (s.size() >= 2) { try { std::vector history; @@ -129,6 +149,28 @@ App::DocumentObjectExecReturn *MultiCommon::execute(void) } this->Shape.setValue(resShape); + + if (argumentsAreInCompound){ + //combine histories of every child of source compound into one + ShapeHistory overallHist; + TopTools_IndexedMapOfShape facesOfCompound; + TopAbs_ShapeEnum type = TopAbs_FACE; + TopExp::MapShapes(compoundOfArguments, type, facesOfCompound); + for (int iChild = 0; iChild < history.size(); iChild++){ //loop over children of source compound + //for each face of a child, find the inex of the face in compound, and assign the corresponding right-hand-size of the history + TopTools_IndexedMapOfShape facesOfChild; + TopExp::MapShapes(s[iChild], type, facesOfChild); + for(std::pair &histitem: history[iChild].shapeMap){ //loop over elements of history - that is - over faces of the child of source compound + int iFaceInChild = histitem.first; + ShapeHistory::List &iFacesInResult = histitem.second; + TopoDS_Shape srcFace = facesOfChild(iFaceInChild + 1); //+1 to convert our 0-based to OCC 1-bsed conventions + int iFaceInCompound = facesOfCompound.FindIndex(srcFace)-1; + overallHist.shapeMap[iFaceInCompound] = iFacesInResult; //this may overwrite existing info if the same face is used in several children of compound. This shouldn't be a problem, because the histories should match anyway... + } + } + history.clear(); + history.push_back(overallHist); + } this->History.setValues(history); } catch (Standard_Failure) { diff --git a/src/Mod/Part/App/FeaturePartFuse.cpp b/src/Mod/Part/App/FeaturePartFuse.cpp index 5dd11b4b8..13ebe2212 100644 --- a/src/Mod/Part/App/FeaturePartFuse.cpp +++ b/src/Mod/Part/App/FeaturePartFuse.cpp @@ -26,6 +26,9 @@ # include # include # include +# include +# include +# include #endif @@ -83,6 +86,23 @@ App::DocumentObjectExecReturn *MultiFuse::execute(void) } } + bool argumentsAreInCompound = false; + TopoDS_Shape compoundOfArguments; + + //if only one source shape, and it is a compound - fuse children of the compound + if (s.size() == 1){ + compoundOfArguments = s[0]; + if (compoundOfArguments.ShapeType() == TopAbs_COMPOUND){ + s.clear(); + TopoDS_Iterator it(compoundOfArguments); + for (; it.More(); it.Next()) { + const TopoDS_Shape& aChild = it.Value(); + s.push_back(aChild); + } + argumentsAreInCompound = true; + } + } + if (s.size() >= 2) { try { std::vector history; @@ -153,6 +173,29 @@ App::DocumentObjectExecReturn *MultiFuse::execute(void) } this->Shape.setValue(resShape); + + + if (argumentsAreInCompound){ + //combine histories of every child of source compound into one + ShapeHistory overallHist; + TopTools_IndexedMapOfShape facesOfCompound; + TopAbs_ShapeEnum type = TopAbs_FACE; + TopExp::MapShapes(compoundOfArguments, type, facesOfCompound); + for (int iChild = 0; iChild < history.size(); iChild++){ //loop over children of source compound + //for each face of a child, find the inex of the face in compound, and assign the corresponding right-hand-size of the history + TopTools_IndexedMapOfShape facesOfChild; + TopExp::MapShapes(s[iChild], type, facesOfChild); + for(std::pair &histitem: history[iChild].shapeMap){ //loop over elements of history - that is - over faces of the child of source compound + int iFaceInChild = histitem.first; + ShapeHistory::List &iFacesInResult = histitem.second; + TopoDS_Shape srcFace = facesOfChild(iFaceInChild + 1); //+1 to convert our 0-based to OCC 1-bsed conventions + int iFaceInCompound = facesOfCompound.FindIndex(srcFace)-1; + overallHist.shapeMap[iFaceInCompound] = iFacesInResult; //this may overwrite existing info if the same face is used in several children of compound. This shouldn't be a problem, because the histories should match anyway... + } + } + history.clear(); + history.push_back(overallHist); + } this->History.setValues(history); } catch (Standard_Failure) { diff --git a/src/Mod/Part/App/PropertyTopoShape.h b/src/Mod/Part/App/PropertyTopoShape.h index e08eb41d3..1b85f8e4b 100644 --- a/src/Mod/Part/App/PropertyTopoShape.h +++ b/src/Mod/Part/App/PropertyTopoShape.h @@ -96,6 +96,10 @@ private: }; struct PartExport ShapeHistory { + /** + * @brief MapList: key is index of subshape (of type 'type') in source + * shape. Value is list of indexes of subshapes in result shape. + */ typedef std::map > MapList; typedef std::vector List; diff --git a/src/Mod/Part/Gui/Command.cpp b/src/Mod/Part/Gui/Command.cpp index 2bc1fc21c..b7a4acfaa 100644 --- a/src/Mod/Part/Gui/Command.cpp +++ b/src/Mod/Part/Gui/Command.cpp @@ -34,6 +34,7 @@ # include # include # include +# include #endif #include @@ -350,9 +351,28 @@ CmdPartCommon::CmdPartCommon() void CmdPartCommon::activated(int iMsg) { std::vector Sel = getSelection().getSelectionEx(0, Part::Feature::getClassTypeId()); - if (Sel.size() < 2) { + + //test if selected object is a compound, and if it is, look how many children it has... + int numShapes = 0; + if (Sel.size() == 1){ + numShapes = 1; //to be updated later in code, if + Gui::SelectionObject selobj = Sel[0]; + if (selobj.getObject()->isDerivedFrom(Part::Feature::getClassTypeId())){ + TopoDS_Shape sh = static_cast(selobj.getObject())->Shape.getValue(); + if (sh.ShapeType() == TopAbs_COMPOUND) { + numShapes = 0; + TopoDS_Iterator it(sh); + for (; it.More(); it.Next()) { + ++numShapes; + } + } + } + } else { + numShapes = Sel.size(); + } + if (numShapes < 2) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select two shapes or more, please.")); + QObject::tr("Select two shapes or more, please. Or, select one compound containing two or more shapes to compute common between.")); return; } @@ -409,7 +429,7 @@ void CmdPartCommon::activated(int iMsg) bool CmdPartCommon::isActive(void) { - return getSelection().countObjectsOfType(Part::Feature::getClassTypeId())>=2; + return getSelection().countObjectsOfType(Part::Feature::getClassTypeId())>=1; } //=========================================================================== @@ -432,9 +452,28 @@ CmdPartFuse::CmdPartFuse() void CmdPartFuse::activated(int iMsg) { std::vector Sel = getSelection().getSelectionEx(0, Part::Feature::getClassTypeId()); - if (Sel.size() < 2) { + + //test if selected object is a compound, and if it is, look how many children it has... + int numShapes = 0; + if (Sel.size() == 1){ + numShapes = 1; //to be updated later in code + Gui::SelectionObject selobj = Sel[0]; + if (selobj.getObject()->isDerivedFrom(Part::Feature::getClassTypeId())){ + TopoDS_Shape sh = static_cast(selobj.getObject())->Shape.getValue(); + if (sh.ShapeType() == TopAbs_COMPOUND) { + numShapes = 0; + TopoDS_Iterator it(sh); + for (; it.More(); it.Next()) { + ++numShapes; + } + } + } + } else { + numShapes = Sel.size(); + } + if (numShapes < 2) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select two shapes or more, please.")); + QObject::tr("Select two shapes or more, please. Or, select one compound containing two or more shapes to be fused.")); return; } @@ -491,7 +530,7 @@ void CmdPartFuse::activated(int iMsg) bool CmdPartFuse::isActive(void) { - return getSelection().countObjectsOfType(Part::Feature::getClassTypeId())>=2; + return getSelection().countObjectsOfType(Part::Feature::getClassTypeId())>=1; } //===========================================================================