Salome HOME
added new Sewing feature
authormbs <martin.bernhard@opencascade.com>
Wed, 30 Nov 2022 15:41:31 +0000 (15:41 +0000)
committerGérald NICOLAS <gerald.nicolas@edf.fr>
Wed, 1 Feb 2023 16:32:06 +0000 (17:32 +0100)
18 files changed:
src/FeaturesAPI/CMakeLists.txt
src/FeaturesAPI/FeaturesAPI.i
src/FeaturesAPI/FeaturesAPI_Sewing.cpp [new file with mode: 0644]
src/FeaturesAPI/FeaturesAPI_Sewing.h [new file with mode: 0644]
src/FeaturesAPI/FeaturesAPI_swig.h
src/FeaturesPlugin/CMakeLists.txt
src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp
src/FeaturesPlugin/FeaturesPlugin_Sewing.cpp [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_Sewing.h [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.h
src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts
src/FeaturesPlugin/FeaturesPlugin_msg_ru.ts
src/FeaturesPlugin/icons/sewing.png [new file with mode: 0644]
src/FeaturesPlugin/plugin-Features.xml
src/FeaturesPlugin/sewing_widget.xml [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_Sewing.cpp
src/GeomAlgoAPI/GeomAlgoAPI_Sewing.h

index 554d5ddaa44df1fbbd6953c961df67c612d60eef..1d929468d5be139e767586abf50c9d08f688f088 100644 (file)
@@ -47,6 +47,7 @@ SET(PROJECT_HEADERS
   FeaturesAPI_RevolutionBoolean.h
   FeaturesAPI_Rotation.h
   FeaturesAPI_Scale.h
+  FeaturesAPI_Sewing.h
   FeaturesAPI_Symmetry.h
   FeaturesAPI_Translation.h
   FeaturesAPI_Union.h
@@ -86,6 +87,7 @@ SET(PROJECT_SOURCES
   FeaturesAPI_RevolutionBoolean.cpp
   FeaturesAPI_Rotation.cpp
   FeaturesAPI_Scale.cpp
+  FeaturesAPI_Sewing.cpp
   FeaturesAPI_Symmetry.cpp
   FeaturesAPI_Translation.cpp
   FeaturesAPI_Union.cpp
index 2cc08c164e24296392f064da13953eb95e2f89ba..4a4db824a223f66f3e2297ef4fe0181b3ad6f5dd 100644 (file)
@@ -50,6 +50,7 @@
 %feature("kwargs") addPlacement;
 %feature("kwargs") addRotation;
 %feature("kwargs") addScale;
+%feature("kwargs") addSewing;
 %feature("kwargs") addSplit;
 %feature("kwargs") addSmash;
 %feature("kwargs") addSymmetry;
@@ -87,6 +88,7 @@
 %shared_ptr(FeaturesAPI_RevolutionFuse)
 %shared_ptr(FeaturesAPI_Rotation)
 %shared_ptr(FeaturesAPI_Scale)
+%shared_ptr(FeaturesAPI_Sewing)
 %shared_ptr(FeaturesAPI_Symmetry)
 %shared_ptr(FeaturesAPI_Translation)
 %shared_ptr(FeaturesAPI_Union)
 %include "FeaturesAPI_RevolutionBoolean.h"
 %include "FeaturesAPI_Rotation.h"
 %include "FeaturesAPI_Scale.h"
+%include "FeaturesAPI_Sewing.h"
 %include "FeaturesAPI_Symmetry.h"
 %include "FeaturesAPI_Translation.h"
 %include "FeaturesAPI_Union.h"
diff --git a/src/FeaturesAPI/FeaturesAPI_Sewing.cpp b/src/FeaturesAPI/FeaturesAPI_Sewing.cpp
new file mode 100644 (file)
index 0000000..65aa608
--- /dev/null
@@ -0,0 +1,115 @@
+// Copyright (C) 2014-2022  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_Sewing.h"
+
+#include <ModelHighAPI_Double.h>
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Tools.h>
+
+//==================================================================================================
+FeaturesAPI_Sewing::FeaturesAPI_Sewing(const std::shared_ptr<ModelAPI_Feature>& theFeature)
+: ModelHighAPI_Interface(theFeature)
+{
+  initialize();
+}
+
+//==================================================================================================
+FeaturesAPI_Sewing::FeaturesAPI_Sewing(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                       const std::list<ModelHighAPI_Selection>& theMainObjects,
+                                       const ModelHighAPI_Double& theTolerance,
+                                       bool theIsAllowNonManifold/*=false*/,
+                                       bool theIsAlwaysCreateResult/*=true*/)
+: ModelHighAPI_Interface(theFeature)
+{
+  if (initialize()) {
+    fillAttribute(theMainObjects, mainObjects());
+    setTolerance(theTolerance);
+    setIsAllowNonManifold(theIsAllowNonManifold);
+    setIsAlwaysCreateResult(theIsAlwaysCreateResult);
+  }
+}
+
+//==================================================================================================
+FeaturesAPI_Sewing::~FeaturesAPI_Sewing()
+{
+}
+
+//==================================================================================================
+void FeaturesAPI_Sewing::setMainObjects(const std::list<ModelHighAPI_Selection>& theMainObjects)
+{
+  fillAttribute(theMainObjects, mainObjects());
+  execute();
+}
+
+//==================================================================================================
+void FeaturesAPI_Sewing::setTolerance(const ModelHighAPI_Double& theTolerance)
+{
+  fillAttribute(theTolerance, tolerance());
+  execute();
+}
+
+//==================================================================================================
+void FeaturesAPI_Sewing::setIsAllowNonManifold(bool theFlag)
+{
+  fillAttribute(theFlag, isAllowNonManifold());
+  execute();
+}
+
+//==================================================================================================
+void FeaturesAPI_Sewing::setIsAlwaysCreateResult(bool theFlag)
+{
+  fillAttribute(theFlag, isAlwaysCreateResult());
+  execute();
+}
+
+//==================================================================================================
+void FeaturesAPI_Sewing::dump(ModelHighAPI_Dumper& theDumper) const
+{
+  FeaturePtr aBase = feature();
+  const std::string& aDocName = theDumper.name(aBase->document());
+
+  AttributeSelectionListPtr anAttrObjects =
+    aBase->selectionList(FeaturesPlugin_Sewing::OBJECTS_LIST_ID());
+  theDumper << aBase << " = model.addSewing(" << aDocName << ", " << anAttrObjects;
+
+  AttributeDoublePtr anAttrTolerance = aBase->real(FeaturesPlugin_Sewing::TOLERANCE_ID());
+  theDumper << ", " << anAttrTolerance;
+
+  AttributeBooleanPtr anAttrAllowNonMFold = aBase->boolean(FeaturesPlugin_Sewing::ALLOW_NON_MANIFOLD_ID());
+  theDumper << ", " << anAttrAllowNonMFold;
+
+  AttributeBooleanPtr anAttrAlwaysResult = aBase->boolean(FeaturesPlugin_Sewing::ALWAYS_CREATE_RESULT_ID());
+  theDumper << ", " << anAttrAlwaysResult;
+
+  theDumper << ")" << std::endl;
+}
+
+//==================================================================================================
+SewingPtr addSewing(const std::shared_ptr<ModelAPI_Document>& thePart,
+                    const std::list<ModelHighAPI_Selection>& theMainObjects,
+                    const ModelHighAPI_Double& theTolerance,
+                    const bool theIsAllowNonManifold,
+                    const bool theIsAlwaysCreateResult)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_Sewing::ID());
+  SewingPtr aSewing;
+  aSewing.reset(new FeaturesAPI_Sewing(aFeature, theMainObjects, theTolerance, theIsAllowNonManifold, theIsAlwaysCreateResult));
+  return aSewing;
+}
diff --git a/src/FeaturesAPI/FeaturesAPI_Sewing.h b/src/FeaturesAPI/FeaturesAPI_Sewing.h
new file mode 100644 (file)
index 0000000..049294b
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright (C) 2014-2022  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_SEWING_H_
+#define FEATURESAPI_SEWING_H_
+
+#include "FeaturesAPI.h"
+
+#include <FeaturesPlugin_Sewing.h>
+
+#include <ModelHighAPI_Interface.h>
+#include <ModelHighAPI_Macro.h>
+
+class ModelHighAPI_Double;
+class ModelHighAPI_Dumper;
+class ModelHighAPI_Selection;
+
+/// \class FeaturesAPI_Sewing
+/// \ingroup CPPHighAPI
+/// \brief Interface for Sewing feature.
+class FeaturesAPI_Sewing: public ModelHighAPI_Interface
+{
+public:
+  /// Constructor without values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_Sewing(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+  /// Constructor with values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_Sewing(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                              const std::list<ModelHighAPI_Selection>& theMainObjects,
+                              const ModelHighAPI_Double& theTolerance,
+                              bool theIsAllowNonManifold = false,
+                              bool theIsAlwaysCreateResult = true);
+
+  /// Destructor.
+  FEATURESAPI_EXPORT
+  virtual ~FeaturesAPI_Sewing();
+
+  INTERFACE_4(FeaturesPlugin_Sewing::ID(),
+              mainObjects, FeaturesPlugin_Sewing::OBJECTS_LIST_ID(),
+              ModelAPI_AttributeSelectionList, /** Main objects */,
+              tolerance, FeaturesPlugin_Sewing::TOLERANCE_ID(),
+              ModelAPI_AttributeDouble, /** Tolerance */,
+              isAllowNonManifold, FeaturesPlugin_Sewing::ALLOW_NON_MANIFOLD_ID(),
+              ModelAPI_AttributeBoolean, /** Allow Non-Manifold Shapes */,
+              isAlwaysCreateResult, FeaturesPlugin_Sewing::ALWAYS_CREATE_RESULT_ID(),
+              ModelAPI_AttributeBoolean, /** Always Create Result */)
+
+  /// Set main objects.
+  FEATURESAPI_EXPORT
+  void setMainObjects(const std::list<ModelHighAPI_Selection>& theMainObjects);
+
+  /// Set the tolerance.
+  FEATURESAPI_EXPORT
+  void setTolerance(const ModelHighAPI_Double& theTolerance);
+
+  /// Set flag whether to allow non-manifold results.
+  FEATURESAPI_EXPORT
+  void setIsAllowNonManifold(bool theFlag);
+
+  /// Set flag whether to always create a result.
+  FEATURESAPI_EXPORT
+  void setIsAlwaysCreateResult(bool theFlag);
+
+  /// Dump wrapped feature
+  FEATURESAPI_EXPORT
+  virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+};
+
+/// Pointer on Sewing object.
+typedef std::shared_ptr<FeaturesAPI_Sewing> SewingPtr;
+
+/// \ingroup CPPHighAPI
+/// \brief Create Sewing feature.
+FEATURESAPI_EXPORT
+SewingPtr addSewing(const std::shared_ptr<ModelAPI_Document>& thePart,
+                    const std::list<ModelHighAPI_Selection>& theMainObjects,
+                    const ModelHighAPI_Double& theTolerance,
+                    const bool theIsAllowNonManifold,
+                    const bool theIsAlwaysCreateResult);
+
+#endif // FEATURESAPI_SEWING_H_
index f03aad755c7c49bf7f09f49f1037893f70dd540a..d46a5c084bc5431f3d6742ae27935c3a2a99c9ba 100644 (file)
@@ -49,6 +49,7 @@
   #include "FeaturesAPI_RevolutionBoolean.h"
   #include "FeaturesAPI_Rotation.h"
   #include "FeaturesAPI_Scale.h"
+  #include "FeaturesAPI_Sewing.h"
   #include "FeaturesAPI_Symmetry.h"
   #include "FeaturesAPI_Translation.h"
   #include "FeaturesAPI_Union.h"
index 9cc7503140a3a06a1b139d8a3f16dd61102c4d92..3f9fb4e533baf7fa99075e9c9944e44b836597c9 100644 (file)
@@ -57,6 +57,7 @@ SET(PROJECT_HEADERS
     FeaturesPlugin_Tools.h
     FeaturesPlugin_Symmetry.h
     FeaturesPlugin_Scale.h
+    FeaturesPlugin_Sewing.h
     FeaturesPlugin_MultiTranslation.h
     FeaturesPlugin_MultiRotation.h
     FeaturesPlugin_Fillet.h
@@ -113,6 +114,7 @@ SET(PROJECT_SOURCES
     FeaturesPlugin_Tools.cpp
     FeaturesPlugin_Symmetry.cpp
     FeaturesPlugin_Scale.cpp
+    FeaturesPlugin_Sewing.cpp
     FeaturesPlugin_MultiTranslation.cpp
     FeaturesPlugin_MultiRotation.cpp
     FeaturesPlugin_Fillet.cpp
@@ -159,6 +161,7 @@ SET(XML_RESOURCES
   union_widget.xml
   symmetry_widget.xml
   scale_widget.xml
+  sewing_widget.xml
   multitranslation_widget.xml
   multirotation_widget.xml
   fillet_widget.xml
index ca33e7adcbb5cc1408bcbc6d338a836cd3976581..56f86af9ce69a438c8dee916981d24f0c64b4e7d 100644 (file)
@@ -53,6 +53,7 @@
 #include <FeaturesPlugin_RevolutionFuse.h>
 #include <FeaturesPlugin_Rotation.h>
 #include <FeaturesPlugin_Scale.h>
+#include <FeaturesPlugin_Sewing.h>
 #include <FeaturesPlugin_Symmetry.h>
 #include <FeaturesPlugin_Translation.h>
 #include <FeaturesPlugin_Union.h>
@@ -134,6 +135,8 @@ FeaturesPlugin_Plugin::FeaturesPlugin_Plugin()
                               new FeaturesPlugin_ValidatorImportResults);
   aFactory->registerValidator("FeaturesPlugin_ValidatorDefeaturingSelection",
                               new FeaturesPlugin_ValidatorDefeaturingSelection);
+  aFactory->registerValidator("FeaturesPlugin_ValidatorSewingSelection",
+                              new FeaturesPlugin_ValidatorSewingSelection);
 
   // register this plugin
   ModelAPI_Session::get()->registerPlugin(this);
@@ -189,6 +192,8 @@ FeaturePtr FeaturesPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new FeaturesPlugin_Symmetry);
   } else if (theFeatureID == FeaturesPlugin_Scale::ID()) {
     return FeaturePtr(new FeaturesPlugin_Scale);
+  } else if (theFeatureID == FeaturesPlugin_Sewing::ID()) {
+    return FeaturePtr(new FeaturesPlugin_Sewing);
   } else if (theFeatureID == FeaturesPlugin_MultiTranslation::ID()) {
     return FeaturePtr(new FeaturesPlugin_MultiTranslation);
   } else if (theFeatureID == FeaturesPlugin_MultiRotation::ID()) {
diff --git a/src/FeaturesPlugin/FeaturesPlugin_Sewing.cpp b/src/FeaturesPlugin/FeaturesPlugin_Sewing.cpp
new file mode 100644 (file)
index 0000000..8282f66
--- /dev/null
@@ -0,0 +1,188 @@
+// Copyright (C) 2014-2022  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_Sewing.h>
+
+//#include <GeomAlgoAPI_MakeShape.h>
+#include <GeomAlgoAPI_Sewing.h>
+#include <GeomAlgoAPI_Tools.h>
+
+//#include <GeomAPI_PlanarEdges.h>
+#include <GeomAPI_Shape.h>
+//#include <GeomAPI_ShapeExplorer.h>
+//#include <GeomAPI_ShapeIterator.h>
+
+#include <ModelAPI_AttributeBoolean.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_ResultBody.h>
+//#include <ModelAPI_ResultConstruction.h>
+
+//---------------------------------------------------------
+// #define USE_DEBUG
+// #define DEBUG
+// static const char *dbg_class = "FeaturesPlugin_Sewing";
+// #include "MBDebug.h"
+// #include "MBModel.h"
+// #include "MBGeom.h"
+//---------------------------------------------------------
+
+
+
+//=================================================================================================
+FeaturesPlugin_Sewing::FeaturesPlugin_Sewing()
+{
+//  DBG_FUN();
+}
+
+//=================================================================================================
+void FeaturesPlugin_Sewing::initAttributes()
+{
+//  DBG_FUN();
+
+  data()->addAttribute(OBJECTS_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
+  data()->addAttribute(ALLOW_NON_MANIFOLD_ID(), ModelAPI_AttributeBoolean::typeId());
+  data()->addAttribute(TOLERANCE_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(ALWAYS_CREATE_RESULT_ID(), ModelAPI_AttributeBoolean::typeId());
+}
+
+//=================================================================================================
+void FeaturesPlugin_Sewing::execute()
+{
+//  DBG_FUN();
+
+  // Collect all base shapes
+  ListOfShape aShapes;
+  getOriginalShapes(OBJECTS_LIST_ID(), aShapes);
+//  SHOW(aShapes);
+
+  // Get all other feature arguments
+  bool isAllowNonManifold = boolean(FeaturesPlugin_Sewing::ALLOW_NON_MANIFOLD_ID())->value();
+  bool isAlwaysCreateResult = boolean(FeaturesPlugin_Sewing::ALWAYS_CREATE_RESULT_ID())->value();
+  double aTolerance = real(FeaturesPlugin_Sewing::TOLERANCE_ID())->value();
+  // SHOW(isAllowNonManifold);
+  // SHOW(isAlwaysCreateResult);
+  // SHOW(aTolerance);
+
+  std::shared_ptr<GeomAlgoAPI_Sewing> aSewingAlgo(new GeomAlgoAPI_Sewing(aShapes, isAllowNonManifold, aTolerance));
+
+  std::string anError;
+  if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aSewingAlgo, getKind(), anError))
+  {
+    // SHOW(anError);
+    setError(anError);
+    return;
+  }
+    
+  // Store result.
+  GeomShapePtr aResult = aSewingAlgo->shape();
+  // SHOW(aResult);
+
+  int anIndex = 0;
+  ResultBodyPtr aResultBody = document()->createBody(data(), anIndex);
+  // SHOW(aResultBody);
+  aResultBody->storeModified(aShapes, aResult, aSewingAlgo);
+  // SHOW(aResultBody);
+
+  if (!isSewn(aShapes, aResult) && !isAlwaysCreateResult)
+  {
+    static const std::string anError = "Error: No faces were sewn.";
+    setError(anError);
+    return;
+  }
+
+  setResult(aResultBody, anIndex);
+}
+
+//=================================================================================================
+void FeaturesPlugin_Sewing::getOriginalShapes(const std::string& theAttributeName,
+                                              ListOfShape&       theShapes)
+{
+  // DBG_FUN();
+  // ARG(theAttributeName);
+
+  // Collect all selections into a single list of shapes
+  AttributeSelectionListPtr aSelectionList = selectionList(theAttributeName);
+  for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex)
+  {
+    AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
+    GeomShapePtr aShape = aSelection->value();
+    GeomShapePtr aContext = aSelection->context()->shape();
+    if (!aShape.get())
+    {
+      aShape = aContext;
+    }
+    theShapes.push_back(aShape);
+  }
+}
+
+//=================================================================================================
+bool FeaturesPlugin_Sewing::isSewn(const ListOfShape& theInputs,
+                                   const GeomShapePtr theResult)
+{
+  // DBG_FUN();
+  // ARG(theInputs);
+  // ARG(theResult);
+
+  // Consider the list of input shapes the same as the result, if
+  //  * both arguments have the same number of shells
+  //  * the total number of faces in these shells did NOT change.
+  int nbInputShells = 0, nbInputFaces = 0;
+  for (ListOfShape::const_iterator anIt = theInputs.cbegin();
+       anIt != theInputs.cend();
+       ++anIt)
+  {
+    GeomShapePtr aShape = *anIt;
+    if (aShape.get() && aShape->isShell())
+    {
+      nbInputShells++;
+      nbInputFaces += aShape->subShapes(GeomAPI_Shape::FACE, true).size();
+    }
+  }
+  // SHOW(nbInputShells);
+  // SHOW(nbInputFaces);
+
+  int nbResultShells = 0, nbResultFaces = 0;
+  if (theResult->isCompound())
+  {
+    // MSGEL("...result is COMPOUND");
+    ListOfShape shells = theResult->subShapes(GeomAPI_Shape::SHELL, true);
+    nbResultShells = shells.size();
+    for (ListOfShape::const_iterator anIt = shells.cbegin();
+        anIt != shells.cend();
+        ++anIt)
+    {
+      GeomShapePtr aShape = *anIt;
+      if (aShape.get() && aShape->isShell())
+      {
+        nbInputFaces += aShape->subShapes(GeomAPI_Shape::FACE, true).size();
+      }
+    }
+  }
+  else if (theResult->isShell())
+  {
+    // MSGEL("...result is single SHELL");
+    nbResultShells = 1;
+    nbResultFaces = theResult->subShapes(GeomAPI_Shape::FACE, true).size();
+  }
+  // SHOW(nbResultShells);
+  // SHOW(nbResultFaces);
+
+  return (nbResultShells >= nbInputShells && nbResultFaces > nbInputFaces);
+}
diff --git a/src/FeaturesPlugin/FeaturesPlugin_Sewing.h b/src/FeaturesPlugin/FeaturesPlugin_Sewing.h
new file mode 100644 (file)
index 0000000..815ad1a
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright (C) 2014-2022  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_SEWING_H_
+#define FEATURESPLUGIN_SEWING_H_
+
+#include <FeaturesPlugin.h>
+
+#include <ModelAPI_Feature.h>
+//#include <GeomAlgoAPI_MakeShape.h>
+#include <GeomAPI_Shape.h>
+
+
+/** \class FeaturesPlugin_Sewing
+ *  \ingroup Plugins
+ *  \brief Feature to perform sewing operation on objects.
+ */
+class FeaturesPlugin_Sewing : public ModelAPI_Feature
+{
+ public:
+  /// Sewing kind.
+  inline static const std::string& ID()
+  {
+    static const std::string MY_SEWING_ID("Sewing");
+    return MY_SEWING_ID;
+  }
+
+  /// \return the kind of a feature.
+  FEATURESPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = FeaturesPlugin_Sewing::ID();
+    return MY_KIND;
+  }
+
+  /// Attribute name of referenced objects.
+  inline static const std::string& OBJECTS_LIST_ID()
+  {
+    static const std::string MY_OBJECTS_LIST_ID("main_objects");
+    return MY_OBJECTS_LIST_ID;
+  }
+
+  /// Attribute name for non-manifold state.
+  inline static const std::string& ALLOW_NON_MANIFOLD_ID()
+  {
+    static const std::string MY_ALLOW_NON_MANIFOLD_ID("allow_non_manifold");
+    return MY_ALLOW_NON_MANIFOLD_ID;
+  }
+
+  /// Attribute name for tolerance.
+  inline static const std::string& TOLERANCE_ID()
+  {
+    static const std::string MY_TOLERANCE_ID("tolerance");
+    return MY_TOLERANCE_ID;
+  }
+
+  /// Attribute name for result creation state.
+  inline static const std::string& ALWAYS_CREATE_RESULT_ID()
+  {
+    static const std::string MY_ALWAYS_CREATE_RESULT_ID("always_create_result");
+    return MY_ALWAYS_CREATE_RESULT_ID;
+  }
+
+  /// Request for initialization of data model of the feature: adding all attributes.
+  FEATURESPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Performs the algorithm and stores results in the data structure.
+  FEATURESPLUGIN_EXPORT virtual void execute();
+
+public:
+  /// Use plugin manager for features creation.
+  FeaturesPlugin_Sewing();
+
+private:
+  /// Retrieve all shapes from the selection list
+  void getOriginalShapes(const std::string& theAttributeName,
+                         ListOfShape&       theShapes);
+
+  /// Check, whether the result is sewn or not
+  bool isSewn(const ListOfShape& theInputs,
+              const GeomShapePtr theResult);
+};
+
+#endif // FEATURESPLUGIN_SEWING_H_
index 8878e2d921140a3423b4f44970733103c83fc250..c92dd6f896af12f5b94d42c93ece8ff02c01f1ff 100644 (file)
@@ -2097,3 +2097,69 @@ bool FeaturesPlugin_ValidatorDefeaturingSelection::isValid(
 
   return true;
 }
+
+
+//---------------------------------------------------------
+// #define USE_DEBUG
+// #define DEBUG
+// static const char *dbg_class = "FeaturesPlugin_ValidatorSewingSelection";
+// #include "MBDebug.h"
+// #include "MBModel.h"
+// #include "MBGeom.h"
+//---------------------------------------------------------
+
+//==================================================================================================
+bool FeaturesPlugin_ValidatorSewingSelection::isValid(const AttributePtr& theAttribute,
+                                                      const std::list<std::string>& theArguments,
+                                                      Events_InfoMessage& theError) const
+{
+  // DBG_FUN();
+  // ARG(theAttribute);
+
+  AttributeSelectionListPtr anAttrSelectionList =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
+  if (!anAttrSelectionList.get()) {
+    theError = "Error: This validator can only work with selection list attributes.";
+    return false;
+  }
+
+  // Check selected entities are of valid types
+  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;
+    }
+    if (aContext->groupName() != ModelAPI_ResultBody::group()) {
+      theError = "Error: Not a result body.";
+      return false;
+    }
+
+    GeomShapePtr aContextShape = aContext->shape();
+    if (!aContextShape.get()) {
+      theError = "Error: Empty shape.";
+      return false;
+    }
+
+    GeomAPI_Shape::ShapeType aShapeType = aContextShape->shapeType();
+    std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
+    anAllowedTypes.insert(GeomAPI_Shape::FACE);
+    anAllowedTypes.insert(GeomAPI_Shape::SHELL);
+    anAllowedTypes.insert(GeomAPI_Shape::SOLID);
+    anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
+    anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
+    if (anAllowedTypes.find(aShapeType) == anAllowedTypes.end()) {
+      theError = "Error: Selected shape has the wrong type.";
+      return false;
+    }
+
+  }
+
+  // MSGEL("...selection is VALID.");
+  return true;
+}
index adfb0cd3f6d9d58a75a8ccafdd42dbbf32621293..4814dc2df2ff51df6f5282d4e1c85b8c23919f0c 100644 (file)
@@ -466,4 +466,20 @@ public:
                        Events_InfoMessage& theError) const;
 };
 
+/// \class FeaturesPlugin_ValidatorSewingSelection
+/// \ingroup Validators
+/// \brief Validates selection for sewing operation.
+class FeaturesPlugin_ValidatorSewingSelection : public ModelAPI_AttributeValidator
+{
+public:
+  /// \return True if the attribute is valid. It checks whether the selection
+  /// is acceptable for sewing 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
index e2e2f20bb0d8b003a562b343418508cb81212184..23c8c6be607b03b138e9ecd30311aa29c7abf52b 100644 (file)
       <source>Remove Sub-Shapes</source>
       <translation>Supprimer les sous-formes</translation>
     </message>
+    <message>
+      <source>Sewing</source>
+      <translation>Couture</translation>
+    </message>
     <message>
       <source>Revolution</source>
       <translation>Révolution</translation>
     </message>
   </context>
 
+  <!-- Sewing -->
+  <context>
+    <name>Sewing</name>
+    <message>
+      <source>Perform sewing operation on shapes</source>
+      <translation>Effectuer une opération de couture sur des formes</translation>
+    </message>
+    <message>
+      <source>Sewing</source>
+      <translation>Coudre les faces</translation>
+    </message>
+    <message>
+      <source>Error: No faces were sewn.</source>
+      <translation>Erreur: Aucun face n'a été cousu.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sewing:main_objects</name>
+    <message>
+      <source>Objects</source>
+      <translation>Objets</translation>
+    </message>
+    <message>
+      <source>Select shapes to sew.</source>
+      <translation>Sélectionnez les formes à coudre.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sewing:tolerance</name>
+    <message>
+      <source>Tolerance</source>
+      <translation>Tolérance</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sewing:allow_non_manifold</name>
+    <message>
+      <source>Allow Non-Manifold</source>
+      <translation>Autoriser non multiple</translation>
+    </message>
+    <message>
+      <source>Allow the creation of non-manifold results</source>
+      <translation>Autoriser la création de résultats non multiples</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sewing:always_create_result</name>
+    <message>
+      <source>Always create a result</source>
+      <translation>Créez toujours un résultat</translation>
+    </message>
+    <message>
+      <source>Always create a result, even if nothing is sewed</source>
+      <translation>Créez toujours un résultat, même si rien n'est cousu</translation>
+    </message>
+  </context>
+
   <!-- Smash -->
   <context>
     <name>Smash</name>
       <translation>Le résultat est vide</translation>
     </message>
   </context>
+  <context>
+    <name></name>
+    <message>
+    </message>
+  </context>
 
 </TS>
index e2777069916eb3f9224efa0e75d3462a1a4b892b..1b328d613edf7757cb8427954311f9f47e0bfe0e 100644 (file)
     </message>
   </context>
 
+  <!-- Sewing -->
+  <context>
+    <name>Sewing</name>
+    <message>
+      <source>Perform sewing operation on shapes</source>
+      <translation>Выполнение операции шитья на фигурах</translation>
+    </message>
+    <message>
+      <source>Sewing</source>
+      <translation>Шитье лица</translation>
+    </message>
+    <message>
+      <source>Error: No faces were sewn.</source>
+      <translation>Ошибка: лица не были сшиты.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sewing:main_objects</name>
+    <message>
+      <source>Objects</source>
+      <translation>Объекты</translation>
+    </message>
+    <message>
+      <source>Select shapes to sew.</source>
+      <translation>Выберите фигуры для шитья.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sewing:tolerance</name>
+    <message>
+      <source>Tolerance</source>
+      <translation>Толерантность</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sewing:allow_non_manifold</name>
+    <message>
+      <source>Allow Non-Manifold</source>
+      <translation>Разрешить не многообразие</translation>
+    </message>
+    <message>
+      <source>Allow the creation of non-manifold results</source>
+      <translation>Разрешить создание однократных результатов</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sewing:always_create_result</name>
+    <message>
+      <source>Always create a result</source>
+      <translation>Всегда создавайте результат</translation>
+    </message>
+    <message>
+      <source>Always create a result, even if nothing is sewn</source>
+      <translation>Всегда создавайте результат, даже если ничего не шьется</translation>
+    </message>
+  </context>
+
 </TS>
diff --git a/src/FeaturesPlugin/icons/sewing.png b/src/FeaturesPlugin/icons/sewing.png
new file mode 100644 (file)
index 0000000..f9d9ca7
Binary files /dev/null and b/src/FeaturesPlugin/icons/sewing.png differ
index fd27a2ef24673f5d9eb9eaa95e9ff1ddf90df7fb..a77da866c293c05f23f945e02b61db4d6c0204e1 100644 (file)
         <source path="defeaturing_widget.xml"/>
       </feature>
     </group>
+    <group id="Repair" toolbar="yes">
+      <feature id="Sewing" title="Sewing" tooltip="Perform sewing operation on shapes"
+                icon="icons/Features/sewing.png" helpfile="sewingFeature.html"
+                auto_preview="false">
+          <source path="sewing_widget.xml"/>
+      </feature>
+    </group>
   </workbench>
   <workbench id="Part">
     <group id="Movement">
diff --git a/src/FeaturesPlugin/sewing_widget.xml b/src/FeaturesPlugin/sewing_widget.xml
new file mode 100644 (file)
index 0000000..231e43b
--- /dev/null
@@ -0,0 +1,20 @@
+<source>
+  <multi_selector id="main_objects"
+    label="Objects"
+    icon=""
+    tooltip="Select shapes to sew."
+    concealment="true">
+    <validator id="FeaturesPlugin_ValidatorSewingSelection"/>
+  </multi_selector>
+  <groupbox>
+    <doublevalue id="tolerance"
+                  label="Tolerance"
+                  min="1.0e-8"
+                  max="1"
+                  default="1.0e-7"
+                  tooltip="Tolerance"/>
+    <!-- validator id="GeomValidators_Positive"/ -->
+  </groupbox>
+  <boolvalue id="allow_non_manifold" label="Allow Non-Manifold" default="false" tooltip="Allow the creation of non-manifold results"/>
+  <boolvalue id="always_create_result" label="Always create a result" default="true" tooltip="Always create a result, even if nothing is sewn"/>
+</source>
index 3d9630ecf05164ac581e4f03dfffae614b862ef9..18236bd52f37719217d74eb13a39880414269d9d 100644 (file)
@@ -32,7 +32,12 @@ GeomAlgoAPI_Sewing::GeomAlgoAPI_Sewing(const ListOfShape& theShapes)
   build(theShapes);
 }
 
-void GeomAlgoAPI_Sewing::build(const ListOfShape& theShapes)
+GeomAlgoAPI_Sewing::GeomAlgoAPI_Sewing(const ListOfShape& theShapes, const bool theAllowNonManifold, const double theTolerance)
+{
+  build(theShapes, theAllowNonManifold, theTolerance);
+}
+
+void GeomAlgoAPI_Sewing::build(const ListOfShape& theShapes, const bool theAllowNonManifold, const double theTolerance)
 {
   if(theShapes.empty()) {
     return;
@@ -41,6 +46,11 @@ void GeomAlgoAPI_Sewing::build(const ListOfShape& theShapes)
   BRepBuilderAPI_Sewing* aSewingBuilder = new BRepBuilderAPI_Sewing();
   this->setImpl(aSewingBuilder);
 
+  aSewingBuilder->SetTolerance(theTolerance);
+  aSewingBuilder->SetFaceMode(Standard_True);
+  aSewingBuilder->SetFloatingEdgesMode(Standard_False);
+  aSewingBuilder->SetNonManifoldMode(theAllowNonManifold);
+
   for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
     const TopoDS_Shape& aShape = (*anIt)->impl<TopoDS_Shape>();
     aSewingBuilder->Add(aShape);
@@ -49,28 +59,6 @@ void GeomAlgoAPI_Sewing::build(const ListOfShape& theShapes)
   aSewingBuilder->Perform();
 
   TopoDS_Shape aResult = aSewingBuilder->SewedShape();
-  BRep_Builder aBuilder;
-  if(aResult.ShapeType() == TopAbs_COMPOUND) {
-    TopoDS_Compound aResultCompound;
-    aBuilder.MakeCompound(aResultCompound);
-    for(TopoDS_Iterator anIt(aResult); anIt.More(); anIt.Next()) {
-      const TopoDS_Shape aSubShape = anIt.Value();
-      if(aSubShape.ShapeType() == TopAbs_SHELL) {
-        aBuilder.Add(aResultCompound, aSubShape);
-      } else if (aSubShape.ShapeType() == TopAbs_FACE) {
-        TopoDS_Shell aShell;
-        aBuilder.MakeShell(aShell);
-        aBuilder.Add(aShell, aSubShape);
-        aBuilder.Add(aResultCompound, aShell);
-      }
-    }
-    aResult = aResultCompound;
-  } else if(aResult.ShapeType() == TopAbs_FACE) {
-    TopoDS_Shell aShell;
-    aBuilder.MakeShell(aShell);
-    aBuilder.Add(aShell, aResult);
-    aResult = aShell;
-  }
 
   std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
   aShape->setImpl(new TopoDS_Shape(aResult));
index 4d03762a2439727f5351fcc1c1b2e4fc8e65e93e..811b6e44957bcfcbb521ea65376176f1fb6b8ab7 100644 (file)
@@ -35,6 +35,9 @@ public:
   /// Constructor.
   GEOMALGOAPI_EXPORT GeomAlgoAPI_Sewing(const ListOfShape& theShapes);
 
+  /// Constructor with additional arguments
+  GEOMALGOAPI_EXPORT GeomAlgoAPI_Sewing(const ListOfShape& theShapes, const bool theAllowNonManifold, const double theTolerance);
+
   /// \return the list of shapes modified from the shape \a theShape.
   /// \param[in] theShape base shape.
   /// \param[out] theHistory modified shapes.
@@ -43,7 +46,7 @@ public:
 
 private:
   /// Builds resulting shape.
-  void build(const ListOfShape& theShapes);
+  void build(const ListOfShape& theShapes, const bool theAllowNonManifold = false, const double theTolerance = 1.e-6);
 };
 
 #endif