FeaturesAPI_Translation.h
FeaturesAPI_Union.h
FeaturesAPI_FusionFaces.h
+ FeaturesAPI_Copy.h
)
SET(PROJECT_SOURCES
FeaturesAPI_Translation.cpp
FeaturesAPI_Union.cpp
FeaturesAPI_FusionFaces.cpp
+ FeaturesAPI_Copy.cpp
)
SET(PROJECT_LIBRARIES
%shared_ptr(FeaturesAPI_Union)
%shared_ptr(FeaturesAPI_FusionFaces)
%shared_ptr(FeaturesAPI_RemoveResults)
+%shared_ptr(FeaturesAPI_Copy)
%typecheck(SWIG_TYPECHECK_POINTER) std::pair<std::list<ModelHighAPI_Selection>, bool>, const std::pair<std::list<ModelHighAPI_Selection>, bool> & {
%include "FeaturesAPI_Union.h"
%include "FeaturesAPI_FusionFaces.h"
%include "FeaturesAPI_RemoveResults.h"
+%include "FeaturesAPI_Copy.h"
--- /dev/null
+// Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "FeaturesAPI_Copy.h"
+
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Tools.h>
+
+//================================================================================================
+FeaturesAPI_Copy::FeaturesAPI_Copy(const std::shared_ptr<ModelAPI_Feature>& theFeature)
+: ModelHighAPI_Interface(theFeature)
+{
+ initialize();
+}
+
+//================================================================================================
+FeaturesAPI_Copy::FeaturesAPI_Copy(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theObjects,
+ const int theNumber)
+: ModelHighAPI_Interface(theFeature)
+{
+ if(initialize()) {
+ setNumber(theNumber);
+ setObjects(theObjects);
+ }
+}
+
+//================================================================================================
+FeaturesAPI_Copy::~FeaturesAPI_Copy() {}
+
+//=================================================================================================
+void FeaturesAPI_Copy::setObjects(const std::list<ModelHighAPI_Selection>& theObjects)
+{
+ fillAttribute(theObjects, myobjects);
+ execute();
+}
+//=================================================================================================
+void FeaturesAPI_Copy::setNumber(const int theNumber)
+{
+ fillAttribute(theNumber, mynumber);
+ execute();
+}
+
+//=================================================================================================
+void FeaturesAPI_Copy::dump(ModelHighAPI_Dumper& theDumper) const
+{
+ FeaturePtr aBase = feature();
+ const std::string& aDocName = theDumper.name(aBase->document());
+
+ AttributeSelectionListPtr anObjects = aBase->selectionList(FeaturesPlugin_Copy::OBJECTS());
+ AttributeIntegerPtr aNumber = aBase->integer(FeaturesPlugin_Copy::NUMBER());
+
+ theDumper << aBase << " = model.addCopy("
+ << aDocName << ", " << anObjects << ", " << aNumber << ")" << std::endl;
+}
+
+//=================================================================================================
+CopyPtr addCopy(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const std::list<ModelHighAPI_Selection>& theObjects,
+ const int theNumber)
+{
+ std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_Copy::ID());
+ return CopyPtr(new FeaturesAPI_Copy(aFeature, theObjects, theNumber));
+}
--- /dev/null
+// Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef FeaturesAPI_Copy_H_
+#define FeaturesAPI_Copy_H_
+
+#include "FeaturesAPI.h"
+
+#include <FeaturesPlugin_Copy.h>
+
+#include <ModelHighAPI_Interface.h>
+#include <ModelHighAPI_Macro.h>
+
+class ModelHighAPI_Dumper;
+class ModelHighAPI_Selection;
+
+/// \class FeaturesAPI_Copy
+/// \ingroup CPPHighAPI
+/// \brief Interface for Copy feature.
+class FeaturesAPI_Copy: public ModelHighAPI_Interface
+{
+public:
+ /// Constructor without values.
+ FEATURESAPI_EXPORT
+ explicit FeaturesAPI_Copy(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+ /// Constructor with values.
+ FEATURESAPI_EXPORT
+ explicit FeaturesAPI_Copy(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theBaseObjects,
+ const int theVersion = 0);
+
+ /// Destructor.
+ FEATURESAPI_EXPORT virtual ~FeaturesAPI_Copy();
+
+ INTERFACE_2(FeaturesPlugin_Copy::ID(),
+ objects, FeaturesPlugin_Copy::OBJECTS(),
+ ModelAPI_AttributeSelectionList, /** Source objects */,
+ number, FeaturesPlugin_Copy::NUMBER(),
+ ModelAPI_AttributeInteger, /** Number of copies */)
+
+ /// Modify objects attribute of the feature.
+ FEATURESAPI_EXPORT void setObjects(const std::list<ModelHighAPI_Selection>& theBaseObjects);
+
+ /// Modify number of copies attribute of the feature.
+ FEATURESAPI_EXPORT void setNumber(const int theNumber);
+
+ /// Dump wrapped feature
+ FEATURESAPI_EXPORT virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+};
+
+/// Pointer on Copy object.
+typedef std::shared_ptr<FeaturesAPI_Copy> CopyPtr;
+
+/// \ingroup CPPHighAPI
+/// \brief Create Copy feature.
+FEATURESAPI_EXPORT
+CopyPtr addCopy(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const std::list<ModelHighAPI_Selection>& theObjects,
+ const int theNumber);
+
+#endif // FeaturesAPI_Copy_H_
#include "FeaturesAPI_Union.h"
#include "FeaturesAPI_FusionFaces.h"
#include "FeaturesAPI_RemoveResults.h"
+ #include "FeaturesAPI_Copy.h"
#endif // FeaturesAPI_swig_H_
FeaturesPlugin_FusionFaces.h
FeaturesPlugin_RemoveResults.h
FeaturesPlugin_Chamfer.h
+ FeaturesPlugin_Copy.h
)
SET(PROJECT_SOURCES
FeaturesPlugin_FusionFaces.cpp
FeaturesPlugin_RemoveResults.cpp
FeaturesPlugin_Chamfer.cpp
+ FeaturesPlugin_Copy.cpp
)
SET(XML_RESOURCES
measurement_widget.xml
fusion_faces_widget.xml
chamfer_widget.xml
+ copy_widget.xml
)
SET(TEXT_RESOURCES
Test3033.py
Test3076.py
Test17909.py
+ TestCopyFeature.py
+ TestCopyFeatureMoveGroupOfFeature.py
+ TestCopyMoveResult.py
+ TestCopyMoveSubShapes.py
+ TestCopyNames.py
+ TestCopySubShapes.py
+ TestCopyWholeFeature.py
)
--- /dev/null
+// Copyright (C) 2017-2019 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "FeaturesPlugin_Copy.h"
+
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_Tools.h>
+
+#include <GeomAlgoAPI_Copy.h>
+#include <GeomAlgoAPI_Tools.h>
+#include <GeomAPI_ShapeExplorer.h>
+
+#include <sstream>
+
+void FeaturesPlugin_Copy::initAttributes()
+{
+ data()->addAttribute(OBJECTS(), ModelAPI_AttributeSelectionList::typeId());
+ data()->addAttribute(NUMBER(), ModelAPI_AttributeInteger::typeId());
+}
+
+static GeomShapePtr shapeOfSelection(AttributeSelectionPtr theSel) {
+ GeomShapePtr aResult;
+ FeaturePtr aSelFeature = theSel->contextFeature();
+ if (aSelFeature.get()) {
+ if (aSelFeature->results().empty()) // if selected feature has no results, make nothing
+ return aResult;
+ if (aSelFeature->results().size() == 1) { // for one sub-result don't make compound
+ aResult = aSelFeature->firstResult()->shape();
+ }
+ }
+ if (!aResult.get())
+ aResult = theSel->value();
+ if (!aResult.get()) {
+ if (theSel->context().get())
+ aResult = theSel->context()->shape();
+ }
+ return aResult;
+}
+
+void FeaturesPlugin_Copy::execute()
+{
+ int aCopiesNum = integer(NUMBER())->value();
+ AttributeSelectionListPtr aList = selectionList(OBJECTS());
+ int aResultIndex = 0;
+ std::set<std::string> anExistingNames; // to avoid names duplication
+ for(int aCopy = 0; aCopy < aCopiesNum; aCopy++) {
+ for (int aSelIndex = 0; aSelIndex < aList->size(); aSelIndex++) {
+ AttributeSelectionPtr aSel = aList->value(aSelIndex);
+ GeomShapePtr aShape = shapeOfSelection(aSel);
+ if (!aShape.get())
+ continue;
+ std::shared_ptr<GeomAlgoAPI_Copy> aCopyBuilder(new GeomAlgoAPI_Copy(aShape, false, false));
+ std::string anError;
+ if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCopyBuilder, getKind(), anError)) {
+ setError(anError);
+ return;
+ }
+ GeomShapePtr aResult = aCopyBuilder->shape();
+
+ std::string aBaseName = aSel->context() ? aSel->context()->data()->name() :
+ aSel->contextFeature()->firstResult()->data()->name();
+ std::string aName;
+ int anInd = 0;
+ do {
+ anInd++;
+ std::ostringstream aNameStr;
+ aNameStr << aBaseName << "_" << (aCopy + anInd);
+ aName = aNameStr.str();
+ } while (anExistingNames.count(aName));
+ anExistingNames.insert(aName);
+
+ std::shared_ptr<ModelAPI_ResultBody> aResultBody =
+ document()->createBody(data(), aResultIndex);
+ aResultBody->data()->setName(aName);
+ // to make sub-results also names with a similar name temporarily rename the feature
+ std::string anOrigName = name();
+ data()->setName(aBaseName);
+ aResultBody->store(aResult);
+ data()->setName(anOrigName);
+ aResultBody->loadFirstLevel(aResult, "Copy");
+ setResult(aResultBody, aResultIndex++);
+ }
+ }
+ removeResults(aResultIndex);
+}
+
+void FeaturesPlugin_Copy::getCopies(
+ ObjectPtr theContext, std::shared_ptr<GeomAPI_Shape> theValue,
+ std::list<ObjectPtr>& theCopyContext, std::list<std::shared_ptr<GeomAPI_Shape> >& theCopyVals)
+{
+ ResultPtr aContextRes = std::dynamic_pointer_cast<ModelAPI_Result>(theContext);
+ GeomShapePtr aGroupValue = theValue.get() ? theValue : aContextRes->shape();
+
+ AttributeSelectionListPtr aList = selectionList(OBJECTS());
+ std::list<ResultPtr>::const_iterator aResIter = results().cbegin();
+ while(aResIter != results().cend()) { // do as long as many iterations
+ for (int aSelIndex = 0; aSelIndex < aList->size(); aSelIndex++) {
+ if (aResIter == results().cend()) // no more results corresponding to the selection
+ return;
+ AttributeSelectionPtr aSel = aList->value(aSelIndex);
+ GeomShapePtr aShape = shapeOfSelection(aSel);
+ if (!aShape.get())
+ continue;
+
+ if (aShape->isSubShape(aGroupValue, false)) { // group value is subshape of copied => copy
+ // search the same result in the copy by the same index of sub-shape in the shape
+ GeomAPI_ShapeExplorer anOrigExp(aShape, aGroupValue->shapeType());
+ GeomAPI_ShapeExplorer aCopyShape((*aResIter)->shape(), aGroupValue->shapeType());
+ for(; anOrigExp.more(); anOrigExp.next(), aCopyShape.next()) {
+ if (anOrigExp.current()->isSame(aGroupValue)) {
+ // searching for sub-result if it is composite result, but context-not
+ ResultPtr aResContext = *aResIter;
+ if (aContextRes->shape()->shapeType() > (*aResIter)->shape()->shapeType()) {
+ ResultBodyPtr aResBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResContext);
+ if (aResBody.get()) {
+ std::list<ResultPtr> aSubs;
+ ModelAPI_Tools::allSubs(aResBody, aSubs, true);
+ std::list<ResultPtr>::iterator aSubIter = aSubs.begin();
+ for(; aSubIter != aSubs.end(); aSubIter++) {
+ GeomShapePtr aSubShape = (*aSubIter)->shape();
+ if (aSubShape.get() && aSubShape->isSubShape(aCopyShape.current(), false)) {
+ aResContext = *aSubIter;
+ break;
+ }
+ }
+ }
+ }
+ theCopyContext.push_back(aResContext);
+ theCopyVals.push_back(aResContext->shape()->isSame(
+ aCopyShape.current()) ? GeomShapePtr() : aCopyShape.current());
+ break;
+ }
+ }
+ }
+ aResIter++;
+ }
+ }
+}
--- /dev/null
+// Copyright (C) 2017-2019 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef FeaturesPlugin_Copy_H_
+#define FeaturesPlugin_Copy_H_
+
+#include "FeaturesPlugin.h"
+
+#include <ModelAPI_Feature.h>
+
+/// \class FeaturesPlugin_Copy
+/// \ingroup Plugins
+/// \brief This feature copies the selected results and sub-results (for the whole feature selected
+/// all results of this feature are copied). The referenced arguments of this feature are
+/// not concealed. The difference with \94Recover\94 feature is that not concealed results may
+/// be selected and in the history behavior: the \93Move to the End\94 of groups will move to
+/// all copy-results.
+
+class FeaturesPlugin_Copy : public ModelAPI_Feature, public ModelAPI_FeatureCopyInterface
+{
+public:
+ /// Feature kind.
+ inline static const std::string& ID()
+ {
+ static const std::string MY_ID("Copy");
+ return MY_ID;
+ }
+
+ /// \return the kind of a feature.
+ FEATURESPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = FeaturesPlugin_Copy::ID();
+ return MY_KIND;
+ }
+
+ /// Selection list attribute that contains all copied shapes selection.
+ inline static const std::string& OBJECTS()
+ {
+ static const std::string MY_OBJECTS("objects");
+ return MY_OBJECTS;
+ }
+ /// Integer attribute that contains the number of resulting copies needed
+ inline static const std::string NUMBER()
+ {
+ static std::string MY_NUMBER("number");
+ return MY_NUMBER;
+ }
+
+ /// Performs the algorithm and stores results it in the data structure.
+ FEATURESPLUGIN_EXPORT virtual void execute();
+
+ /// Request for initialization of data model of the feature: adding all attributes.
+ FEATURESPLUGIN_EXPORT virtual void initAttributes();
+
+ /// To update the group feature which is moved over this copy feature (to add copies to selection)
+ FEATURESPLUGIN_EXPORT virtual void getCopies(
+ ObjectPtr theContext, std::shared_ptr<GeomAPI_Shape> theValue,
+ std::list<ObjectPtr>& theCopyContext, std::list<std::shared_ptr<GeomAPI_Shape> >& theCopyVals);
+
+ /// Use plugin manager for features creation.
+ FeaturesPlugin_Copy() {}
+};
+
+#endif
#include <FeaturesPlugin_Union.h>
#include <FeaturesPlugin_FusionFaces.h>
#include <FeaturesPlugin_RemoveResults.h>
+#include <FeaturesPlugin_Copy.h>
#include <FeaturesPlugin_ValidatorTransform.h>
#include <FeaturesPlugin_Validators.h>
return FeaturePtr(new FeaturesPlugin_RemoveResults);
} else if (theFeatureID == FeaturesPlugin_Chamfer::ID()) {
return FeaturePtr(new FeaturesPlugin_Chamfer);
+ } else if (theFeatureID == FeaturesPlugin_Copy::ID()) {
+ return FeaturePtr(new FeaturesPlugin_Copy);
}
+
// feature of such kind is not found
return FeaturePtr();
}
--- /dev/null
+# Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+# Checks selection of the whole featurte and move to the end of the group created on results of this feature..
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(11.02869497636673, 9.8764247475525, 3.312248077480665)
+SketchCircle_2 = Sketch_1.addCircle(4.278198729238611, 4.677840612715367, 1.794922837237287)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1")], model.selection(), 10, 0)
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("SOLID", "Extrusion_1_1"), model.selection("SOLID", "Extrusion_1_2")])
+Copy_1 = model.addCopy(Part_1_doc, [model.selection("COMPOUND", "all-in-Extrusion_1")], 1)
+model.do()
+# move the group feature to the end - through copy of the whole feature
+Part_1_doc.moveFeature(Group_1.feature(), Copy_1.feature())
+model.end()
+
+from ModelAPI import *
+aFactory = ModelAPI_Session.get().validators()
+assert(aFactory.validate(Group_1.feature()))
+selectionList = Group_1.feature().selectionList("group_list")
+assert(selectionList.size() == 4) # two original solids plus two copies
+assert(selectionList.value(3).namingName() == "Extrusion_1_1_1_1")
+assert(selectionList.value(2).namingName() == "Extrusion_1_1_1_2")
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+# Checks selection of the whole featurte and move to the end of the group created on this feature..
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(11.02869497636673, 9.8764247475525, 3.312248077480665)
+SketchCircle_2 = Sketch_1.addCircle(4.278198729238611, 4.677840612715367, 1.794922837237287)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1")], model.selection(), 10, 0)
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+Copy_1 = model.addCopy(Part_1_doc, [model.selection("COMPOUND", "all-in-Extrusion_1")], 1)
+model.do()
+# move the group feature to the end - through copy of the whole feature
+Part_1_doc.moveFeature(Group_1.feature(), Copy_1.feature())
+model.end()
+
+from ModelAPI import *
+aFactory = ModelAPI_Session.get().validators()
+assert(aFactory.validate(Group_1.feature()))
+selectionList = Group_1.feature().selectionList("group_list")
+assert(selectionList.size() == 2) # two: original feature and the copy-feature
+assert(selectionList.value(0).namingName() == "all-in-Extrusion_1")
+assert(selectionList.value(1).namingName() == "all-in-Copy_1")
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+# Checks selection of the whole shape and move to the end of the simple copy wihtout the
+# next modifications applied.
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(38.31034482758622, 31.49775664633739, 7.836206896551726, 31.49775664633739)
+SketchLine_2 = Sketch_1.addLine(7.836206896551726, 31.49775664633739, 7.836206896551726, 8.984209848307833)
+SketchLine_3 = Sketch_1.addLine(7.836206896551726, 8.984209848307833, 38.31034482758622, 8.984209848307833)
+SketchLine_4 = Sketch_1.addLine(38.31034482758622, 8.984209848307833, 38.31034482758622, 31.49775664633739)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchLine_5 = Sketch_1.addLine(21.64285714285715, 31.4977566463374, 25.0012315270936, 8.984209848307833)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.startPoint(), SketchLine_1.result())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_3.result())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_5r"), model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_5f-SketchLine_3f-SketchLine_4f")], model.selection(), 7, 0)
+Extrusion_1.result().setName("Origin")
+Group_1 = model.addGroup(Part_1_doc, "Solids", [model.selection("SOLID", "Extrusion_1_1_1")])
+Copy_1 = model.addCopy(Part_1_doc, [model.selection("COMPSOLID", "Origin")], 1)
+Copy_1.result().setName("Origin_1")
+Fillet_1 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Origin_1_1/Copy_3][Origin_1_1/Copy_7]"), model.selection("EDGE", "[Origin_1_1/Copy_12][Origin_1_1/Copy_14]")], 2)
+Fillet_1.result().setName("CopyCompound")
+model.do()
+# move the group feature to the end - through copy and fillet on this copy (to distinguish the origin and the copy)
+Part_1_doc.moveFeature(Group_1.feature(), Fillet_1.feature())
+model.end()
+
+from ModelAPI import *
+aFactory = ModelAPI_Session.get().validators()
+assert(aFactory.validate(Group_1.feature()))
+selectionList = Group_1.feature().selectionList("group_list")
+assert(selectionList.size() == 1) # still the same solid
+
+assert(selectionList.value(0).namingName() == "Fillet_1_1_1")
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+# Checks selection of the sub-shapes move to the end with combination of 2 Copy features in history
+
+from salome.shaper import model
+from ModelAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Group_1 = model.addGroup(Part_1_doc, "Edges", [model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]")])
+Copy_1 = model.addCopy(Part_1_doc, [model.selection("FACE", "Box_1_1/Front")], 2)
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 5, [model.selection("SOLID", "Box_1_1")])
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1/Front"))
+SketchCircle_1 = Sketch_1.addCircle(9.650212071680357, 9.344990586582618, 1.565166813054581)
+ExtrusionCut_1.setNestedSketch(Sketch_1)
+ExtrusionCut_1.result().setColor(225, 0, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1_1"))
+SketchCircle_2 = Sketch_2.addCircle(0.7603686814133139, 9.06793355634084, 1.630854194501576)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchCircle_2_2r")])
+Cut_1 = model.addCut(Part_1_doc, [model.selection("FACE", "Box_1_1_1")], [model.selection("FACE", "Face_1_1")], keepSubResults = True)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("FACE", "Box_1_1_2")], model.selection("EDGE", "PartSet/OX"), 5)
+Copy_2 = model.addCopy(Part_1_doc, [model.selection("FACE", "Box_1_1_2")], 2)
+Rotation_1 = model.addRotation(Part_1_doc, [model.selection("FACE", "Box_1_1_2_1")], model.selection("EDGE", "PartSet/OZ"), 10)
+Rotation_2 = model.addRotation(Part_1_doc, [model.selection("FACE", "Box_1_1_2_2")], model.selection("EDGE", "PartSet/OZ"), 20)
+model.do()
+# move the group feature to the end - through 2 copies and many modifications of the selected edge
+Part_1_doc.moveFeature(Group_1.feature(), Rotation_2.feature())
+model.end()
+
+# result is 5 edges: cut, translation, 2 rotations, extrusion cut
+aFactory = ModelAPI_Session.get().validators()
+assert(aFactory.validate(Group_1.feature()))
+selectionList = Group_1.feature().selectionList("group_list")
+assert(selectionList.size() == 5)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+# Checks that the Copy feature produces correct names, same as in the description #3109
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-11.9408866995074, 14.67733990147784, -29.35467980295567, 14.67733990147784)
+SketchLine_2 = Sketch_1.addLine(-29.35467980295567, 14.67733990147784, -29.35467980295567, -7.960591133004924)
+SketchLine_3 = Sketch_1.addLine(-29.35467980295567, -7.960591133004924, -11.9408866995074, -7.960591133004924)
+SketchLine_4 = Sketch_1.addLine(-11.9408866995074, -7.960591133004924, -11.9408866995074, 14.67733990147784)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchCircle_1 = Sketch_1.addCircle(14.92610837438425, 16.04556650246306, 6.602917012013241)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f")], model.selection(), 10, 0)
+Extrusion_1.result().setName("Box")
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection(), 10, 0)
+Extrusion_2.result().setName("Cylinder")
+Copy_1 = model.addCopy(Part_1_doc, [model.selection("SOLID", "Box"), model.selection("SOLID", "Cylinder")], 3)
+model.end()
+
+assert(Copy_1.feature().results().size() == 6)
+
+assert(Copy_1.feature().results()[0].data().name() == "Box_1")
+assert(Copy_1.feature().results()[1].data().name() == "Cylinder_1")
+assert(Copy_1.feature().results()[2].data().name() == "Box_2")
+assert(Copy_1.feature().results()[3].data().name() == "Cylinder_2")
+assert(Copy_1.feature().results()[4].data().name() == "Box_3")
+assert(Copy_1.feature().results()[5].data().name() == "Cylinder_3")
+
+model.begin()
+model.testHaveNamingSubshapes(Copy_1, model, Part_1_doc)
+model.end()
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+# Checks that the Copy feature produces correct results and names if sub-shapes of the same shape are selected
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-25.99630541871921, 19.52832512315271, -16.66748768472907, 29.72783251231528)
+SketchLine_2 = Sketch_1.addLine(-16.66748768472907, 29.72783251231528, -12.4384236453202, 17.66256157635469)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(-12.4384236453202, 17.66256157635469, -25.99630541871921, 19.52832512315271)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 10, 0)
+Extrusion_1.result().setName("Prism")
+Copy_1_objects = [model.selection("FACE", "Prism/Generated_Face&Sketch_1/SketchLine_3"), model.selection("FACE", "Prism/Generated_Face&Sketch_1/SketchLine_2"), model.selection("EDGE", "[Prism/Generated_Face&Sketch_1/SketchLine_1][Prism/To_Face]")]
+Copy_1 = model.addCopy(Part_1_doc, Copy_1_objects, 2)
+Copy_1.result().setName("Prism_1")
+model.end()
+
+assert(Copy_1.feature().results().size() == 6)
+
+for index in range(6):
+ # name is just incremented
+ assert(Copy_1.feature().results()[index].data().name() == "Prism_" + str(index + 1))
+ # type of the shape corresponds to selection: 2 faces then edge
+ if index%3 == 2:
+ assert(Copy_1.feature().results()[index].shape().shapeTypeStr() == "EDGE")
+ else:
+ assert(Copy_1.feature().results()[index].shape().shapeTypeStr() == "FACE")
+
+model.begin()
+model.testHaveNamingSubshapes(Copy_1, model, Part_1_doc)
+model.end()
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+# Checks that the Copy feature produces correct results and names if the whole result and feature are copied.
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-19.47177806477657, -9.723714972297476, -32.14322074518937, 18.42485654704614)
+SketchLine_2 = Sketch_1.addLine(-32.14322074518937, 18.42485654704614, -13.96909823036938, 5.527027954588926)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(-13.96909823036938, 5.527027954588926, -19.47177806477657, -9.723714972297476)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchLine_4 = Sketch_1.addLine(-19.47177806477657, -9.723714972297476, -38.20802856635906, 4.439747463237282)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(-38.20802856635906, 4.439747463237282, -32.14322074518937, 18.42485654704614)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_5.endPoint())
+SketchCircle_1 = Sketch_1.addCircle(15.45187411494798, 10.57784256870842, 6.036432809751617)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_5r-SketchLine_4r"), model.selection("FACE", "Sketch_1/Face-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 10, 0)
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("WIRE", "Sketch_1/Face-SketchCircle_1_2f_wire")], model.selection(), 10, 0)
+Copy_1 = model.addCopy(Part_1_doc, [model.selection("COMPSOLID", "Extrusion_1_1"), model.selection("COMPOUND", "all-in-Extrusion_2")], 1)
+model.end()
+
+assert(Copy_1.feature().results().size() == 2)
+
+from ModelAPI import *
+assert(Copy_1.feature().results()[0].data().name() == "Extrusion_1_1_1")
+assert(modelAPI_ResultBody(Copy_1.feature().results()[0]).subResult(0).data().name() == "Extrusion_1_1_1_1")
+assert(modelAPI_ResultBody(Copy_1.feature().results()[0]).subResult(1).data().name() == "Extrusion_1_1_1_2")
+assert(Copy_1.feature().results()[1].data().name() == "Extrusion_2_1_1")
+
+# Check that copy of the whole feature that contains several results produce compound of all results
+model.begin()
+Extrusion_3 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1")], model.selection(), 10, 0)
+Copy_2 = model.addCopy(Part_1_doc, [model.selection("COMPOUND", "all-in-Extrusion_3")], 1)
+model.end()
+
+assert(Copy_2.feature().results()[0].data().name() == "Extrusion_3_1_1")
+assert(Copy_2.feature().results()[0].shape().shapeTypeStr() == "COMPOUND")
+aSub1 = modelAPI_ResultBody(Copy_2.feature().results()[0]).subResult(0)
+assert(aSub1.shape().shapeTypeStr() == "COMPSOLID")
+aSub2 = modelAPI_ResultBody(Copy_2.feature().results()[0]).subResult(1)
+assert(aSub2.shape().shapeTypeStr() == "SOLID")
+
+model.begin()
+model.testHaveNamingSubshapes(Copy_1, model, Part_1_doc)
+model.testHaveNamingSubshapes(Copy_2, model, Part_1_doc)
+model.end()
+
+assert(model.checkPythonDump())
--- /dev/null
+<source>
+ <multi_selector id="objects"
+ label="Sources:"
+ tooltip="Select copied objects"
+ shape_types="vertices edges wires faces shells compsolids objects"
+ use_choice="false"
+ concealment="false">
+ </multi_selector>
+ <integervalue id="number"
+ label="Nb copies"
+ step="1"
+ default="1"
+ min="1"
+ tooltip="Number of copies">
+ </integervalue>
+</source>
helpfile="recoverFeature.html">
<source path="recover_widget.xml"/>
</feature>
+ <feature id="Copy"
+ title="Copy"
+ tooltip="Copies results or sub-results"
+ icon="icons/Features/copy.png"
+ helpfile="copyFeature.html">
+ <source path="copy_widget.xml"/>
+ </feature>
<feature id="RemoveResults" title="Remove results" tooltip="Internal feature for results removal" internal="1">
<multi_selector id="results" concealment="true"/>
</feature>
void Model_AttributeSelection::concealedFeature(
- const FeaturePtr theFeature, const FeaturePtr theStop, std::list<FeaturePtr>& theConcealers,
- const ResultPtr theResultOfFeature)
+ const FeaturePtr theFeature, const FeaturePtr theStop, const bool theCheckCopy,
+ std::list<FeaturePtr>& theConcealers, const ResultPtr theResultOfFeature)
{
std::set<FeaturePtr> alreadyProcessed;
alreadyProcessed.insert(theFeature);
if (alreadyProcessed.find(aRefFeat) != alreadyProcessed.end()) // optimization
continue;
alreadyProcessed.insert(aRefFeat);
- if (ModelAPI_Session::get()->validators()->isConcealed(aRefFeat->getKind(), (*aRef)->id()))
+ if (ModelAPI_Session::get()->validators()->isConcealed(aRefFeat->getKind(), (*aRef)->id())
+ || (theCheckCopy &&
+ std::dynamic_pointer_cast<ModelAPI_FeatureCopyInterface>(aRefFeat).get()))
{
// for extrusion cut in python script the nested sketch reference may be concealed before
// it is nested, so, check this composite feature is valid
} else aResIter++;
}
+ bool aStaySame = false;
if (aResults.empty()) {
// check the context become concealed by operation which is earlier than this selection
FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
FeaturePtr aContextOwner = theDoc->feature(theContext);
std::list<FeaturePtr> aConcealers;
- concealedFeature(aContextOwner, aThisFeature, aConcealers, theContext);
+ concealedFeature(aContextOwner, aThisFeature, false, aConcealers, theContext);
std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
for(; aConcealer != aConcealers.end(); aConcealer++) {
std::list<ResultPtr> aRefResults;
if (aResults.empty())
return true; // feature conceals result, return true, so the context will be removed
}
- if (aResults.empty())
- return false; // no modifications found, must stay the same
+ aStaySame = aResults.empty();
+ }
+ if (myParent && myParent->isMakeCopy()) {
+ // check there are copies before the new results, so, make a copy
+ std::set<ResultPtr>::iterator aResIter = aResults.begin();
+ std::list<ObjectPtr> aCopyContext;
+ std::list<GeomShapePtr> aCopyVals;
+ // features between the new and the old: check the "Move" interface to get a copy
+ FeaturePtr aRootOwner = theDoc->feature(theContext);
+ FeaturePtr anOwner = ModelAPI_Tools::compositeOwner(aRootOwner);
+ for(; anOwner.get(); anOwner = ModelAPI_Tools::compositeOwner(anOwner))
+ aRootOwner = anOwner;
+ FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
+ // iterate all results to find a "Copy" features between the new and one and to add the
+ // copy-results also to results if this attribute refers to the copied shape
+ int anIndex = kUNDEFINED_FEATURE_INDEX;
+ for(FeaturePtr aFeat = theDoc->objects()->nextFeature(aRootOwner, anIndex); aFeat.get() &&
+ aFeat != aThisFeature; aFeat = theDoc->objects()->nextFeature(aFeat, anIndex)) {
+ std::shared_ptr<ModelAPI_FeatureCopyInterface> aCopier =
+ std::dynamic_pointer_cast<ModelAPI_FeatureCopyInterface>(aFeat);
+ if (aCopier.get()) {
+ GeomShapePtr aValShape(new GeomAPI_Shape);
+ aValShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(
+ theValShape.IsNull() ? theContShape : theValShape));
+ aCopier->getCopies(theContext, aValShape, aCopyContext, aCopyVals);
+ }
+ }
+ // check for the further modifications of the copy contexts and values
+ std::list<ObjectPtr>::iterator aCopyContIter = aCopyContext.begin();
+ std::list<GeomShapePtr>::iterator aCopyValIter = aCopyVals.begin();
+ for(; aCopyContIter != aCopyContext.end(); aCopyContIter++, aCopyValIter++) {
+ ResultPtr aNewCont = std::dynamic_pointer_cast<ModelAPI_Result>(*aCopyContIter);
+ TopoDS_Shape aNewContShape = aNewCont->shape()->impl<TopoDS_Shape>();
+ GeomShapePtr aNewVal = *aCopyValIter;
+ TopoDS_Shape aNewValShape;
+ if (aNewVal.get() && !aNewVal->isNull())
+ aNewValShape = aNewVal->impl<TopoDS_Shape>();
+ std::list<ResultPtr> aNewRes;
+ TopTools_ListOfShape aNewUpdatedVal;
+ if (searchNewContext(theDoc, aNewContShape, aNewCont, aNewValShape,
+ theAccessLabel, aNewRes, aNewUpdatedVal)) {
+ // append new results instead of the current ones
+ std::list<ResultPtr>::iterator aNewIter = aNewRes.begin();
+ TopTools_ListIteratorOfListOfShape aNewUpdVal(aNewUpdatedVal);
+ for(; aNewIter != aNewRes.end(); aNewIter++, aNewUpdVal.Next()) {
+ theResults.push_back(*aNewIter);
+ theValShapes.Append(aNewUpdVal.Value());
+ }
+ } else { // the current result is good
+ theResults.push_back(aNewCont);
+ theValShapes.Append(aNewValShape);
+ }
+ }
+ if (aStaySame && !theResults.empty()) { // no changes except copy, so, keep the origin as first
+ theResults.push_front(theContext);
+ theValShapes.Prepend(theValShape);
+ return true;
+ }
}
+ if (aStaySame)
+ return false;
+
// iterate all results to find further modifications
std::set<ResultPtr>::iterator aResIter = aResults.begin();
- for(; aResIter != aResults.end(); aResIter++) {
+ for(aResIter = aResults.begin(); aResIter != aResults.end(); aResIter++) {
if (aResIter->get() != NULL) {
+ ResultPtr aNewResObj = *aResIter;
// compute new values by two contexts: the old and the new
TopTools_ListOfShape aValShapes;
- computeValues(theContext, *aResIter, theValShape, aValShapes);
+ computeValues(theContext, aNewResObj, theValShape, aValShapes);
TopTools_ListIteratorOfListOfShape aNewVal(aValShapes);
for(; aNewVal.More(); aNewVal.Next()) {
std::list<ResultPtr> aNewRes;
TopTools_ListOfShape aNewUpdatedVal;
TopoDS_Shape aNewValSh = aNewVal.Value();
- TopoDS_Shape aNewContShape = (*aResIter)->shape()->impl<TopoDS_Shape>();
+ TopoDS_Shape aNewContShape = aNewResObj->shape()->impl<TopoDS_Shape>();
+
if (theValShape.IsNull() && aNewContShape.IsSame(aNewValSh))
aNewValSh.Nullify();
- if (searchNewContext(theDoc, aNewContShape, *aResIter, aNewValSh,
+ if (searchNewContext(theDoc, aNewContShape, aNewResObj, aNewValSh,
theAccessLabel, aNewRes, aNewUpdatedVal))
{
// append new results instead of the current ones
theValShapes.Append(aNewUpdVal.Value());
}
} else { // the current result is good
- theResults.push_back(*aResIter);
+ theResults.push_back(aNewResObj);
theValShapes.Append(aNewValSh);
}
}
if (aFeature.get()) {
FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
std::list<FeaturePtr> aConcealers;
- concealedFeature(aFeature, aThisFeature, aConcealers, ResultPtr());
+ bool aCopyPossible = myParent && myParent->isMakeCopy();
+ concealedFeature(aFeature, aThisFeature, aCopyPossible, aConcealers, ResultPtr());
if (aConcealers.empty())
return;
+ // if there are copies, but no direct modification, keep the original
+ bool aKeepOrigin = false;
+ if (aCopyPossible) {
+ std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
+ for(aKeepOrigin = true; aConcealer != aConcealers.end(); aConcealer++)
+ if (!std::dynamic_pointer_cast<ModelAPI_FeatureCopyInterface>(*aConcealer).get()) {
+ aKeepOrigin = false;
+ break;
+ }
+ if (aKeepOrigin) {
+ aConcealers.push_front(aFeature);
+ }
+ }
bool aChanged = false;
std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
for(; aConcealer != aConcealers.end(); aConcealer++)
- if (!myParent->isInList(*aConcealer, anEmptyShape)) {// avoid addition of duplicates
- setValue(*aConcealer, anEmptyShape);
- aChanged = true;
- }
- if (aConcealer == aConcealers.end()) {
- if (!aChanged) // remove this
- theRemove = true;
- } else { // append new
- for(aConcealer++; aConcealer != aConcealers.end(); aConcealer++)
- if (!myParent->isInList(*aConcealer, anEmptyShape)) // avoid addition of duplicates
+ if (aChanged) {
+ if (aKeepOrigin || !myParent->isInList(*aConcealer, anEmptyShape))
myParent->append(*aConcealer, anEmptyShape);
- }
- if (aChanged) // searching for the further modifications
+ } else {
+ if (!myParent->isInList(*aConcealer, anEmptyShape)) {// avoid addition of duplicates
+ setValue(*aConcealer, anEmptyShape);
+ aChanged = true;
+ } else if (aCopyPossible && *aConcealer == aFeature) { // keep the origin in case of copy
+ aChanged = true;
+ }
+ }
+ if (!aChanged) // remove this
+ theRemove = true;
+ else if (!aKeepOrigin) // searching further modifications only if current changed
updateInHistory(theRemove);
}
}
if (!myParent || !myParent->isInList(aNewContext, aValueShape)) { // avoid duplicates
setValue(aNewContext, aValueShape);
aFirst = false;
+ } else if (aNewContext == aContext && myParent && myParent->isMakeCopy()) {
+ // this may be exactly the old one, not modified in case of copy
+ aFirst = false;
}
} else if (myParent) {
if (!myParent->isInList(aNewContext, aValueShape)) // avoid addition of duplicates
/// Returns features that conceals theFeature and located in history before theStop
/// theResultOfFeature if not null defines exact referenced result of a feature
void concealedFeature(
- const FeaturePtr theFeature, const FeaturePtr theStop, std::list<FeaturePtr>& theConcealers,
- const ResultPtr theResultOfFeature);
+ const FeaturePtr theFeature, const FeaturePtr theStop, const bool theCheckCopy,
+ std::list<FeaturePtr>& theConcealers, const ResultPtr theResultOfFeature);
friend class Model_Data;
friend class Model_AttributeSelectionList;
} while (aSub.get());
}
+ AttributeSelectionListPtr aMovedList;
+ if (theMoved->getKind() == "Group") {
+ aMovedList = theMoved->selectionList("group_list");
+ if (aMovedList.get())
+ aMovedList->setMakeCopy(true);
+ }
myObjs->moveFeature(theMoved, anAfterThisSub);
if (theSplit) { // split the group into sub-features
// must be after move to make enabled all features which are before theMoved
setCurrentFeature(theMoved, true);
}
-
- if (theSplit) { // split the group into sub-features
- theMoved->customAction("split");
- }
+ if (aMovedList.get())
+ aMovedList->setMakeCopy(false);
}
void Model_Document::updateHistory(const std::shared_ptr<ModelAPI_Object> theObject)
}
}
+void Model_ResultBody::loadFirstLevel(GeomShapePtr theShape, const std::string& theName)
+{
+ if (mySubs.size()) { // consists of subs
+ for (std::vector<ResultBodyPtr>::const_iterator aSubIter = mySubs.cbegin();
+ aSubIter != mySubs.cend();
+ ++aSubIter)
+ {
+ const ResultBodyPtr& aSub = *aSubIter;
+ aSub->loadFirstLevel(theShape, theName);
+ }
+ } else { // do for this directly
+ myBuilder->loadFirstLevel(theShape, theName);
+ }
+}
+
int Model_ResultBody::numberOfSubs(bool forTree) const
{
return int(mySubs.size());
const GeomAPI_Shape::ShapeType theShapeTypeToExplore,
const std::string& theName = "") override;
+ /// load shapes of the first level (to be used during shape import)
+ MODEL_EXPORT virtual void loadFirstLevel(GeomShapePtr theShape, const std::string& theName);
/// Returns the number of sub-elements
MODEL_EXPORT virtual int numberOfSubs(bool forTree = false) const;
/// may be sub-objects, so, it is the same as all sub-shapes are selected (#3005). It is "false"
/// by default.
bool myIsWholeResultAllowed;
- public:
+ /// Flag that indicates that update in history must check the copy-features
+ /// and make a copy of selection for them.
+ bool myMakeCopy;
+public:
/// Adds the new reference to the end of the list
/// \param theContext object where the sub-shape was selected
/// \param theSubShape selected sub-shape (if null, the whole context is selected)
myIsWholeResultAllowed = theFlag;
}
+ /// Returns true if a copy features must be used in update in history.
+ MODELAPI_EXPORT virtual const bool isMakeCopy() const {
+ return myMakeCopy;
+ }
+
+ /// Sets true if a copy features must be used in update in history.
+ MODELAPI_EXPORT virtual void setMakeCopy(const bool theFlag) {
+ myMakeCopy = theFlag;
+ }
+
protected:
/// Default constructor
MODELAPI_EXPORT ModelAPI_AttributeSelectionList() : ModelAPI_Attribute()
- {myIsWholeResultAllowed = false;}
+ {myIsWholeResultAllowed = false; myMakeCopy = false;}
};
//! Pointer on feature object
typedef std::shared_ptr<ModelAPI_Feature> FeaturePtr;
-#endif
+//! An interface for performing special copy actions. To give feature which is moved (a group)
+//! over this feature.
+class ModelAPI_FeatureCopyInterface {
+public:
+ /// An algorithm to update the moved feature by the separate Copy feature
+ /// \param theContext the original context object
+ /// \param theValue the original shape
+ /// \param theCopies resulting copy-context will be appended here
+ virtual void getCopies(ObjectPtr theContext, std::shared_ptr<GeomAPI_Shape> theValue,
+ std::list<ObjectPtr>& theCopyContext,
+ std::list<std::shared_ptr<GeomAPI_Shape> >& theCopyVals) = 0;
+};
+#endif
myBuilder->loadDeletedShapes(theAlgo, theOldShape, theShapeTypeToExplore, theShapesToExclude);
}
-void ModelAPI_ResultBody::loadFirstLevel(GeomShapePtr theShape,
- const std::string& theName)
-{
- myBuilder->loadFirstLevel(theShape, theName);
-}
-
// LCOV_EXCL_START
bool ModelAPI_ResultBody::isConnectedTopology()
{
/// load shapes of the first level (to be used during shape import)
MODELAPI_EXPORT virtual void loadFirstLevel(GeomShapePtr theShape,
- const std::string& theName);
+ const std::string& theName) = 0;
/// Returns true is the topology is connected.
MODELAPI_EXPORT virtual bool isConnectedTopology() = 0;
from FeaturesAPI import addFusionFaces
from FeaturesAPI import measureLength, measureDistance, measureRadius, measureAngle
from FeaturesAPI import addRemoveResults
+from FeaturesAPI import addCopy