From: azv Date: Wed, 29 Jan 2020 12:13:15 +0000 (+0300) Subject: Issue #17342: 3D Model defeaturing X-Git-Tag: V9_5_0a1~53 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=2a2f4487370c6f7be90aa398fd1a205cc7ea96df;p=modules%2Fshaper.git Issue #17342: 3D Model defeaturing --- diff --git a/src/FeaturesAPI/CMakeLists.txt b/src/FeaturesAPI/CMakeLists.txt index 921b2eec7..2b6df755f 100644 --- a/src/FeaturesAPI/CMakeLists.txt +++ b/src/FeaturesAPI/CMakeLists.txt @@ -50,6 +50,7 @@ SET(PROJECT_HEADERS FeaturesAPI_FusionFaces.h FeaturesAPI_Copy.h FeaturesAPI_ImportResult.h + FeaturesAPI_Defeaturing.h ) SET(PROJECT_SOURCES @@ -82,6 +83,7 @@ SET(PROJECT_SOURCES FeaturesAPI_FusionFaces.cpp FeaturesAPI_Copy.cpp FeaturesAPI_ImportResult.cpp + FeaturesAPI_Defeaturing.cpp ) SET(PROJECT_LIBRARIES diff --git a/src/FeaturesAPI/FeaturesAPI.i b/src/FeaturesAPI/FeaturesAPI.i index 41999dee9..a77c6a1c4 100644 --- a/src/FeaturesAPI/FeaturesAPI.i +++ b/src/FeaturesAPI/FeaturesAPI.i @@ -79,6 +79,7 @@ %shared_ptr(FeaturesAPI_RemoveResults) %shared_ptr(FeaturesAPI_Copy) %shared_ptr(FeaturesAPI_ImportResult) +%shared_ptr(FeaturesAPI_Defeaturing) %typecheck(SWIG_TYPECHECK_POINTER) std::pair, bool>, const std::pair, bool> & { @@ -149,6 +150,7 @@ %include "FeaturesAPI_BooleanSmash.h" %include "FeaturesAPI_BooleanFill.h" %include "FeaturesAPI_Chamfer.h" +%include "FeaturesAPI_Defeaturing.h" %include "FeaturesAPI_Extrusion.h" %include "FeaturesAPI_ExtrusionBoolean.h" %include "FeaturesAPI_Fillet.h" diff --git a/src/FeaturesAPI/FeaturesAPI_Defeaturing.cpp b/src/FeaturesAPI/FeaturesAPI_Defeaturing.cpp new file mode 100644 index 000000000..5accac9a3 --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_Defeaturing.cpp @@ -0,0 +1,79 @@ +// Copyright (C) 2020 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_Defeaturing.h" + +#include +#include + +FeaturesAPI_Defeaturing::FeaturesAPI_Defeaturing( + const std::shared_ptr& theFeature) + : ModelHighAPI_Interface(theFeature) +{ + initialize(); +} + +FeaturesAPI_Defeaturing::FeaturesAPI_Defeaturing( + const std::shared_ptr& theFeature, + const std::list& theFacesToRemove) + : ModelHighAPI_Interface(theFeature) +{ + if (initialize()) + setFaces(theFacesToRemove); +} + +FeaturesAPI_Defeaturing::~FeaturesAPI_Defeaturing() +{ +} + +void FeaturesAPI_Defeaturing::setFaces(const std::list& theFacesToRemove) +{ + mybaseObjects->clear(); + fillAttribute(theFacesToRemove, mybaseObjects); + + execIfBaseNotEmpty(); +} + +void FeaturesAPI_Defeaturing::dump(ModelHighAPI_Dumper& theDumper) const +{ + FeaturePtr aBase = feature(); + const std::string& aDocName = theDumper.name(aBase->document()); + + AttributeSelectionListPtr anAttrObjects = + aBase->selectionList(FeaturesPlugin_Defeaturing::OBJECT_LIST_ID()); + + theDumper << aBase << " = model.addDefeaturing(" << aDocName << ", " + << anAttrObjects << ")" << std::endl; +} + +void FeaturesAPI_Defeaturing::execIfBaseNotEmpty() +{ + if (mybaseObjects->size() > 0) + execute(); +} + + +//================================================================================================== + +DefeaturingPtr addDefeaturing(const std::shared_ptr& thePart, + const std::list& theFaces) +{ + std::shared_ptr aFeature = thePart->addFeature(FeaturesAPI_Defeaturing::ID()); + return DefeaturingPtr(new FeaturesAPI_Defeaturing(aFeature, theFaces)); +} diff --git a/src/FeaturesAPI/FeaturesAPI_Defeaturing.h b/src/FeaturesAPI/FeaturesAPI_Defeaturing.h new file mode 100644 index 000000000..960934d00 --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_Defeaturing.h @@ -0,0 +1,76 @@ +// Copyright (C) 2020 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_Defeaturing_H_ +#define FeaturesAPI_Defeaturing_H_ + +#include "FeaturesAPI.h" + +#include + +#include +#include + +class ModelHighAPI_Selection; + +/// \class FeaturesAPI_Defeaturing +/// \ingroup CPPHighAPI +/// \brief Interface for the Defeaturing feature. +class FeaturesAPI_Defeaturing: public ModelHighAPI_Interface +{ +public: + /// Constructor without values. + FEATURESAPI_EXPORT + explicit FeaturesAPI_Defeaturing(const std::shared_ptr& theFeature); + + /// Constructor with values. + FEATURESAPI_EXPORT + explicit FeaturesAPI_Defeaturing(const std::shared_ptr& theFeature, + const std::list& theFacesToRemove); + + /// Destructor. + FEATURESAPI_EXPORT + virtual ~FeaturesAPI_Defeaturing(); + + INTERFACE_1(FeaturesPlugin_Defeaturing::ID(), + baseObjects, FeaturesPlugin_Defeaturing::OBJECT_LIST_ID(), + ModelAPI_AttributeSelectionList, /** Base objects */) + + /// Modify faces to be removed. + FEATURESAPI_EXPORT + void setFaces(const std::list& theFacesToRemove); + + /// Dump wrapped feature + FEATURESAPI_EXPORT + virtual void dump(ModelHighAPI_Dumper& theDumper) const; + +private: + void execIfBaseNotEmpty(); +}; + +/// Pointer on the Defeaturing object. +typedef std::shared_ptr DefeaturingPtr; + +/// \ingroup CPPHighAPI +/// \brief Create Defeaturing feature. +FEATURESAPI_EXPORT +DefeaturingPtr addDefeaturing(const std::shared_ptr& thePart, + const std::list& theFaces); + +#endif // FeaturesAPI_Defeaturing_H_ diff --git a/src/FeaturesAPI/FeaturesAPI_swig.h b/src/FeaturesAPI/FeaturesAPI_swig.h index ca0d4b6db..af2866c3e 100644 --- a/src/FeaturesAPI/FeaturesAPI_swig.h +++ b/src/FeaturesAPI/FeaturesAPI_swig.h @@ -29,6 +29,7 @@ #include "FeaturesAPI_BooleanSmash.h" #include "FeaturesAPI_BooleanFill.h" #include "FeaturesAPI_Chamfer.h" + #include "FeaturesAPI_Defeaturing.h" #include "FeaturesAPI_Extrusion.h" #include "FeaturesAPI_ExtrusionBoolean.h" #include "FeaturesAPI_Fillet.h" diff --git a/src/FeaturesPlugin/CMakeLists.txt b/src/FeaturesPlugin/CMakeLists.txt index b5b856d71..80d67e469 100644 --- a/src/FeaturesPlugin/CMakeLists.txt +++ b/src/FeaturesPlugin/CMakeLists.txt @@ -63,6 +63,7 @@ SET(PROJECT_HEADERS FeaturesPlugin_Chamfer.h FeaturesPlugin_Copy.h FeaturesPlugin_ImportResult.h + FeaturesPlugin_Defeaturing.h ) SET(PROJECT_SOURCES @@ -107,6 +108,7 @@ SET(PROJECT_SOURCES FeaturesPlugin_Chamfer.cpp FeaturesPlugin_Copy.cpp FeaturesPlugin_ImportResult.cpp + FeaturesPlugin_Defeaturing.cpp ) SET(XML_RESOURCES @@ -141,6 +143,7 @@ SET(XML_RESOURCES chamfer_widget.xml copy_widget.xml import_result_widget.xml + defeaturing_widget.xml ) SET(TEXT_RESOURCES @@ -555,4 +558,12 @@ ADD_UNIT_TESTS(TestExtrusion.py TestCopySubShapes.py TestCopyWholeFeature.py TestImportResult.py + TestDefeaturing_ErrorMsg.py + TestDefeaturing_OnSolid1.py + TestDefeaturing_OnSolid2.py + TestDefeaturing_OnSolid3.py + TestDefeaturing_OnCompsolid1.py + TestDefeaturing_OnCompsolid2.py + TestDefeaturing_OnCompsolid3.py + TestDefeaturing_OnCompound.py ) diff --git a/src/FeaturesPlugin/FeaturesPlugin_Defeaturing.cpp b/src/FeaturesPlugin/FeaturesPlugin_Defeaturing.cpp new file mode 100644 index 000000000..104667ed5 --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_Defeaturing.cpp @@ -0,0 +1,115 @@ +// Copyright (C) 2020 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 +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include + + +FeaturesPlugin_Defeaturing::FeaturesPlugin_Defeaturing() +{ +} + +void FeaturesPlugin_Defeaturing::initAttributes() +{ + data()->addAttribute(OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()); +} + + +void FeaturesPlugin_Defeaturing::execute() +{ + typedef std::unordered_map SolidFaces; + SolidFaces aBodiesAndFacesToRemove; + + // getting objects and sort them according to parent solids + AttributeSelectionListPtr anObjectsSelList = selectionList(OBJECT_LIST_ID()); + for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); ++anObjectsIndex) { + AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex); + GeomShapePtr anObject = anObjectAttr->value(); + if (!anObject) + return; + + ResultPtr aContext = anObjectAttr->context(); + if (!aContext.get()) + return; + + ResultBodyPtr aCtxOwner = ModelAPI_Tools::bodyOwner(aContext, true); + GeomShapePtr aParent = aCtxOwner ? aCtxOwner->shape() : aContext->shape(); + aBodiesAndFacesToRemove[aParent].push_back(anObject); + } + + // Perform Defeaturing algorithm + GeomAlgoAPI_MakeShapeList aMakeShapeList; + std::shared_ptr anAlgo; + int aResultIndex = 0; + std::string anError; + + std::vector aResultBaseAlgoList; + ListOfShape anOriginalShapesList, aResultShapesList; + + for (SolidFaces::iterator anIt = aBodiesAndFacesToRemove.begin(); + anIt != aBodiesAndFacesToRemove.end(); ++anIt) { + GeomShapePtr aParent = anIt->first; + anAlgo.reset(new GeomAlgoAPI_Defeaturing(aParent, anIt->second)); + if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(anAlgo, getKind(), anError)) { + setError(anError); + return; + } + + GeomShapePtr aResult = anAlgo->shape(); + ListOfShape aBaseShapes; + for (GeomAPI_ShapeExplorer anExp(aParent, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) + aBaseShapes.push_back(anExp.current()); + + std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); + FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, aBaseShapes, ListOfShape(), + anAlgo, aResult, "Defeaturing"); + + setResult(aResultBody, aResultIndex); + aResultIndex++; + + FeaturesPlugin_Tools::ResultBaseAlgo aRBA; + aRBA.resultBody = aResultBody; + aRBA.baseShape = aParent; + aRBA.makeShape = anAlgo; + aResultBaseAlgoList.push_back(aRBA); + aResultShapesList.push_back(aResult); + anOriginalShapesList.insert(anOriginalShapesList.end(), aBaseShapes.begin(), aBaseShapes.end()); + } + + // Store deleted shapes after all results has been proceeded. This is to avoid issue when in one + // result shape has been deleted, but in another it was modified or stayed. + GeomShapePtr aResultShapesCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList); + FeaturesPlugin_Tools::loadDeletedShapes(aResultBaseAlgoList, + anOriginalShapesList, aResultShapesCompound); + + removeResults(aResultIndex); +} diff --git a/src/FeaturesPlugin/FeaturesPlugin_Defeaturing.h b/src/FeaturesPlugin/FeaturesPlugin_Defeaturing.h new file mode 100644 index 000000000..c703e027b --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_Defeaturing.h @@ -0,0 +1,74 @@ +// Copyright (C) 2020 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_Defeaturing_H_ +#define FeaturesPlugin_Defeaturing_H_ + +#include "FeaturesPlugin.h" + +#include + +class GeomAlgoAPI_MakeShape; +class GeomAPI_Shape; + +/// \class FeaturesPlugin_Defeaturing +/// \ingroup Plugins +/// \brief Feature for the removal of the unwanted parts or features from the model. +class FeaturesPlugin_Defeaturing : public ModelAPI_Feature +{ +public: + /// Feature kind. + inline static const std::string& ID() + { + static const std::string MY_ID("Defeaturing"); + return MY_ID; + } + + /// \return the kind of a feature. + FEATURESPLUGIN_EXPORT virtual const std::string& getKind() + { + static std::string MY_KIND = FeaturesPlugin_Defeaturing::ID(); + return MY_KIND; + } + + /// Attribute name of main objects. + inline static const std::string& OBJECT_LIST_ID() + { + static const std::string MY_OBJECT_LIST_ID("main_objects"); + return MY_OBJECT_LIST_ID; + } + + /// Performs the defeaturing algorithm and stores 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(); + + /// Use plugin manager for features creation. + FeaturesPlugin_Defeaturing(); + +private: + /// Load Naming data structure of the feature to the document + void loadNamingDS(std::shared_ptr theResultBody, + const std::shared_ptr theBaseShape, + const std::shared_ptr theResultShape, + const std::shared_ptr& theMakeShape); +}; + +#endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp index 8ade62615..5f226c11b 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -118,6 +119,8 @@ FeaturesPlugin_Plugin::FeaturesPlugin_Plugin() new FeaturesPlugin_ValidatorBooleanCommonArguments); aFactory->registerValidator("FeaturesPlugin_ValidatorImportResults", new FeaturesPlugin_ValidatorImportResults); + aFactory->registerValidator("FeaturesPlugin_ValidatorDefeaturingSelection", + new FeaturesPlugin_ValidatorDefeaturingSelection); // register this plugin ModelAPI_Session::get()->registerPlugin(this); @@ -187,6 +190,8 @@ FeaturePtr FeaturesPlugin_Plugin::createFeature(std::string theFeatureID) return FeaturePtr(new FeaturesPlugin_Copy); } else if (theFeatureID == FeaturesPlugin_ImportResult::ID()) { return FeaturePtr(new FeaturesPlugin_ImportResult); + } else if (theFeatureID == FeaturesPlugin_Defeaturing::ID()) { + return FeaturePtr(new FeaturesPlugin_Defeaturing); } diff --git a/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp b/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp index 07db4dd86..6426d9473 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp @@ -1877,3 +1877,42 @@ bool FeaturesPlugin_ValidatorBooleanCommonArguments::isNotObligatory( return false; } // LCOV_EXCL_STOP + +//================================================================================================== +bool FeaturesPlugin_ValidatorDefeaturingSelection::isValid( + const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + AttributeSelectionListPtr anAttrSelectionList = + std::dynamic_pointer_cast(theAttribute); + if (!anAttrSelectionList.get()) { + // LCOV_EXCL_START + theError = "Error: This validator can only work with selection list attributes."; + return false; + // LCOV_EXCL_STOP + } + + // Check selected entities are sub-shapes of solid or compsolid + GeomShapePtr aBaseSolid; + for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) { + AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex); + if (!anAttrSelection.get()) { + theError = "Error: Empty attribute selection."; + return false; + } + ResultPtr aContext = anAttrSelection->context(); + if (!aContext.get()) { + theError = "Error: Empty selection context."; + return false; + } + + GeomShapePtr aContextShape = aContext->shape(); + if (aContextShape->shapeType() != GeomAPI_Shape::SOLID) { + theError = "Error: Not all selected shapes are sub-shapes of solids."; + return false; + } + } + + return true; +} diff --git a/src/FeaturesPlugin/FeaturesPlugin_Validators.h b/src/FeaturesPlugin/FeaturesPlugin_Validators.h index c2ec597df..da3222d1e 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Validators.h +++ b/src/FeaturesPlugin/FeaturesPlugin_Validators.h @@ -419,4 +419,20 @@ public: virtual bool isNotObligatory(std::string theFeature, std::string theAttribute); }; +/// \class FeaturesPlugin_ValidatorDefeaturingSelection +/// \ingroup Validators +/// \brief Validates selection for fillet operation. +class FeaturesPlugin_ValidatorDefeaturingSelection : public ModelAPI_AttributeValidator +{ +public: + /// \return True if the attribute is valid. It checks whether the selection + /// is acceptable for boolean operation. + /// \param[in] theAttribute an attribute to check. + /// \param[in] theArguments a filter parameters. + /// \param[out] theError error message. + virtual bool isValid(const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const; +}; + #endif diff --git a/src/FeaturesPlugin/Test/TestDefeaturing_ErrorMsg.py b/src/FeaturesPlugin/Test/TestDefeaturing_ErrorMsg.py new file mode 100644 index 000000000..387605fc0 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestDefeaturing_ErrorMsg.py @@ -0,0 +1,50 @@ +# Copyright (C) 2020 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 +# + +from salome.shaper import model + +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) + +Defeaturing_1 = model.addDefeaturing(Part_1_doc, [model.selection("FACE", "Box_1_1/Top")]) +assert(Defeaturing_1.feature().error() != "") + +model.do() + +Part_2 = model.addPart(partSet) +Part_2_doc = Part_2.document() +Box_2 = model.addBox(Part_2_doc, 10, 10, 10) +ExtrusionCut_1 = model.addExtrusionCut(Part_2_doc, [], model.selection(), [model.selection("SOLID", "Box_1_1")]) +Sketch_1 = model.addSketch(Part_2_doc, model.selection("FACE", "Box_1_1/Top")) +SketchCircle_1 = Sketch_1.addCircle(4, 5.137343601256935, 3) +SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 3) +SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"), False) +SketchLine_1 = SketchProjection_1.createdFeature() +SketchConstraintDistance_1 = Sketch_1.setDistance(SketchCircle_1.center(), SketchLine_1.result(), 4, True) +ExtrusionCut_1.setNestedSketch(Sketch_1) +Plane_4 = model.addPlane(Part_2_doc, model.selection("FACE", "Box_1_1/Back"), model.selection("FACE", "Box_1_1/Front")) +Partition_1 = model.addPartition(Part_2_doc, [model.selection("SOLID", "ExtrusionCut_1_1"), model.selection("FACE", "Plane_1")], keepSubResults = True) + +Defeaturing_2 = model.addDefeaturing(Part_2_doc, [model.selection("FACE", "Partition_1_1_1/Modified_Face&Sketch_1/SketchCircle_1_2")]) +assert(Defeaturing_2.feature().error() != "") + +model.end() diff --git a/src/FeaturesPlugin/Test/TestDefeaturing_OnCompound.py b/src/FeaturesPlugin/Test/TestDefeaturing_OnCompound.py new file mode 100644 index 000000000..ce66d04c5 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestDefeaturing_OnCompound.py @@ -0,0 +1,47 @@ +# Copyright (C) 2020 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 +# + +from salome.shaper import model + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Box_1 = model.addBox(Part_1_doc, 20, 20, 10) +Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10) +Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], 10, 10, 0) +Cylinder_2 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10) +Cut_1 = model.addCut(Part_1_doc, [model.selection("SOLID", "Box_1_1")], [model.selection("SOLID", "Translation_1_1"), model.selection("SOLID", "Cylinder_2_1")], keepSubResults = True) +LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Cut_1_1")], model.selection("EDGE", "PartSet/OX"), 30, 2, model.selection("EDGE", "PartSet/OY"), 30, 2) +Defeaturing_1_objects = [model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Cylinder_2_1/Face_1"), model.selection("FACE", "LinearCopy_1_1_4/MF:Translated&Cylinder_1_1/Face_1"), model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Cylinder_2_1/Face_1"), model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Cylinder_1_1/Face_1")] +Defeaturing_1 = model.addDefeaturing(Part_1_doc, Defeaturing_1_objects) +model.testHaveNamingSubshapes(Defeaturing_1, model, Part_1_doc) +model.end() + +from GeomAPI import * + +model.testNbResults(Defeaturing_1, 1) +model.testNbSubResults(Defeaturing_1, [4]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.SOLID, [4]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.FACE, [28]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.EDGE, [120]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.VERTEX, [240]) +model.testResultsVolumes(Defeaturing_1, [14036.50459153]) + +assert(model.checkPythonDump()) diff --git a/src/FeaturesPlugin/Test/TestDefeaturing_OnCompsolid1.py b/src/FeaturesPlugin/Test/TestDefeaturing_OnCompsolid1.py new file mode 100644 index 000000000..a6807c559 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestDefeaturing_OnCompsolid1.py @@ -0,0 +1,45 @@ +# Copyright (C) 2020 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 +# + +from salome.shaper import model + +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) +Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10) +Cut_1 = model.addCut(Part_1_doc, [model.selection("SOLID", "Box_1_1")], [model.selection("SOLID", "Cylinder_1_1")], keepSubResults = True) +Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "Cut_1_1/Modified_Face&Box_1_1/Back"), model.selection("FACE", "Box_1_1/Front")) +Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Cut_1_1"), model.selection("FACE", "Plane_1")], keepSubResults = True) +Defeaturing_1 = model.addDefeaturing(Part_1_doc, [model.selection("FACE", "Cut_1_1/Modified_Face&Cylinder_1_1/Face_1")]) +model.testHaveNamingSubshapes(Defeaturing_1, model, Part_1_doc) +model.end() + +from GeomAPI import * + +model.testNbResults(Defeaturing_1, 1) +model.testNbSubResults(Defeaturing_1, [2]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.SOLID, [2]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.FACE, [12]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.EDGE, [48]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.VERTEX, [96]) +model.testResultsVolumes(Defeaturing_1, [1000]) + +assert(model.checkPythonDump()) diff --git a/src/FeaturesPlugin/Test/TestDefeaturing_OnCompsolid2.py b/src/FeaturesPlugin/Test/TestDefeaturing_OnCompsolid2.py new file mode 100644 index 000000000..684011999 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestDefeaturing_OnCompsolid2.py @@ -0,0 +1,52 @@ +# Copyright (C) 2020 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 +# + +from salome.shaper import model + +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) +ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), [model.selection("SOLID", "Box_1_1")]) +Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1/Top")) +SketchCircle_1 = Sketch_1.addCircle(4, 5.137343601256935, 3) +SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 3) +SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"), False) +SketchLine_1 = SketchProjection_1.createdFeature() +SketchConstraintDistance_1 = Sketch_1.setDistance(SketchCircle_1.center(), SketchLine_1.result(), 4, True) +ExtrusionCut_1.setNestedSketch(Sketch_1) +Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "Box_1_1/Back"), model.selection("FACE", "Box_1_1/Front")) +Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "ExtrusionCut_1_1"), model.selection("FACE", "Plane_1")], keepSubResults = True) +Defeaturing_1_objects = [model.selection("FACE", "Partition_1_1_2/Modified_Face&Sketch_1/SketchCircle_1_2&weak_name_2"), model.selection("FACE", "Partition_1_1_2/Modified_Face&Sketch_1/SketchCircle_1_2&weak_name_1"), model.selection("FACE", "Partition_1_1_1/Modified_Face&Sketch_1/SketchCircle_1_2")] +Defeaturing_1 = model.addDefeaturing(Part_1_doc, Defeaturing_1_objects) +model.testHaveNamingSubshapes(Defeaturing_1, model, Part_1_doc) +model.end() + +from GeomAPI import * + +model.testNbResults(Defeaturing_1, 1) +model.testNbSubResults(Defeaturing_1, [2]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.SOLID, [2]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.FACE, [12]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.EDGE, [48]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.VERTEX, [96]) +model.testResultsVolumes(Defeaturing_1, [1000]) + +assert(model.checkPythonDump()) diff --git a/src/FeaturesPlugin/Test/TestDefeaturing_OnCompsolid3.py b/src/FeaturesPlugin/Test/TestDefeaturing_OnCompsolid3.py new file mode 100644 index 000000000..c63df13bf --- /dev/null +++ b/src/FeaturesPlugin/Test/TestDefeaturing_OnCompsolid3.py @@ -0,0 +1,85 @@ +# Copyright (C) 2020 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 +# + +from SketchAPI import * + +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(5, 1.355252715607035e-20, 20, -1.336382355046098e-51) +SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result()) +SketchLine_2 = Sketch_1.addLine(20, -1.336382355046098e-51, 20, 5.85786437626905) +SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint()) +SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result()) +SketchLine_3 = Sketch_1.addLine(20, 5.85786437626905, 15.85786437626905, 10) +SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint()) +SketchLine_4 = Sketch_1.addLine(15.85786437626905, 10, 20, 14.14213562373095) +SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint()) +SketchLine_5 = Sketch_1.addLine(20, 14.14213562373095, 20, 20) +SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint()) +SketchLine_6 = Sketch_1.addLine(20, 20, 0, 20) +SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint()) +SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_6.result()) +SketchLine_7 = Sketch_1.addLine(0, 20, 0, 5) +SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint()) +SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_7.result()) +SketchConstraintVertical_2.setName("SketchConstraintVertical_3") +SketchArc_1 = Sketch_1.addArc(0, 0, 5, 1.355252715607035e-20, 0, 5, False) +SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchArc_1.startPoint()) +SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchArc_1.endPoint()) +SketchConstraintCollinear_1 = Sketch_1.setCollinear(SketchLine_2.result(), SketchLine_5.result()) +SketchConstraintPerpendicular_1 = Sketch_1.setPerpendicular(SketchLine_3.result(), SketchLine_4.result()) +SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_1.result()) +SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_7.result()) +SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False) +SketchPoint_1 = SketchProjection_1.createdFeature() +SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchArc_1.center(), SketchAPI_Point(SketchPoint_1).coordinates()) +SketchConstraintDistance_1 = Sketch_1.setDistance(SketchArc_1.center(), SketchLine_1.endPoint(), 20, True) +SketchConstraintDistance_2 = Sketch_1.setDistance(SketchArc_1.center(), SketchLine_7.startPoint(), 20, True) +SketchLine_8 = Sketch_1.addLine(10, 0, 10, 20) +SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_8.startPoint(), SketchLine_1.result()) +SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchLine_8.endPoint(), SketchLine_6.result()) +SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result()) +SketchConstraintVertical_3.setName("SketchConstraintVertical_4") +SketchConstraintMiddle_1 = Sketch_1.setMiddlePoint(SketchLine_8.endPoint(), SketchLine_6.result()) +SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_5.result()) +SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_4.result()) +SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], 5) +SketchConstraintEqual_3 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_3.result()) +model.do() +Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection(), 10, 0) +Defeaturing_1 = model.addDefeaturing(Part_1_doc, [model.selection("FACE", "Extrusion_1_1_2/Generated_Face&Sketch_1/SketchArc_1_2"), model.selection("FACE", "Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_3")]) +model.testHaveNamingSubshapes(Defeaturing_1, model, Part_1_doc) +model.end() + +from GeomAPI import * + +model.testNbResults(Defeaturing_1, 1) +model.testNbSubResults(Defeaturing_1, [2]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.SOLID, [2]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.FACE, [14]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.EDGE, [60]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.VERTEX, [120]) +model.testResultsVolumes(Defeaturing_1, [4000]) + +assert(model.checkPythonDump()) diff --git a/src/FeaturesPlugin/Test/TestDefeaturing_OnSolid1.py b/src/FeaturesPlugin/Test/TestDefeaturing_OnSolid1.py new file mode 100644 index 000000000..8feef55cb --- /dev/null +++ b/src/FeaturesPlugin/Test/TestDefeaturing_OnSolid1.py @@ -0,0 +1,43 @@ +# Copyright (C) 2020 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 +# + +from salome.shaper import model + +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) +Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10) +Cut_1 = model.addCut(Part_1_doc, [model.selection("SOLID", "Box_1_1")], [model.selection("SOLID", "Cylinder_1_1")], keepSubResults = True) +Defeaturing_1 = model.addDefeaturing(Part_1_doc, [model.selection("FACE", "Cut_1_1/Modified_Face&Cylinder_1_1/Face_1")]) +model.testHaveNamingSubshapes(Defeaturing_1, model, Part_1_doc) +model.end() + +from GeomAPI import * + +model.testNbResults(Defeaturing_1, 1) +model.testNbSubResults(Defeaturing_1, [0]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.SOLID, [1]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.FACE, [6]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.EDGE, [24]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.VERTEX, [48]) +model.testResultsVolumes(Defeaturing_1, [1000]) + +assert(model.checkPythonDump()) diff --git a/src/FeaturesPlugin/Test/TestDefeaturing_OnSolid2.py b/src/FeaturesPlugin/Test/TestDefeaturing_OnSolid2.py new file mode 100644 index 000000000..a7d7c5d7e --- /dev/null +++ b/src/FeaturesPlugin/Test/TestDefeaturing_OnSolid2.py @@ -0,0 +1,95 @@ +# Copyright (C) 2020 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 +# + +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(10.19197853506727, -21.07109716039953, 30.19197853506727, -21.07109716039953) +SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result()) +SketchLine_2 = Sketch_1.addLine(30.19197853506727, -21.07109716039953, 30.19197853506727, -6.071097160399531) +SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint()) +SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result()) +SketchLine_3 = Sketch_1.addLine(30.19197853506727, -6.071097160399531, 20.19197853506727, -6.071097160399531) +SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint()) +SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result()) +SketchLine_4 = Sketch_1.addLine(20.19197853506727, -6.071097160399531, 20.19197853506727, 8.928902839600468) +SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint()) +SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result()) +SketchLine_5 = Sketch_1.addLine(20.19197853506727, 8.928902839600468, 30.19197853506727, 8.928902839600468) +SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint()) +SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_5.result()) +SketchLine_6 = Sketch_1.addLine(30.19197853506727, 8.928902839600468, 30.19197853506727, 18.92890283960047) +SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint()) +SketchLine_7 = Sketch_1.addLine(30.19197853506727, 18.92890283960047, 10.19197853506727, 18.92890283960047) +SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint()) +SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_7.result()) +SketchLine_8 = Sketch_1.addLine(10.19197853506727, 18.92890283960047, 10.19197853506727, -21.07109716039953) +SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint()) +SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_8.endPoint()) +SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result()) +SketchConstraintVertical_3.setName("SketchConstraintVertical_4") +SketchConstraintCollinear_1 = Sketch_1.setCollinear(SketchLine_2.result(), SketchLine_6.result()) +SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 20) +SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_8.result(), 40) +SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_2.result(), 15) +SketchConstraintLength_4 = Sketch_1.setLength(SketchLine_6.result(), 10) +SketchConstraintLength_5 = Sketch_1.setLength(SketchLine_3.result(), 10) +model.do() +Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f-SketchLine_7f-SketchLine_8f")], model.selection(), 10, 0) +ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_3"), 0, model.selection(), 0, [model.selection("SOLID", "Extrusion_1_1")]) +Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_1")) +SketchLine_9 = Sketch_2.addLine(30.19197853506727, 5, 25.19197853506727, 5) +SketchLine_10 = Sketch_2.addLine(25.19197853506727, 5, 25.19197853506727, 10) +SketchLine_11 = Sketch_2.addLine(25.19197853506727, 10, 30.19197853506727, 10) +SketchLine_12 = Sketch_2.addLine(30.19197853506727, 10, 30.19197853506727, 5) +SketchConstraintCoincidence_9 = Sketch_2.setCoincident(SketchLine_12.endPoint(), SketchLine_9.startPoint()) +SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint()) +SketchConstraintCoincidence_11 = Sketch_2.setCoincident(SketchLine_10.endPoint(), SketchLine_11.startPoint()) +SketchConstraintCoincidence_12 = Sketch_2.setCoincident(SketchLine_11.endPoint(), SketchLine_12.startPoint()) +SketchConstraintHorizontal_5 = Sketch_2.setHorizontal(SketchLine_9.result()) +SketchConstraintVertical_4 = Sketch_2.setVertical(SketchLine_10.result()) +SketchConstraintVertical_4.setName("SketchConstraintVertical_5") +SketchConstraintHorizontal_6 = Sketch_2.setHorizontal(SketchLine_11.result()) +SketchConstraintVertical_5 = Sketch_2.setVertical(SketchLine_12.result()) +SketchConstraintVertical_5.setName("SketchConstraintVertical_6") +SketchProjection_1 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_2][Extrusion_1_1/To_Face]"), False) +SketchPoint_1 = SketchProjection_1.createdFeature() +SketchConstraintCoincidence_13 = Sketch_2.setCoincident(SketchLine_11.endPoint(), SketchPoint_1.result()) +SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_12.result(), SketchLine_11.result()) +SketchConstraintLength_6 = Sketch_2.setLength(SketchLine_12.result(), 5) +ExtrusionCut_1.setNestedSketch(Sketch_2) +Defeaturing_1 = model.addDefeaturing(Part_1_doc, [model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_4"), model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_5")]) +model.testHaveNamingSubshapes(Defeaturing_1, model, Part_1_doc) +model.end() + +from GeomAPI import * + +model.testNbResults(Defeaturing_1, 1) +model.testNbSubResults(Defeaturing_1, [0]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.SOLID, [1]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.FACE, [9]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.EDGE, [42]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.VERTEX, [84]) +model.testResultsVolumes(Defeaturing_1, [7625]) + +assert(model.checkPythonDump()) diff --git a/src/FeaturesPlugin/Test/TestDefeaturing_OnSolid3.py b/src/FeaturesPlugin/Test/TestDefeaturing_OnSolid3.py new file mode 100644 index 000000000..e56452268 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestDefeaturing_OnSolid3.py @@ -0,0 +1,95 @@ +# Copyright (C) 2020 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 +# + +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(10.19197853506727, -21.07109716039953, 30.19197853506727, -21.07109716039953) +SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result()) +SketchLine_2 = Sketch_1.addLine(30.19197853506727, -21.07109716039953, 30.19197853506727, -6.071097160399531) +SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint()) +SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result()) +SketchLine_3 = Sketch_1.addLine(30.19197853506727, -6.071097160399531, 20.19197853506727, -6.071097160399531) +SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint()) +SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result()) +SketchLine_4 = Sketch_1.addLine(20.19197853506727, -6.071097160399531, 20.19197853506727, 8.928902839600468) +SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint()) +SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result()) +SketchLine_5 = Sketch_1.addLine(20.19197853506727, 8.928902839600468, 30.19197853506727, 8.928902839600468) +SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint()) +SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_5.result()) +SketchLine_6 = Sketch_1.addLine(30.19197853506727, 8.928902839600468, 30.19197853506727, 18.92890283960047) +SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint()) +SketchLine_7 = Sketch_1.addLine(30.19197853506727, 18.92890283960047, 10.19197853506727, 18.92890283960047) +SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint()) +SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_7.result()) +SketchLine_8 = Sketch_1.addLine(10.19197853506727, 18.92890283960047, 10.19197853506727, -21.07109716039953) +SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint()) +SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_8.endPoint()) +SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result()) +SketchConstraintVertical_3.setName("SketchConstraintVertical_4") +SketchConstraintCollinear_1 = Sketch_1.setCollinear(SketchLine_2.result(), SketchLine_6.result()) +SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 20) +SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_8.result(), 40) +SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_2.result(), 15) +SketchConstraintLength_4 = Sketch_1.setLength(SketchLine_6.result(), 10) +SketchConstraintLength_5 = Sketch_1.setLength(SketchLine_3.result(), 10) +model.do() +Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f-SketchLine_7f-SketchLine_8f")], model.selection(), 10, 0) +ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_3"), 0, model.selection(), 0, [model.selection("SOLID", "Extrusion_1_1")]) +Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_1")) +SketchLine_9 = Sketch_2.addLine(30.19197853506727, 5, 25.19197853506727, 5) +SketchLine_10 = Sketch_2.addLine(25.19197853506727, 5, 25.19197853506727, 10) +SketchLine_11 = Sketch_2.addLine(25.19197853506727, 10, 30.19197853506727, 10) +SketchLine_12 = Sketch_2.addLine(30.19197853506727, 10, 30.19197853506727, 5) +SketchConstraintCoincidence_9 = Sketch_2.setCoincident(SketchLine_12.endPoint(), SketchLine_9.startPoint()) +SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint()) +SketchConstraintCoincidence_11 = Sketch_2.setCoincident(SketchLine_10.endPoint(), SketchLine_11.startPoint()) +SketchConstraintCoincidence_12 = Sketch_2.setCoincident(SketchLine_11.endPoint(), SketchLine_12.startPoint()) +SketchConstraintHorizontal_5 = Sketch_2.setHorizontal(SketchLine_9.result()) +SketchConstraintVertical_4 = Sketch_2.setVertical(SketchLine_10.result()) +SketchConstraintVertical_4.setName("SketchConstraintVertical_5") +SketchConstraintHorizontal_6 = Sketch_2.setHorizontal(SketchLine_11.result()) +SketchConstraintVertical_5 = Sketch_2.setVertical(SketchLine_12.result()) +SketchConstraintVertical_5.setName("SketchConstraintVertical_6") +SketchProjection_1 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_2][Extrusion_1_1/To_Face]"), False) +SketchPoint_1 = SketchProjection_1.createdFeature() +SketchConstraintCoincidence_13 = Sketch_2.setCoincident(SketchLine_11.endPoint(), SketchPoint_1.result()) +SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_12.result(), SketchLine_11.result()) +SketchConstraintLength_6 = Sketch_2.setLength(SketchLine_12.result(), 5) +ExtrusionCut_1.setNestedSketch(Sketch_2) +Defeaturing_1 = model.addDefeaturing(Part_1_doc, [model.selection("FACE", "ExtrusionCut_1_1/Generated_Face&Sketch_2/SketchLine_10"), model.selection("FACE", "ExtrusionCut_1_1/Generated_Face&Sketch_2/SketchLine_9")]) +model.testHaveNamingSubshapes(Defeaturing_1, model, Part_1_doc) +model.end() + +from GeomAPI import * + +model.testNbResults(Defeaturing_1, 1) +model.testNbSubResults(Defeaturing_1, [0]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.SOLID, [1]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.FACE, [10]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.EDGE, [48]) +model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.VERTEX, [96]) +model.testResultsVolumes(Defeaturing_1, [6500]) + +assert(model.checkPythonDump()) diff --git a/src/FeaturesPlugin/defeaturing_widget.xml b/src/FeaturesPlugin/defeaturing_widget.xml new file mode 100644 index 000000000..9a0303e82 --- /dev/null +++ b/src/FeaturesPlugin/defeaturing_widget.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/src/FeaturesPlugin/icons/defeaturing.png b/src/FeaturesPlugin/icons/defeaturing.png new file mode 100644 index 000000000..9b5ecc8d6 Binary files /dev/null and b/src/FeaturesPlugin/icons/defeaturing.png differ diff --git a/src/FeaturesPlugin/plugin-Features.xml b/src/FeaturesPlugin/plugin-Features.xml index 3477954d1..cba1b4292 100644 --- a/src/FeaturesPlugin/plugin-Features.xml +++ b/src/FeaturesPlugin/plugin-Features.xml @@ -115,7 +115,7 @@ - + @@ -128,6 +128,10 @@ icon="icons/Features/fusion_faces.png" auto_preview="true" helpfile="FeaturesPlugin/fusionFacesFeature.html"> + + + diff --git a/src/GeomAPI/GeomAPI_Shape.cpp b/src/GeomAPI/GeomAPI_Shape.cpp index a0c9061d7..ce7788b54 100644 --- a/src/GeomAPI/GeomAPI_Shape.cpp +++ b/src/GeomAPI/GeomAPI_Shape.cpp @@ -751,3 +751,21 @@ bool GeomAPI_Shape::ComparatorWithOri::operator()( } return isLess; } + +int GeomAPI_Shape::Hash::operator()(const std::shared_ptr& theShape) const +{ + const TopoDS_Shape& aShape = theShape->impl(); + return aShape.HashCode(IntegerLast()); +} + +bool GeomAPI_Shape::Equal::operator()(const std::shared_ptr& theShape1, + const std::shared_ptr& theShape2) const +{ + const TopoDS_Shape& aShape1 = theShape1->impl(); + const TopoDS_Shape& aShape2 = theShape2->impl(); + + Standard_Integer aHash1 = aShape1.Location().HashCode(IntegerLast()); + Standard_Integer aHash2 = aShape2.Location().HashCode(IntegerLast()); + + return aShape1.TShape() == aShape2.TShape() && aHash1 == aHash2; +} diff --git a/src/GeomAPI/GeomAPI_Shape.h b/src/GeomAPI/GeomAPI_Shape.h index 7c3a2a6cc..ec6e57374 100644 --- a/src/GeomAPI/GeomAPI_Shape.h +++ b/src/GeomAPI/GeomAPI_Shape.h @@ -249,6 +249,25 @@ public: bool operator ()(const std::shared_ptr& theShape1, const std::shared_ptr& theShape2) const; }; + + /// \brief Hash code for the shape + class Hash + { + public: + /// Return Hash value according to the address of the shape + GEOMAPI_EXPORT + int operator ()(const std::shared_ptr& theShape) const; + }; + + /// \brief Compare addresses of shapes + class Equal + { + public: + /// Return \c true if the address of the shapes are equal + GEOMAPI_EXPORT + bool operator ()(const std::shared_ptr& theShape1, + const std::shared_ptr& theShape2) const; + }; }; //! Pointer on list of shapes diff --git a/src/GeomAlgoAPI/CMakeLists.txt b/src/GeomAlgoAPI/CMakeLists.txt index 5861ac8d8..391acc8f6 100644 --- a/src/GeomAlgoAPI/CMakeLists.txt +++ b/src/GeomAlgoAPI/CMakeLists.txt @@ -84,6 +84,7 @@ SET(PROJECT_HEADERS GeomAlgoAPI_MapShapesAndAncestors.h GeomAlgoAPI_Projection.h GeomAlgoAPI_Chamfer.h + GeomAlgoAPI_Defeaturing.h ) SET(PROJECT_SOURCES @@ -147,6 +148,7 @@ SET(PROJECT_SOURCES GeomAlgoAPI_MapShapesAndAncestors.cpp GeomAlgoAPI_Projection.cpp GeomAlgoAPI_Chamfer.cpp + GeomAlgoAPI_Defeaturing.cpp ) SET(PROJECT_LIBRARIES diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Defeaturing.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Defeaturing.cpp new file mode 100644 index 000000000..9b058e8b3 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Defeaturing.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2020 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 +#include + +#include + +GeomAlgoAPI_Defeaturing::GeomAlgoAPI_Defeaturing(const GeomShapePtr& theBaseSolid, + const ListOfShape& theFacesToRemove) +{ + build(theBaseSolid, theFacesToRemove); +} + +void GeomAlgoAPI_Defeaturing::build(const GeomShapePtr& theBaseSolid, + const ListOfShape& theFacesToRemove) +{ + if (!theBaseSolid || theFacesToRemove.empty()) + return; + + BRepAlgoAPI_Defeaturing* aDefeaturing = new BRepAlgoAPI_Defeaturing; + aDefeaturing->SetShape(theBaseSolid->impl()); + aDefeaturing->SetRunParallel(Standard_True); + + // collect faces to remove + TopTools_ListOfShape aFaces; + for (ListOfShape::const_iterator anIt = theFacesToRemove.begin(); + anIt != theFacesToRemove.end(); ++anIt) + aDefeaturing->AddFaceToRemove((*anIt)->impl()); + + setImpl(aDefeaturing); + setBuilderType(OCCT_BRepBuilderAPI_MakeShape); + + // build and get result + aDefeaturing->Build(); + if (!aDefeaturing->IsDone() || aDefeaturing->HasErrors() || aDefeaturing->HasWarnings()) { + std::ostringstream errors; + aDefeaturing->DumpErrors(errors); + aDefeaturing->DumpWarnings(errors); + myError = errors.str(); + return; + } + + TopoDS_Shape aResult = GeomAlgoAPI_DFLoader::refineResult(aDefeaturing->Shape()); + + std::shared_ptr aShape(new GeomAPI_Shape()); + aShape->setImpl(new TopoDS_Shape(aResult)); + setShape(aShape); + setDone(true); +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Defeaturing.h b/src/GeomAlgoAPI/GeomAlgoAPI_Defeaturing.h new file mode 100644 index 000000000..04a1bf070 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Defeaturing.h @@ -0,0 +1,46 @@ +// Copyright (C) 2020 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 GeomAlgoAPI_Defeaturing_H_ +#define GeomAlgoAPI_Defeaturing_H_ + +#include +#include + +#include + +/// \class GeomAlgoAPI_Defeaturing +/// \ingroup DataAlgo +/// \brief Perform Defeaturing algorithm +class GeomAlgoAPI_Defeaturing : public GeomAlgoAPI_MakeShape +{ +public: + /// Run Defeaturing operation on the solid for the given list of faces. + /// \param theBaseSolid a changing solid + /// \param theFacesToRemove list of faces to be removed + GEOMALGOAPI_EXPORT GeomAlgoAPI_Defeaturing(const GeomShapePtr& theBaseSolid, + const ListOfShape& theFacesToRemove); + +private: + /// Perform Defeaturing operation. + void build(const GeomShapePtr& theBaseSolid, + const ListOfShape& theFacesToRemove); +}; + +#endif diff --git a/src/PythonAPI/model/features/__init__.py b/src/PythonAPI/model/features/__init__.py index 74d9637b9..ca5f25fec 100644 --- a/src/PythonAPI/model/features/__init__.py +++ b/src/PythonAPI/model/features/__init__.py @@ -32,3 +32,4 @@ from FeaturesAPI import addFusionFaces from FeaturesAPI import measureLength, measureDistance, measureRadius, measureAngle from FeaturesAPI import addRemoveResults from FeaturesAPI import addCopy, addImportResult +from FeaturesAPI import addDefeaturing