Salome HOME
Issue #17342: 3D Model defeaturing
authorazv <azv@opencascade.com>
Wed, 29 Jan 2020 12:13:15 +0000 (15:13 +0300)
committerazv <azv@opencascade.com>
Thu, 30 Jan 2020 10:28:31 +0000 (13:28 +0300)
28 files changed:
src/FeaturesAPI/CMakeLists.txt
src/FeaturesAPI/FeaturesAPI.i
src/FeaturesAPI/FeaturesAPI_Defeaturing.cpp [new file with mode: 0644]
src/FeaturesAPI/FeaturesAPI_Defeaturing.h [new file with mode: 0644]
src/FeaturesAPI/FeaturesAPI_swig.h
src/FeaturesPlugin/CMakeLists.txt
src/FeaturesPlugin/FeaturesPlugin_Defeaturing.cpp [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_Defeaturing.h [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.h
src/FeaturesPlugin/Test/TestDefeaturing_ErrorMsg.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestDefeaturing_OnCompound.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestDefeaturing_OnCompsolid1.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestDefeaturing_OnCompsolid2.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestDefeaturing_OnCompsolid3.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestDefeaturing_OnSolid1.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestDefeaturing_OnSolid2.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestDefeaturing_OnSolid3.py [new file with mode: 0644]
src/FeaturesPlugin/defeaturing_widget.xml [new file with mode: 0644]
src/FeaturesPlugin/icons/defeaturing.png [new file with mode: 0644]
src/FeaturesPlugin/plugin-Features.xml
src/GeomAPI/GeomAPI_Shape.cpp
src/GeomAPI/GeomAPI_Shape.h
src/GeomAlgoAPI/CMakeLists.txt
src/GeomAlgoAPI/GeomAlgoAPI_Defeaturing.cpp [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_Defeaturing.h [new file with mode: 0644]
src/PythonAPI/model/features/__init__.py

index 921b2eec785f6bdb58b940705b9a2a52ab3c1bcc..2b6df755fbc79463e186f9871574952685c7c31d 100644 (file)
@@ -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
index 41999dee9d046104a61c665faa65ee525b38842d..a77c6a1c4b1692a44593081af896bf84ba17b4dd 100644 (file)
@@ -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<std::list<ModelHighAPI_Selection>, bool>, const std::pair<std::list<ModelHighAPI_Selection>, bool> & {
 %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 (file)
index 0000000..5accac9
--- /dev/null
@@ -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 <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Tools.h>
+
+FeaturesAPI_Defeaturing::FeaturesAPI_Defeaturing(
+    const std::shared_ptr<ModelAPI_Feature>& theFeature)
+  : ModelHighAPI_Interface(theFeature)
+{
+  initialize();
+}
+
+FeaturesAPI_Defeaturing::FeaturesAPI_Defeaturing(
+    const std::shared_ptr<ModelAPI_Feature>& theFeature,
+    const std::list<ModelHighAPI_Selection>& theFacesToRemove)
+  : ModelHighAPI_Interface(theFeature)
+{
+  if (initialize())
+    setFaces(theFacesToRemove);
+}
+
+FeaturesAPI_Defeaturing::~FeaturesAPI_Defeaturing()
+{
+}
+
+void FeaturesAPI_Defeaturing::setFaces(const std::list<ModelHighAPI_Selection>& 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<ModelAPI_Document>& thePart,
+                              const std::list<ModelHighAPI_Selection>& theFaces)
+{
+  std::shared_ptr<ModelAPI_Feature> 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 (file)
index 0000000..960934d
--- /dev/null
@@ -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 <FeaturesPlugin_Defeaturing.h>
+
+#include <ModelHighAPI_Interface.h>
+#include <ModelHighAPI_Macro.h>
+
+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<ModelAPI_Feature>& theFeature);
+
+  /// Constructor with values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_Defeaturing(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                   const std::list<ModelHighAPI_Selection>& 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<ModelHighAPI_Selection>& 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<FeaturesAPI_Defeaturing> DefeaturingPtr;
+
+/// \ingroup CPPHighAPI
+/// \brief Create Defeaturing feature.
+FEATURESAPI_EXPORT
+DefeaturingPtr addDefeaturing(const std::shared_ptr<ModelAPI_Document>& thePart,
+                              const std::list<ModelHighAPI_Selection>& theFaces);
+
+#endif // FeaturesAPI_Defeaturing_H_
index ca0d4b6dbdc894c4ab0a1a6a7d86581ea3383a69..af2866c3ee671b5caf762ccc84ad8aaa7e80e27a 100644 (file)
@@ -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"
index b5b856d714d9b48314dbdbc8b9aa8b643c86838a..80d67e4692de9beb5760aed1af8b0a187ec6fba2 100644 (file)
@@ -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 (file)
index 0000000..104667e
--- /dev/null
@@ -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 <FeaturesPlugin_Defeaturing.h>
+#include <FeaturesPlugin_Tools.h>
+
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_Tools.h>
+
+#include <GeomAPI_ShapeExplorer.h>
+
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_Defeaturing.h>
+#include <GeomAlgoAPI_MakeShapeList.h>
+#include <GeomAlgoAPI_Tools.h>
+
+#include <unordered_map>
+
+
+FeaturesPlugin_Defeaturing::FeaturesPlugin_Defeaturing()
+{
+}
+
+void FeaturesPlugin_Defeaturing::initAttributes()
+{
+  data()->addAttribute(OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
+}
+
+
+void FeaturesPlugin_Defeaturing::execute()
+{
+  typedef std::unordered_map<GeomShapePtr, ListOfShape,
+                             GeomAPI_Shape::Hash, GeomAPI_Shape::Equal> 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<GeomAlgoAPI_Defeaturing> anAlgo;
+  int aResultIndex = 0;
+  std::string anError;
+
+  std::vector<FeaturesPlugin_Tools::ResultBaseAlgo> 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<ModelAPI_ResultBody> 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 (file)
index 0000000..c703e02
--- /dev/null
@@ -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 <ModelAPI_Feature.h>
+
+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<ModelAPI_ResultBody> theResultBody,
+                    const std::shared_ptr<GeomAPI_Shape> theBaseShape,
+                    const std::shared_ptr<GeomAPI_Shape> theResultShape,
+                    const std::shared_ptr<GeomAlgoAPI_MakeShape>& theMakeShape);
+};
+
+#endif
index 8ade62615bd4d976d6a43b051f9306c6c5d614a3..5f226c11b5d615d0fde56686f2628a7532dcf467 100644 (file)
@@ -25,6 +25,7 @@
 #include <FeaturesPlugin_BooleanSmash.h>
 #include <FeaturesPlugin_BooleanFill.h>
 #include <FeaturesPlugin_Chamfer.h>
+#include <FeaturesPlugin_Defeaturing.h>
 #include <FeaturesPlugin_Extrusion.h>
 #include <FeaturesPlugin_ExtrusionCut.h>
 #include <FeaturesPlugin_ExtrusionFuse.h>
@@ -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);
   }
 
 
index 07db4dd86f32d32371a2dede20b1e61811bde22f..6426d94739bba43533d8efb7910e3ad6f1be5298 100644 (file)
@@ -1877,3 +1877,42 @@ bool FeaturesPlugin_ValidatorBooleanCommonArguments::isNotObligatory(
   return false;
 }
 // LCOV_EXCL_STOP
+
+//==================================================================================================
+bool FeaturesPlugin_ValidatorDefeaturingSelection::isValid(
+    const AttributePtr& theAttribute,
+    const std::list<std::string>& theArguments,
+    Events_InfoMessage& theError) const
+{
+  AttributeSelectionListPtr anAttrSelectionList =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(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;
+}
index c2ec597dfbc60dba004f592bc404ef48abd0fddc..da3222d1ec7e0c4a71cbd58c73f91936ebb00de4 100644 (file)
@@ -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<std::string>& 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 (file)
index 0000000..387605f
--- /dev/null
@@ -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 (file)
index 0000000..ce66d04
--- /dev/null
@@ -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 (file)
index 0000000..a6807c5
--- /dev/null
@@ -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 (file)
index 0000000..6840119
--- /dev/null
@@ -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 (file)
index 0000000..c63df13
--- /dev/null
@@ -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 (file)
index 0000000..8feef55
--- /dev/null
@@ -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 (file)
index 0000000..a7d7c5d
--- /dev/null
@@ -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 (file)
index 0000000..e564522
--- /dev/null
@@ -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 (file)
index 0000000..9a0303e
--- /dev/null
@@ -0,0 +1,12 @@
+<source>
+  <multi_selector id="main_objects"
+                  label="Faces to remove"
+                  icon=""
+                  tooltip="Select faces"
+                  shape_types="faces"
+                  use_choice="false"
+                  concealment="true">
+    <validator id="PartSet_DifferentObjects"/>
+    <validator id="FeaturesPlugin_ValidatorDefeaturingSelection"/>
+  </multi_selector>
+</source>
diff --git a/src/FeaturesPlugin/icons/defeaturing.png b/src/FeaturesPlugin/icons/defeaturing.png
new file mode 100644 (file)
index 0000000..9b5ecc8
Binary files /dev/null and b/src/FeaturesPlugin/icons/defeaturing.png differ
index 3477954d1e4987982a59579aaa3724cfee276cfa..cba1b4292fbb3984de3503a22d9e2d1a67284638 100644 (file)
         <multi_selector id="results" concealment="true"/>
       </feature>
     </group>
-    <group id="Fillet">
+    <group id="Features">
       <feature id="Fillet" title="Fillet" tooltip="Perform fillet on face or edge"
                icon="icons/Features/fillet.png" auto_preview="true" helpfile="filletFeature.html">
         <source path="fillet_widget.xml"/>
                icon="icons/Features/fusion_faces.png" auto_preview="true" helpfile="FeaturesPlugin/fusionFacesFeature.html">
         <source path="fusion_faces_widget.xml"/>
       </feature>
+      <feature id="Defeaturing" title="Defeaturing" tooltip="Perform removing faces from solid"
+               icon="icons/Features/defeaturing.png" auto_preview="true" helpfile="defeaturingFeature.html">
+        <source path="defeaturing_widget.xml"/>
+      </feature>
     </group>
   </workbench>
   <workbench id="Part">
index a0c9061d78a4f1a7cf0eea160ce47db96f211fbc..ce7788b54eacc00f2339011271663f62e27b0435 100644 (file)
@@ -751,3 +751,21 @@ bool GeomAPI_Shape::ComparatorWithOri::operator()(
   }
   return isLess;
 }
+
+int GeomAPI_Shape::Hash::operator()(const std::shared_ptr<GeomAPI_Shape>& theShape) const
+{
+  const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
+  return aShape.HashCode(IntegerLast());
+}
+
+bool GeomAPI_Shape::Equal::operator()(const std::shared_ptr<GeomAPI_Shape>& theShape1,
+                                      const std::shared_ptr<GeomAPI_Shape>& theShape2) const
+{
+  const TopoDS_Shape& aShape1 = theShape1->impl<TopoDS_Shape>();
+  const TopoDS_Shape& aShape2 = theShape2->impl<TopoDS_Shape>();
+
+  Standard_Integer aHash1 = aShape1.Location().HashCode(IntegerLast());
+  Standard_Integer aHash2 = aShape2.Location().HashCode(IntegerLast());
+
+  return aShape1.TShape() == aShape2.TShape() && aHash1 == aHash2;
+}
index 7c3a2a6cc513ca93e36928b5067f86f6042ac2c8..ec6e5737475df793f1c9dc9c5814a9f27b47b778 100644 (file)
@@ -249,6 +249,25 @@ public:
       bool operator ()(const std::shared_ptr<GeomAPI_Shape>& theShape1,
                        const std::shared_ptr<GeomAPI_Shape>& 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<GeomAPI_Shape>& 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<GeomAPI_Shape>& theShape1,
+                     const std::shared_ptr<GeomAPI_Shape>& theShape2) const;
+  };
 };
 
 //! Pointer on list of shapes
index 5861ac8d81332276b0175babe5bcc5af6ad7910a..391acc8f641b11991f567fbccd7aa4a64b7ecf3b 100644 (file)
@@ -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 (file)
index 0000000..9b058e8
--- /dev/null
@@ -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 <GeomAlgoAPI_Defeaturing.h>
+#include <GeomAlgoAPI_DFLoader.h>
+
+#include <BRepAlgoAPI_Defeaturing.hxx>
+
+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<TopoDS_Shape>());
+  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<TopoDS_Shape>());
+
+  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<GeomAPI_Shape> 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 (file)
index 0000000..04a1bf0
--- /dev/null
@@ -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 <GeomAlgoAPI.h>
+#include <GeomAlgoAPI_MakeShape.h>
+
+#include <GeomAPI_Shape.h>
+
+/// \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
index 74d9637b97ed5d218b36bdb914ec258cb49f3a04..ca5f25fecf83bd41ff08317a39ba251d7d912f12 100644 (file)
@@ -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