]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
[bos #40618] [CEA] Offset/Thickness Feature jfa/40618_Offset 73/head
authorjfa <jfa@opencascade.com>
Sat, 31 Aug 2024 00:47:48 +0000 (01:47 +0100)
committerjfa <jfa@opencascade.com>
Thu, 14 Nov 2024 18:36:15 +0000 (18:36 +0000)
56 files changed:
src/FeaturesAPI/CMakeLists.txt
src/FeaturesAPI/FeaturesAPI.i
src/FeaturesAPI/FeaturesAPI_Offset.cpp [new file with mode: 0644]
src/FeaturesAPI/FeaturesAPI_Offset.h [new file with mode: 0644]
src/FeaturesAPI/FeaturesAPI_Thickness.cpp [new file with mode: 0644]
src/FeaturesAPI/FeaturesAPI_Thickness.h [new file with mode: 0644]
src/FeaturesAPI/FeaturesAPI_swig.h
src/FeaturesPlugin/CMakeLists.txt
src/FeaturesPlugin/FeaturesPlugin_Offset.cpp [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_Offset.h [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp
src/FeaturesPlugin/FeaturesPlugin_Thickness.cpp [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_Thickness.h [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.h
src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts
src/FeaturesPlugin/Test/TestOffset.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestThickness.py [new file with mode: 0644]
src/FeaturesPlugin/doc/FeaturesPlugin.rst
src/FeaturesPlugin/doc/TUI_offsetFeature.rst [new file with mode: 0644]
src/FeaturesPlugin/doc/TUI_thicknessFeature.rst [new file with mode: 0644]
src/FeaturesPlugin/doc/examples/offset.py [new file with mode: 0644]
src/FeaturesPlugin/doc/examples/thickness.py [new file with mode: 0644]
src/FeaturesPlugin/doc/images/offset3D.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/offset3D_partial.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/offsetPartialPropertyPanel.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/offsetPropertyPanel.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/offset_partial_result.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/offset_result.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/thickness.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/thickness2.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/thicknessPropertyPanel.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/thicknessPropertyPanel2.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/thickness_result.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/thickness_result2.png [new file with mode: 0644]
src/FeaturesPlugin/doc/offsetFeature.rst [new file with mode: 0644]
src/FeaturesPlugin/doc/thicknessFeature.rst [new file with mode: 0644]
src/FeaturesPlugin/icons/offset3D.png [new file with mode: 0644]
src/FeaturesPlugin/icons/offset3D_partial.png [new file with mode: 0644]
src/FeaturesPlugin/icons/thickness.png [new file with mode: 0644]
src/FeaturesPlugin/icons/thickness2.png [new file with mode: 0644]
src/FeaturesPlugin/offset_widget.xml [new file with mode: 0644]
src/FeaturesPlugin/plugin-Features.xml
src/FeaturesPlugin/tests.set
src/FeaturesPlugin/thickness_widget.xml [new file with mode: 0644]
src/GeomAlgoAPI/CMakeLists.txt
src/GeomAlgoAPI/GeomAlgoAPI_MakeShape.cpp
src/GeomAlgoAPI/GeomAlgoAPI_MakeShape.h
src/GeomAlgoAPI/GeomAlgoAPI_Offset.cpp
src/GeomAlgoAPI/GeomAlgoAPI_Offset.h
src/GeomAlgoAPI/GeomAlgoAPI_Thickness.cpp [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_Thickness.h [new file with mode: 0644]
src/PythonAPI/model/features/__init__.py
src/SHAPERGUI/resources/LightApp.xml.in
src/SHAPERGUI/resources/action_assets.json
src/SketchPlugin/Test/TestOffset1.py

index 4652651c9ee1a1b2f1037e26952c1edce0ada5a1..7c4224928c6302b7155d7ea37d7fdceefe234a9d 100644 (file)
@@ -36,9 +36,11 @@ SET(PROJECT_HEADERS
   FeaturesAPI_NormalToFace.h
   FeaturesAPI_MultiRotation.h
   FeaturesAPI_MultiTranslation.h
+  FeaturesAPI_Offset.h
   FeaturesAPI_Partition.h
   FeaturesAPI_Pipe.h
   FeaturesAPI_Loft.h
+  FeaturesAPI_Thickness.h
   FeaturesAPI_Placement.h
   FeaturesAPI_PointCloudOnFace.h
   FeaturesAPI_Recover.h
@@ -79,9 +81,11 @@ SET(PROJECT_SOURCES
   FeaturesAPI_NormalToFace.cpp
   FeaturesAPI_MultiRotation.cpp
   FeaturesAPI_MultiTranslation.cpp
+  FeaturesAPI_Offset.cpp
   FeaturesAPI_Partition.cpp
   FeaturesAPI_Pipe.cpp
   FeaturesAPI_Loft.cpp
+  FeaturesAPI_Thickness.cpp
   FeaturesAPI_Placement.cpp
   FeaturesAPI_PointCloudOnFace.cpp
   FeaturesAPI_Recover.cpp
index d482e844e45323858116f3d9233a69757ddf6a54..9e0c4e8f2f359db3bf9a7713e559e98438132952 100644 (file)
@@ -85,6 +85,7 @@
 %shared_ptr(FeaturesAPI_MultiRotation)
 %shared_ptr(FeaturesAPI_MultiTranslation)
 %shared_ptr(FeaturesAPI_NormalToFace)
+%shared_ptr(FeaturesAPI_Offset)
 %shared_ptr(FeaturesAPI_Partition)
 %shared_ptr(FeaturesAPI_Pipe)
 %shared_ptr(FeaturesAPI_Placement)
 %shared_ptr(FeaturesAPI_Sewing)
 %shared_ptr(FeaturesAPI_SharedFaces)
 %shared_ptr(FeaturesAPI_Symmetry)
+%shared_ptr(FeaturesAPI_Thickness)
 %shared_ptr(FeaturesAPI_Translation)
 %shared_ptr(FeaturesAPI_Union)
 
 %include "FeaturesAPI_NormalToFace.h"
 %include "FeaturesAPI_MultiRotation.h"
 %include "FeaturesAPI_MultiTranslation.h"
+%include "FeaturesAPI_Offset.h"
 %include "FeaturesAPI_Partition.h"
 %include "FeaturesAPI_Pipe.h"
 %include "FeaturesAPI_Placement.h"
 %include "FeaturesAPI_Sewing.h"
 %include "FeaturesAPI_SharedFaces.h"
 %include "FeaturesAPI_Symmetry.h"
+%include "FeaturesAPI_Thickness.h"
 %include "FeaturesAPI_Translation.h"
 %include "FeaturesAPI_Union.h"
diff --git a/src/FeaturesAPI/FeaturesAPI_Offset.cpp b/src/FeaturesAPI/FeaturesAPI_Offset.cpp
new file mode 100644 (file)
index 0000000..2d7446a
--- /dev/null
@@ -0,0 +1,121 @@
+// Copyright (C) 2017-2024  CEA, EDF
+//
+// 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_Offset.h"
+
+#include <ModelHighAPI_Double.h>
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Selection.h>
+#include <ModelHighAPI_Tools.h>
+
+//==================================================================================================
+
+FeaturesAPI_Offset::FeaturesAPI_Offset(const std::shared_ptr<ModelAPI_Feature>& theFeature)
+  : ModelHighAPI_Interface(theFeature)
+{
+  initialize();
+}
+
+FeaturesAPI_Offset::FeaturesAPI_Offset(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                       const ModelHighAPI_Selection& theBaseObject,
+                                       const ModelHighAPI_Double& theOffset,
+                                       const bool isPipeJoint)
+  : FeaturesAPI_Offset(theFeature)
+{
+  if (initialize()) {
+    fillAttribute(FeaturesPlugin_Offset::CREATION_METHOD_EQUAL(), mycreationMethod);
+    fillAttribute(theBaseObject, mybaseObject);
+    fillAttribute(theOffset, myoffsetValue);
+    fillAttribute(isPipeJoint, myisPipeJoint);
+
+    execute();
+  }
+}
+
+FeaturesAPI_Offset::FeaturesAPI_Offset(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                       const ModelHighAPI_Selection& theBaseObject,
+                                       const ModelHighAPI_Double& theOffset,
+                                       const std::list<ModelHighAPI_Selection>& theFaces)
+  : FeaturesAPI_Offset(theFeature)
+{
+  if (initialize()) {
+    fillAttribute(FeaturesPlugin_Offset::CREATION_METHOD_PARTIAL(), mycreationMethod);
+    fillAttribute(theBaseObject, mybaseObject);
+    fillAttribute(theOffset, myoffsetValue);
+    fillAttribute(theFaces, myfaces);
+
+    execute();
+  }
+}
+
+FeaturesAPI_Offset::~FeaturesAPI_Offset()
+{
+}
+
+void FeaturesAPI_Offset::dump(ModelHighAPI_Dumper& theDumper) const
+{
+  FeaturePtr aBase = feature();
+  const std::string& aDocName = theDumper.name(aBase->document());
+
+  AttributeSelectionPtr anAttrShape =
+    aBase->selection(FeaturesPlugin_Offset::BASE_SHAPE_ID());
+
+  AttributeDoublePtr anAttrOffset = aBase->real(FeaturesPlugin_Offset::OFFSET_VALUE_ID());
+
+  std::string aCreationMethod =
+    aBase->string(FeaturesPlugin_Offset::CREATION_METHOD_ID())->value();
+
+  if (aCreationMethod == FeaturesPlugin_Offset::CREATION_METHOD_EQUAL()) {
+    AttributeBooleanPtr anAttrIsPipe = aBase->boolean(FeaturesPlugin_Offset::PIPE_JOINT_ID());
+
+    theDumper << aBase << " = model.addOffset(" << aDocName << ", " << anAttrShape;
+    theDumper << ", " << anAttrOffset << ", " << anAttrIsPipe << ")" << std::endl;
+  }
+  else if (aCreationMethod == FeaturesPlugin_Offset::CREATION_METHOD_PARTIAL()) {
+    AttributeSelectionListPtr anAttrFaces =
+      aBase->selectionList(FeaturesPlugin_Offset::FACES_ID());
+
+    theDumper << aBase << " = model.addOffsetPartial(" << aDocName << ", " << anAttrShape;
+    theDumper << ", " << anAttrOffset << ", " << anAttrFaces << ")" << std::endl;
+  }
+}
+
+//==================================================================================================
+
+OffsetPtr addOffset(const std::shared_ptr<ModelAPI_Document>& thePart,
+                    const ModelHighAPI_Selection& theBaseObject,
+                    const ModelHighAPI_Double& theOffset,
+                    const bool isPipeJoint)
+{
+  FeaturePtr aFeature = thePart->addFeature(FeaturesAPI_Offset::ID());
+
+  OffsetPtr aOffset (new FeaturesAPI_Offset(aFeature, theBaseObject, theOffset, isPipeJoint));
+  return aOffset;
+}
+
+OffsetPtr addOffsetPartial(const std::shared_ptr<ModelAPI_Document>& thePart,
+                           const ModelHighAPI_Selection& theBaseObject,
+                           const ModelHighAPI_Double& theOffset,
+                           const std::list<ModelHighAPI_Selection>& theFaces)
+{
+  FeaturePtr aFeature = thePart->addFeature(FeaturesAPI_Offset::ID());
+
+  OffsetPtr aOffset (new FeaturesAPI_Offset(aFeature, theBaseObject, theOffset, theFaces));
+  return aOffset;
+}
diff --git a/src/FeaturesAPI/FeaturesAPI_Offset.h b/src/FeaturesAPI/FeaturesAPI_Offset.h
new file mode 100644 (file)
index 0000000..6472708
--- /dev/null
@@ -0,0 +1,102 @@
+// Copyright (C) 2017-2024  CEA, EDF
+//
+// 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_Offset_H_
+#define FeaturesAPI_Offset_H_
+
+#include "FeaturesAPI.h"
+
+#include <FeaturesPlugin_Offset.h>
+
+#include <ModelHighAPI_Double.h>
+#include <ModelHighAPI_Interface.h>
+#include <ModelHighAPI_Macro.h>
+
+class ModelHighAPI_Selection;
+
+/// \class FeaturesAPI_Offset
+/// \ingroup CPPHighAPI
+/// \brief Interface for Offset feature.
+class FeaturesAPI_Offset: public ModelHighAPI_Interface
+{
+public:
+  /// Constructor without values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_Offset(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+  /// Constructor with values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_Offset(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                              const ModelHighAPI_Selection& theBaseObject,
+                              const ModelHighAPI_Double& theOffset,
+                              const bool isPipeJoint);
+
+  /// Constructor with values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_Offset(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                              const ModelHighAPI_Selection& theBaseObject,
+                              const ModelHighAPI_Double& theOffset,
+                              const std::list<ModelHighAPI_Selection>& theFaces);
+
+  /// Destructor.
+  FEATURESAPI_EXPORT
+  virtual ~FeaturesAPI_Offset();
+
+  INTERFACE_5(FeaturesPlugin_Offset::ID(),
+
+              creationMethod, FeaturesPlugin_Offset::CREATION_METHOD_ID(),
+              ModelAPI_AttributeString, /** Creation method */,
+
+              baseObject, FeaturesPlugin_Offset::BASE_SHAPE_ID(),
+              ModelAPI_AttributeSelection, /** Base object */,
+
+              offsetValue, FeaturesPlugin_Offset::OFFSET_VALUE_ID(),
+              ModelAPI_AttributeDouble, /** Value of the offset */,
+
+              isPipeJoint, FeaturesPlugin_Offset::PIPE_JOINT_ID(),
+              ModelAPI_AttributeBoolean, /** Is pipe or intersection joint */,
+
+              faces, FeaturesPlugin_Offset::FACES_ID(),
+              ModelAPI_AttributeSelectionList, /** List of faces for partial offset */)
+
+  /// Dump wrapped feature
+  FEATURESAPI_EXPORT
+  virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+};
+
+/// Pointer on the offset object.
+typedef std::shared_ptr<FeaturesAPI_Offset> OffsetPtr;
+
+/// \ingroup CPPHighAPI
+/// \brief Create Offset feature.
+FEATURESAPI_EXPORT
+OffsetPtr addOffset(const std::shared_ptr<ModelAPI_Document>& thePart,
+                    const ModelHighAPI_Selection& theBaseObject,
+                    const ModelHighAPI_Double& theOffset,
+                    const bool isPipeJoint = true);
+
+/// \ingroup CPPHighAPI
+/// \brief Create Offset feature.
+FEATURESAPI_EXPORT
+OffsetPtr addOffsetPartial(const std::shared_ptr<ModelAPI_Document>& thePart,
+                           const ModelHighAPI_Selection& theBaseObject,
+                           const ModelHighAPI_Double& theOffset,
+                           const std::list<ModelHighAPI_Selection>& theFaces);
+
+#endif // FeaturesAPI_Offset_H_
diff --git a/src/FeaturesAPI/FeaturesAPI_Thickness.cpp b/src/FeaturesAPI/FeaturesAPI_Thickness.cpp
new file mode 100644 (file)
index 0000000..0a0a6c5
--- /dev/null
@@ -0,0 +1,129 @@
+// Copyright (C) 2017-2024  CEA, EDF
+//
+// 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_Thickness.h"
+
+#include <ModelHighAPI_Double.h>
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Selection.h>
+#include <ModelHighAPI_Tools.h>
+
+//==================================================================================================
+
+FeaturesAPI_Thickness::FeaturesAPI_Thickness(const std::shared_ptr<ModelAPI_Feature>& theFeature)
+  : ModelHighAPI_Interface(theFeature)
+{
+  initialize();
+}
+
+FeaturesAPI_Thickness::FeaturesAPI_Thickness(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                             const ModelHighAPI_Selection& theBaseObject,
+                                             const ModelHighAPI_Double& theThickness,
+                                             const bool isInside)
+  : FeaturesAPI_Thickness(theFeature)
+{
+  if (initialize()) {
+    fillAttribute(FeaturesPlugin_Thickness::CREATION_METHOD_THICK(), mycreationMethod);
+    fillAttribute(theBaseObject, mybaseObject);
+    fillAttribute(theThickness, mythicknessValue);
+    fillAttribute(isInside, myisInside);
+
+    execute();
+  }
+}
+
+FeaturesAPI_Thickness::FeaturesAPI_Thickness(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                             const ModelHighAPI_Selection& theBaseObject,
+                                             const ModelHighAPI_Double& theThickness,
+                                             const std::list<ModelHighAPI_Selection>& theFaces,
+                                             const bool isInside)
+  : FeaturesAPI_Thickness(theFeature)
+{
+  if (initialize()) {
+    fillAttribute(FeaturesPlugin_Thickness::CREATION_METHOD_HOLLOWED(), mycreationMethod);
+    fillAttribute(theBaseObject, mybaseObject);
+    fillAttribute(theThickness, mythicknessValue);
+    fillAttribute(theFaces, myfaces);
+    fillAttribute(isInside, myisInside);
+
+    execute();
+  }
+}
+
+FeaturesAPI_Thickness::~FeaturesAPI_Thickness()
+{
+}
+
+void FeaturesAPI_Thickness::dump(ModelHighAPI_Dumper& theDumper) const
+{
+  FeaturePtr aBase = feature();
+  const std::string& aDocName = theDumper.name(aBase->document());
+
+  AttributeSelectionPtr anAttrShape =
+    aBase->selection(FeaturesPlugin_Thickness::BASE_SHAPE_ID());
+
+  AttributeDoublePtr anAttrThickness =
+    aBase->real(FeaturesPlugin_Thickness::THICKNESS_VALUE_ID());
+
+  AttributeBooleanPtr anAttrIsInside =
+    aBase->boolean(FeaturesPlugin_Thickness::INSIDE_ID());
+
+  std::string aCreationMethod =
+    aBase->string(FeaturesPlugin_Thickness::CREATION_METHOD_ID())->value();
+
+  if (aCreationMethod == FeaturesPlugin_Thickness::CREATION_METHOD_THICK()) {
+    theDumper << aBase << " = model.addThickness(" << aDocName;
+    theDumper << ", " << anAttrShape << ", " << anAttrThickness;
+    theDumper << ", " << anAttrIsInside << ")" << std::endl;
+  }
+  else if (aCreationMethod == FeaturesPlugin_Thickness::CREATION_METHOD_HOLLOWED()) {
+    AttributeSelectionListPtr anAttrFaces =
+      aBase->selectionList(FeaturesPlugin_Thickness::FACES_ID());
+
+    theDumper << aBase << " = model.addHollowedSolid(" << aDocName;
+    theDumper << ", " << anAttrShape << ", " << anAttrThickness;
+    theDumper << ", " << anAttrFaces;
+    theDumper << ", " << anAttrIsInside << ")" << std::endl;
+  }
+}
+
+//==================================================================================================
+
+ThicknessPtr addThickness(const std::shared_ptr<ModelAPI_Document>& thePart,
+                          const ModelHighAPI_Selection& theBaseObject,
+                          const ModelHighAPI_Double& theThickness,
+                          const bool isInside)
+{
+  FeaturePtr aFeature = thePart->addFeature(FeaturesAPI_Thickness::ID());
+
+  ThicknessPtr aThickness (new FeaturesAPI_Thickness(aFeature, theBaseObject, theThickness, isInside));
+  return aThickness;
+}
+
+ThicknessPtr addHollowedSolid(const std::shared_ptr<ModelAPI_Document>& thePart,
+                              const ModelHighAPI_Selection& theBaseObject,
+                              const ModelHighAPI_Double& theThickness,
+                              const std::list<ModelHighAPI_Selection>& theFaces,
+                              const bool isInside)
+{
+  FeaturePtr aFeature = thePart->addFeature(FeaturesAPI_Thickness::ID());
+
+  ThicknessPtr aThickness (new FeaturesAPI_Thickness(aFeature, theBaseObject, theThickness, theFaces, isInside));
+  return aThickness;
+}
diff --git a/src/FeaturesAPI/FeaturesAPI_Thickness.h b/src/FeaturesAPI/FeaturesAPI_Thickness.h
new file mode 100644 (file)
index 0000000..3864131
--- /dev/null
@@ -0,0 +1,104 @@
+// Copyright (C) 2017-2024  CEA, EDF
+//
+// 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_Thickness_H_
+#define FeaturesAPI_Thickness_H_
+
+#include "FeaturesAPI.h"
+
+#include <FeaturesPlugin_Thickness.h>
+
+#include <ModelHighAPI_Double.h>
+#include <ModelHighAPI_Interface.h>
+#include <ModelHighAPI_Macro.h>
+
+class ModelHighAPI_Selection;
+
+/// \class FeaturesAPI_Thickness
+/// \ingroup CPPHighAPI
+/// \brief Interface for Thickness feature.
+class FeaturesAPI_Thickness: public ModelHighAPI_Interface
+{
+public:
+  /// Constructor without values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_Thickness(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+  /// Constructor with values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_Thickness(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                 const ModelHighAPI_Selection& theBaseObject,
+                                 const ModelHighAPI_Double& theThickness,
+                                 const bool isInside);
+
+  /// Constructor with values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_Thickness(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                 const ModelHighAPI_Selection& theBaseObject,
+                                 const ModelHighAPI_Double& theThickness,
+                                 const std::list<ModelHighAPI_Selection>& theFaces,
+                                 const bool isInside);
+
+  /// Destructor.
+  FEATURESAPI_EXPORT
+  virtual ~FeaturesAPI_Thickness();
+
+  INTERFACE_5(FeaturesPlugin_Thickness::ID(),
+
+              creationMethod, FeaturesPlugin_Thickness::CREATION_METHOD_ID(),
+              ModelAPI_AttributeString, /** Creation method */,
+
+              baseObject, FeaturesPlugin_Thickness::BASE_SHAPE_ID(),
+              ModelAPI_AttributeSelection, /** Base object */,
+
+              thicknessValue, FeaturesPlugin_Thickness::THICKNESS_VALUE_ID(),
+              ModelAPI_AttributeDouble, /** Value of the thickness */,
+
+              faces, FeaturesPlugin_Thickness::FACES_ID(),
+              ModelAPI_AttributeSelectionList, /** List of faces to remove in hollowed solid mode */,
+
+              isInside, FeaturesPlugin_Thickness::INSIDE_ID(),
+              ModelAPI_AttributeBoolean, /** Do thicken towards inside */)
+
+  /// Dump wrapped feature
+  FEATURESAPI_EXPORT
+  virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+};
+
+/// Pointer on the thickness object.
+typedef std::shared_ptr<FeaturesAPI_Thickness> ThicknessPtr;
+
+/// \ingroup CPPHighAPI
+/// \brief Create Thickness feature.
+FEATURESAPI_EXPORT
+ThicknessPtr addThickness(const std::shared_ptr<ModelAPI_Document>& thePart,
+                          const ModelHighAPI_Selection& theBaseObject,
+                          const ModelHighAPI_Double& theThickness,
+                          const bool isInside = true);
+
+/// \ingroup CPPHighAPI
+/// \brief Create Thickness feature.
+FEATURESAPI_EXPORT
+ThicknessPtr addHollowedSolid(const std::shared_ptr<ModelAPI_Document>& thePart,
+                              const ModelHighAPI_Selection& theBaseObject,
+                              const ModelHighAPI_Double& theThickness,
+                              const std::list<ModelHighAPI_Selection>& theFaces,
+                              const bool isInside = true);
+
+#endif // FeaturesAPI_Thickness_H_
index 4dbce1c7505e2b1dbbcb7b706b60e8e220c1331f..1620196f8cdcef9af187e7f7ff626c9ec8705880 100644 (file)
   #include "FeaturesAPI_NormalToFace.h"
   #include "FeaturesAPI_MultiRotation.h"
   #include "FeaturesAPI_MultiTranslation.h"
+  #include "FeaturesAPI_Offset.h"
   #include "FeaturesAPI_Partition.h"
   #include "FeaturesAPI_Pipe.h"
   #include "FeaturesAPI_Loft.h"
+  #include "FeaturesAPI_Thickness.h"
   #include "FeaturesAPI_Placement.h"
   #include "FeaturesAPI_PointCloudOnFace.h"
   #include "FeaturesAPI_Recover.h"
index 4946d5434d9c7f5e5f0a3167a62982a0b93d3f08..01cfeea11c42bf55b50811f44b88a9fdc9d6ac9a 100644 (file)
@@ -40,6 +40,7 @@ SET(PROJECT_HEADERS
     FeaturesPlugin_Partition.h
     FeaturesPlugin_Pipe.h
     FeaturesPlugin_Loft.h
+    FeaturesPlugin_Thickness.h
     FeaturesPlugin_Placement.h
     FeaturesPlugin_PointCloudOnFace.h
     FeaturesPlugin_CompositeBoolean.h
@@ -53,6 +54,7 @@ SET(PROJECT_HEADERS
     FeaturesPlugin_Union.h
     FeaturesPlugin_ValidatorTransform.h
     FeaturesPlugin_Validators.h
+    FeaturesPlugin_Offset.h
     FeaturesPlugin_RemoveSubShapes.h
     FeaturesPlugin_Tools.h
     FeaturesPlugin_Symmetry.h
@@ -102,6 +104,7 @@ SET(PROJECT_SOURCES
     FeaturesPlugin_Partition.cpp
     FeaturesPlugin_Pipe.cpp
     FeaturesPlugin_Loft.cpp
+    FeaturesPlugin_Thickness.cpp
     FeaturesPlugin_Placement.cpp
     FeaturesPlugin_PointCloudOnFace.cpp
     FeaturesPlugin_CompositeBoolean.cpp
@@ -115,6 +118,7 @@ SET(PROJECT_SOURCES
     FeaturesPlugin_Union.cpp
     FeaturesPlugin_ValidatorTransform.cpp
     FeaturesPlugin_Validators.cpp
+    FeaturesPlugin_Offset.cpp
     FeaturesPlugin_RemoveSubShapes.cpp
     FeaturesPlugin_Tools.cpp
     FeaturesPlugin_Symmetry.cpp
@@ -167,6 +171,8 @@ SET(XML_RESOURCES
   intersection_widget.xml
   pipe_widget.xml
   loft_widget.xml
+  thickness_widget.xml
+  offset_widget.xml
   remove_subshapes_widget.xml
   union_widget.xml
   symmetry_widget.xml
diff --git a/src/FeaturesPlugin/FeaturesPlugin_Offset.cpp b/src/FeaturesPlugin/FeaturesPlugin_Offset.cpp
new file mode 100644 (file)
index 0000000..f46b82a
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright (C) 2014-2024  CEA, EDF
+//
+// 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_Offset.h"
+
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeBoolean.h>
+#include <ModelAPI_ResultBody.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Tools.h>
+#include <ModelAPI_Validator.h>
+
+#include <GeomAlgoAPI_Offset.h>
+#include <GeomAlgoAPI_Tools.h>
+
+//==================================================================================================
+FeaturesPlugin_Offset::FeaturesPlugin_Offset()
+{
+}
+
+//==================================================================================================
+void FeaturesPlugin_Offset::initAttributes()
+{
+  data()->addAttribute(CREATION_METHOD_ID(), ModelAPI_AttributeString::typeId());
+  data()->addAttribute(BASE_SHAPE_ID(), ModelAPI_AttributeSelection::typeId());
+  data()->addAttribute(OFFSET_VALUE_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(PIPE_JOINT_ID(), ModelAPI_AttributeBoolean::typeId());
+  data()->addAttribute(FACES_ID(), ModelAPI_AttributeSelectionList::typeId());
+
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PIPE_JOINT_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FACES_ID());
+}
+
+//==================================================================================================
+void FeaturesPlugin_Offset::execute()
+{
+  // Get base shape and sub-shapes list.
+  AttributeSelectionPtr aShapeAttrSelection = selection(BASE_SHAPE_ID());
+  if (!aShapeAttrSelection.get()) {
+    return;
+  }
+
+  // Get base shape.
+  GeomShapePtr aBaseShape = aShapeAttrSelection->value();
+  if (!aBaseShape.get()) {
+    return;
+  }
+
+  // Get offset value.
+  double anOffset = real(OFFSET_VALUE_ID())->value();
+
+  // Getting creation method.
+  std::string aCreationMethod = string(CREATION_METHOD_ID())->value();
+
+  // Perform total or partial offset
+  std::shared_ptr<GeomAlgoAPI_Offset> anOffsetAlgo;
+
+  if (aCreationMethod == CREATION_METHOD_EQUAL()) {
+    // total offset can have pipe or intersection joints
+    bool isPipeJoint = boolean(PIPE_JOINT_ID())->value();
+
+    anOffsetAlgo = std::shared_ptr<GeomAlgoAPI_Offset>
+      (new GeomAlgoAPI_Offset (aBaseShape, anOffset, isPipeJoint));
+  }
+  else {
+    // partial offset has faces argument
+    AttributeSelectionListPtr aFacesAttrList = selectionList(FACES_ID());
+    if (!aShapeAttrSelection.get() || !aFacesAttrList.get()) {
+      return;
+    }
+
+    ListOfShape aFaces;
+    for (int anIndex = 0; anIndex < aFacesAttrList->size(); ++anIndex) {
+      AttributeSelectionPtr aFaceAttrInList = aFacesAttrList->value(anIndex);
+      GeomShapePtr aFace = aFaceAttrInList->value();
+      if (!aFace.get()) {
+        return;
+      }
+      aFaces.push_back(aFace);
+    }
+
+    anOffsetAlgo = std::shared_ptr<GeomAlgoAPI_Offset>
+      (new GeomAlgoAPI_Offset (aBaseShape, aFaces, anOffset));
+  }
+
+  std::string anError;
+  if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(anOffsetAlgo, getKind(), anError)) {
+    setError(anError);
+    return;
+  }
+
+  GeomShapePtr aResult = anOffsetAlgo->shape();
+
+  // Store result.
+  int anIndex = 0;
+  ResultBodyPtr aResultBody = document()->createBody(data(), anIndex);
+  aResultBody->storeModified(aBaseShape, aResult);
+  aResultBody->loadModifiedShapes(anOffsetAlgo, aBaseShape, GeomAPI_Shape::FACE);
+  aResultBody->loadGeneratedShapes(anOffsetAlgo, aBaseShape, GeomAPI_Shape::FACE);
+  setResult(aResultBody, anIndex);
+}
diff --git a/src/FeaturesPlugin/FeaturesPlugin_Offset.h b/src/FeaturesPlugin/FeaturesPlugin_Offset.h
new file mode 100644 (file)
index 0000000..e320efe
--- /dev/null
@@ -0,0 +1,107 @@
+// Copyright (C) 2014-2024  CEA, EDF
+//
+// 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_Offset_H_
+#define FeaturesPlugin_Offset_H_
+
+#include "FeaturesPlugin.h"
+
+#include <ModelAPI_Feature.h>
+
+/// \class FeaturesPlugin_Offset
+/// \ingroup Plugins
+/// \brief Feature for offset.
+class FeaturesPlugin_Offset: public ModelAPI_Feature
+{
+public:
+  /// Use plugin manager for features creation
+  FeaturesPlugin_Offset();
+
+  /// Feature kind.
+  inline static const std::string& ID()
+  {
+    static const std::string MY_ID("Offset3d");
+    return MY_ID;
+  }
+
+  /// Attribute name for creation method.
+  inline static const std::string& CREATION_METHOD_ID()
+  {
+    static const std::string MY_CREATION_METHOD_ID("creation_method");
+    return MY_CREATION_METHOD_ID;
+  }
+
+  /// Attribute name for creation method.
+  inline static const std::string& CREATION_METHOD_EQUAL()
+  {
+    static const std::string MY_CREATION_METHOD_EQUAL("offset_equal");
+    return MY_CREATION_METHOD_EQUAL;
+  }
+
+  /// Attribute name for creation method.
+  inline static const std::string& CREATION_METHOD_PARTIAL()
+  {
+    static const std::string MY_CREATION_METHOD_PARTIAL("offset_partial");
+    return MY_CREATION_METHOD_PARTIAL;
+  }
+
+  /// Attribute name of base shape.
+  inline static const std::string& BASE_SHAPE_ID()
+  {
+    static const std::string MY_BASE_SHAPE_ID("base_shape");
+    return MY_BASE_SHAPE_ID;
+  }
+
+  /// Attribute name of offset value.
+  inline static const std::string& OFFSET_VALUE_ID()
+  {
+    static const std::string MY_OFFSET_VALUE_ID("offset_value");
+    return MY_OFFSET_VALUE_ID;
+  }
+
+  /// Attribute name of pipe/intersection joint bool flag.
+  inline static const std::string& PIPE_JOINT_ID()
+  {
+    static const std::string MY_PIPE_JOINT_ID("pipe_joint");
+    return MY_PIPE_JOINT_ID;
+  }
+
+  /// Attribute name of sub-faces to offset (for partial offset).
+  inline static const std::string& FACES_ID()
+  {
+    static const std::string MY_FACES_ID("faces_to_offset");
+    return MY_FACES_ID;
+  }
+
+
+  /// \return the kind of a feature.
+  FEATURESPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = FeaturesPlugin_Offset::ID();
+    return MY_KIND;
+  }
+
+  /// Request for initialization of data model of the feature: adding all attributes.
+  FEATURESPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Performs the algorithm and stores results it in the data structure.
+  FEATURESPLUGIN_EXPORT virtual void execute();
+};
+
+#endif
index 53669c8f28ed36bbfbde04041a01e1aebd801460..4d0c56a74c72576a593705729d8bf13422b6895d 100644 (file)
@@ -47,6 +47,8 @@
 #include <FeaturesPlugin_Partition.h>
 #include <FeaturesPlugin_Pipe.h>
 #include <FeaturesPlugin_Loft.h>
+#include <FeaturesPlugin_Thickness.h>
+#include <FeaturesPlugin_Offset.h>
 #include <FeaturesPlugin_Placement.h>
 #include <FeaturesPlugin_PointCloudOnFace.h>
 #include <FeaturesPlugin_Recover.h>
@@ -101,6 +103,10 @@ FeaturesPlugin_Plugin::FeaturesPlugin_Plugin()
                               new FeaturesPlugin_ValidatorExtrusionBoundaryFace);
   aFactory->registerValidator("FeaturesPlugin_ValidatorBooleanSelection",
                               new FeaturesPlugin_ValidatorBooleanSelection);
+  aFactory->registerValidator("FeaturesPlugin_ValidatorOffsetFacesSelection",
+                              new FeaturesPlugin_ValidatorOffsetFacesSelection);
+  aFactory->registerValidator("FeaturesPlugin_ValidatorThicknessSelection",
+                              new FeaturesPlugin_ValidatorThicknessSelection);
   aFactory->registerValidator("FeaturesPlugin_ValidatorPartitionSelection",
                               new FeaturesPlugin_ValidatorPartitionSelection);
   aFactory->registerValidator("FeaturesPlugin_ValidatorRemoveSubShapesSelection",
@@ -176,6 +182,8 @@ FeaturePtr FeaturesPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new FeaturesPlugin_Pipe);
   } else if (theFeatureID == FeaturesPlugin_Loft::ID()) {
     return FeaturePtr(new FeaturesPlugin_Loft);
+  } else if (theFeatureID == FeaturesPlugin_Thickness::ID()) {
+    return FeaturePtr(new FeaturesPlugin_Thickness);
   } else if (theFeatureID == FeaturesPlugin_Placement::ID()) {
     return FeaturePtr(new FeaturesPlugin_Placement);
   } else if (theFeatureID == FeaturesPlugin_Recover::ID()) {
@@ -198,6 +206,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_Offset::ID()) {
+    return FeaturePtr(new FeaturesPlugin_Offset);
   } else if (theFeatureID == FeaturesPlugin_Sewing::ID()) {
     return FeaturePtr(new FeaturesPlugin_Sewing);
   } else if (theFeatureID == FeaturesPlugin_MultiTranslation::ID()) {
diff --git a/src/FeaturesPlugin/FeaturesPlugin_Thickness.cpp b/src/FeaturesPlugin/FeaturesPlugin_Thickness.cpp
new file mode 100644 (file)
index 0000000..db39702
--- /dev/null
@@ -0,0 +1,140 @@
+// Copyright (C) 2014-2024  CEA, EDF
+//
+// 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_Thickness.h"
+
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeBoolean.h>
+#include <ModelAPI_ResultBody.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Tools.h>
+#include <ModelAPI_Validator.h>
+
+#include <GeomAlgoAPI_Thickness.h>
+#include <GeomAlgoAPI_Tools.h>
+
+//==================================================================================================
+FeaturesPlugin_Thickness::FeaturesPlugin_Thickness()
+{
+}
+
+//==================================================================================================
+void FeaturesPlugin_Thickness::initAttributes()
+{
+  data()->addAttribute(CREATION_METHOD_ID(), ModelAPI_AttributeString::typeId());
+  data()->addAttribute(BASE_SHAPE_ID(), ModelAPI_AttributeSelection::typeId());
+  data()->addAttribute(FACES_ID(), ModelAPI_AttributeSelectionList::typeId());
+  data()->addAttribute(THICKNESS_VALUE_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(INSIDE_ID(), ModelAPI_AttributeBoolean::typeId());
+
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FACES_ID());
+}
+
+//==================================================================================================
+void FeaturesPlugin_Thickness::execute()
+{
+  // Getting creation method.
+  std::string aCreationMethod = string(CREATION_METHOD_ID())->value();
+
+  // Get base shape
+  AttributeSelectionPtr aShapeAttrSelection = selection(BASE_SHAPE_ID());
+  if (!aShapeAttrSelection.get()) {
+    return;
+  }
+  GeomShapePtr aBaseShape = aShapeAttrSelection->value();
+  if (!aBaseShape.get()) {
+    return;
+  }
+
+  // Get thickness value.
+  double aThickness = real(THICKNESS_VALUE_ID())->value();
+
+  // Get thickening direction
+  bool isInside = boolean(INSIDE_ID())->value();
+
+  // Perform thickness
+  std::shared_ptr<GeomAlgoAPI_Thickness> aThicknessAlgo;
+
+  if (aCreationMethod == CREATION_METHOD_THICK()) {
+    aThicknessAlgo = std::shared_ptr<GeomAlgoAPI_Thickness>
+      (new GeomAlgoAPI_Thickness (aBaseShape, aThickness, isInside));
+  }
+  else {
+    // hollowed solid algorithm has faces argument
+    AttributeSelectionListPtr aFacesAttrList = selectionList(FACES_ID());
+    if (!aShapeAttrSelection.get() || !aFacesAttrList.get()) {
+      return;
+    }
+
+    ListOfShape aFaces;
+    for (int anIndex = 0; anIndex < aFacesAttrList->size(); ++anIndex) {
+      AttributeSelectionPtr aFaceAttrInList = aFacesAttrList->value(anIndex);
+      GeomShapePtr aFace = aFaceAttrInList->value();
+      if (!aFace.get()) {
+        return;
+      }
+      aFaces.push_back(aFace);
+    }
+
+    aThicknessAlgo = std::shared_ptr<GeomAlgoAPI_Thickness>
+      (new GeomAlgoAPI_Thickness (aBaseShape, aFaces, aThickness, isInside));
+  }
+
+  std::string anError;
+  if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aThicknessAlgo, getKind(), anError)) {
+    setError(anError);
+    return;
+  }
+
+  GeomShapePtr aResult = aThicknessAlgo->shape();
+
+  // Store result.
+  int anIndex = 0;
+  ResultBodyPtr aResultBody = document()->createBody(data(), anIndex);
+  if (aCreationMethod == CREATION_METHOD_THICK()) {
+    aResultBody->storeGenerated(aBaseShape, aResult);
+  }
+  else {
+    aResultBody->storeModified(aBaseShape, aResult);
+  }
+  aResultBody->loadModifiedShapes(aThicknessAlgo, aBaseShape, GeomAPI_Shape::FACE);
+  aResultBody->loadGeneratedShapes(aThicknessAlgo, aBaseShape, GeomAPI_Shape::FACE);
+  aResultBody->loadGeneratedShapes(aThicknessAlgo, aBaseShape, GeomAPI_Shape::EDGE);
+  aResultBody->loadGeneratedShapes(aThicknessAlgo, aBaseShape, GeomAPI_Shape::VERTEX);
+  setResult(aResultBody, anIndex);
+}
+
+//==================================================================================================
+void FeaturesPlugin_Thickness::attributeChanged(const std::string& theID)
+{
+  if (theID == CREATION_METHOD_ID()) {
+    // clean base shape, as it has different type in different modes,
+    // so, it cannot be the same
+    AttributeSelectionPtr aBaseAttr = selection(BASE_SHAPE_ID());
+    AttributeSelectionListPtr aFaceAttr = selectionList(FACES_ID());
+    data()->blockSendAttributeUpdated(true, false);
+    aBaseAttr->reset();
+    aFaceAttr->clear(); // reset doesn't work for a list
+    data()->blockSendAttributeUpdated(false, false);
+  }
+  ModelAPI_Feature::attributeChanged(theID);
+}
diff --git a/src/FeaturesPlugin/FeaturesPlugin_Thickness.h b/src/FeaturesPlugin/FeaturesPlugin_Thickness.h
new file mode 100644 (file)
index 0000000..a070bb1
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright (C) 2014-2024  CEA, EDF
+//
+// 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_Thickness_H_
+#define FeaturesPlugin_Thickness_H_
+
+#include "FeaturesPlugin.h"
+
+#include <ModelAPI_Feature.h>
+
+/// \class FeaturesPlugin_Thickness
+/// \ingroup Plugins
+/// \brief Feature for thickness.
+class FeaturesPlugin_Thickness: public ModelAPI_Feature
+{
+public:
+  /// Use plugin manager for features creation
+  FeaturesPlugin_Thickness();
+
+  /// Feature kind.
+  inline static const std::string& ID()
+  {
+    static const std::string MY_ID("Thickness");
+    return MY_ID;
+  }
+
+  /// Attribute name for creation method.
+  inline static const std::string& CREATION_METHOD_ID()
+  {
+    static const std::string MY_CREATION_METHOD_ID("creation_method");
+    return MY_CREATION_METHOD_ID;
+  }
+
+  /// Attribute name for creation method.
+  inline static const std::string& CREATION_METHOD_THICK()
+  {
+    static const std::string MY_CREATION_METHOD_THICK("thickness");
+    return MY_CREATION_METHOD_THICK;
+  }
+
+  /// Attribute name for creation method.
+  inline static const std::string& CREATION_METHOD_HOLLOWED()
+  {
+    static const std::string MY_CREATION_METHOD_HOLLOWED("hollowed_solid");
+    return MY_CREATION_METHOD_HOLLOWED;
+  }
+
+  /// Attribute name of base shape.
+  inline static const std::string& BASE_SHAPE_ID()
+  {
+    static const std::string MY_BASE_SHAPE_ID("base_shape");
+    return MY_BASE_SHAPE_ID;
+  }
+
+  /// Attribute name of sub-faces to remove (for hollowed solid mode).
+  inline static const std::string& FACES_ID()
+  {
+    static const std::string MY_FACES_ID("faces_to_remove");
+    return MY_FACES_ID;
+  }
+
+  /// Attribute name of thickness value.
+  inline static const std::string& THICKNESS_VALUE_ID()
+  {
+    static const std::string MY_THICKNESS_VALUE_ID("thickness_value");
+    return MY_THICKNESS_VALUE_ID;
+  }
+
+  /// Attribute name of pipe/intersection joint bool flag.
+  inline static const std::string& INSIDE_ID()
+  {
+    static const std::string MY_INSIDE_ID("is_inside");
+    return MY_INSIDE_ID;
+  }
+
+
+  /// \return the kind of a feature.
+  FEATURESPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = FeaturesPlugin_Thickness::ID();
+    return MY_KIND;
+  }
+
+  /// Request for initialization of data model of the feature: adding all attributes.
+  FEATURESPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Performs the algorithm and stores results it in the data structure.
+  FEATURESPLUGIN_EXPORT virtual void execute();
+
+  /// Called on change of any argument-attribute of this object.
+  /// \param[in] theID identifier of changed attribute.
+  FEATURESPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+};
+
+#endif
index 3b9784fc10298489ad7f7c1d7254d59fc10918c4..56054e8e0d4fa592941b841717f709277df4d27c 100644 (file)
@@ -48,6 +48,7 @@
 #include <GeomValidators_ShapeType.h>
 
 #include <GeomAPI_DataMapOfShapeShape.h>
+#include <GeomAPI_IndexedMapOfShape.h>
 #include <GeomAPI_Lin.h>
 #include <GeomAPI_PlanarEdges.h>
 #include <GeomAPI_Pln.h>
@@ -1115,6 +1116,160 @@ bool FeaturesPlugin_ValidatorFillet1DSelection::isValid(const AttributePtr& theA
   return true;
 }
 
+//=============================================================================================
+bool FeaturesPlugin_ValidatorOffsetFacesSelection::isValid(const AttributePtr& theAttribute,
+                                                     const std::list<std::string>& theArguments,
+                                                     Events_InfoMessage& theError) const
+{
+  AttributeSelectionListPtr aSubShapesAttrList =
+    std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
+  if (!aSubShapesAttrList.get()) {
+    theError = "Error: This validator can only work with selection list in \"Offset\" feature.";
+    return false;
+  }
+
+  static const std::string aBaseShapeID = "base_shape";
+  FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
+  AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeID);
+
+  if (!aShapeAttrSelection.get()) {
+    theError = "Error: Could not get \"%1\" attribute.";
+    theError.arg(aBaseShapeID);
+    return false;
+  }
+
+  GeomShapePtr aBaseShape = aShapeAttrSelection->value();
+  ResultPtr aContext = aShapeAttrSelection->context();
+  if (!aContext.get()) {
+    theError = "Error: Empty context.";
+    return false;
+  }
+  if (!aBaseShape.get()) {
+    aBaseShape = aContext->shape();
+  }
+  if (!aBaseShape.get()) {
+    theError = "Error: Empty base shape.";
+    return false;
+  }
+
+  if (!aSubShapesAttrList->size()) {
+    theError = "Error: No faces selected.";
+    return false;
+  }
+
+  GeomAPI_IndexedMapOfShape aSubShapesMap (aBaseShape);
+  for (int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
+    AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
+    GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
+    if (!aShapeToAdd.get()) {
+      theError = "Error: Wrong shape selected.";
+      return false;
+    }
+    if (!aSubShapesMap.FindIndex(aShapeToAdd)) {
+      theError = "Error: Only sub-shapes of selected shape are allowed for selection.";
+      return false;
+    }
+  }
+
+  return true;
+}
+
+//=============================================================================================
+bool FeaturesPlugin_ValidatorThicknessSelection::isValid(const AttributePtr& theAttribute,
+                                                   const std::list<std::string>& theArguments,
+                                                   Events_InfoMessage& theError) const
+{
+  static const std::string aBaseShapeID = "base_shape";
+  static const std::string aCreationMethodID = "creation_method";
+  static const std::string aCreationMethodTH = "thickness";
+
+  FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
+
+  AttributeSelectionPtr aShapeAttrSelection =
+    std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
+  if (aShapeAttrSelection.get()) {
+    // 1. Check main objects type (depends on creation method)
+    GeomShapePtr aBaseShape = aShapeAttrSelection->value();
+    ResultPtr aContext = aShapeAttrSelection->context();
+    if (!aContext.get()) {
+      theError = "Error: Empty context.";
+      return false;
+    }
+    if (!aBaseShape.get()) {
+      aBaseShape = aContext->shape();
+    }
+    if (!aBaseShape.get()) {
+      theError = "Error: Empty base shape.";
+      return false;
+    }
+
+    AttributeStringPtr aCreationMethodAttr = aFeature->string(aCreationMethodID);
+    if (aCreationMethodAttr->value() == aCreationMethodTH) {
+      // should be a face or a shell
+      return aBaseShape->isShell() || aBaseShape->isFace();
+    }
+
+    // shoud be a solid
+    return aBaseShape->isSolid();
+  }
+
+  // 2. Check faces selection
+  AttributeSelectionListPtr aSubShapesAttrList =
+    std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
+  if (!aSubShapesAttrList.get()) {
+    theError = "Error: This validator can only work with selection in \"Thickness\" feature.";
+    return false;
+  }
+
+  // base shape
+  aShapeAttrSelection = aFeature->selection(aBaseShapeID);
+
+  if (!aShapeAttrSelection.get()) {
+    theError = "Error: Could not get \"%1\" attribute.";
+    theError.arg(aBaseShapeID);
+    return false;
+  }
+
+  GeomShapePtr aBaseShape = aShapeAttrSelection->value();
+  ResultPtr aContext = aShapeAttrSelection->context();
+  if (!aContext.get()) {
+    theError = "Error: Empty context.";
+    return false;
+  }
+  if (!aBaseShape.get()) {
+    aBaseShape = aContext->shape();
+  }
+  if (!aBaseShape.get()) {
+    theError = "Error: Empty base shape.";
+    return false;
+  }
+
+  if (!aSubShapesAttrList->size()) {
+    theError = "Error: No faces selected.";
+    return false;
+  }
+
+  GeomAPI_IndexedMapOfShape aSubShapesMap (aBaseShape);
+  for (int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
+    AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
+    GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
+    if (!aShapeToAdd.get()) {
+      theError = "Error: Wrong shape selected.";
+      return false;
+    }
+    if (!aSubShapesMap.FindIndex(aShapeToAdd)) {
+      theError = "Error: Only sub-shapes of selected shape are allowed for selection.";
+      return false;
+    }
+    if (!aShapeToAdd->isFace()) {
+      theError = "Error: Only faces are allowed for selection.";
+      return false;
+    }
+  }
+
+  return true;
+}
+
 //==================================================================================================
 bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
                                                        const std::list<std::string>& theArguments,
index 7839f8ee70ca288f0f3a1cb1d3eea1b41f03b445..a0c684a46c7131b4d2b57592a71ed6f556048f8b 100644 (file)
@@ -219,6 +219,38 @@ public:
                        Events_InfoMessage& theError) const;
 };
 
+/// \class FeaturesPlugin_ValidatorOffsetFacesSelection
+/// \ingroup Validators
+/// \brief Validates selection for "Offset" feature.
+class FeaturesPlugin_ValidatorOffsetFacesSelection: public ModelAPI_AttributeValidator
+{
+public:
+  /// \return True if the attribute is valid. It checks whether the selection
+  /// is acceptable for 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;
+};
+
+/// \class FeaturesPlugin_ValidatorThicknessSelection
+/// \ingroup Validators
+/// \brief Validates selection for "Thickness" feature.
+class FeaturesPlugin_ValidatorThicknessSelection: public ModelAPI_AttributeValidator
+{
+public:
+  /// \return True if the attribute is valid. It checks whether the selection
+  /// is acceptable for 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;
+};
+
 /// \class FeaturesPlugin_ValidatorPartitionSelection
 /// \ingroup Validators
 /// \brief Validates selection for partition.
index a01ffc9bc19e22eb61e295bf8b853174e8889e90..ebc521b6289fd7d86d0825d1870c56374c68d628 100644 (file)
       <source>Normal to a face</source>
       <translation>Normale d&apos;une face</translation>
     </message>
+    <message>
+      <source>Offset</source>
+      <translation>Décalage</translation>
+    </message>
+    <message>
+      <source>Thickness</source>
+      <translation>Épaisseur</translation>
+    </message>
     <message>
       <source>Partition</source>
       <translation>Partition</translation>
     </message>
   </context>
 
+  <!-- Offset -->
+  <context>
+    <name>Offset3d</name>
+    <message>
+      <source>Offset</source>
+      <translation>Décalage</translation>
+    </message>
+    <message>
+      <source>Perform offset</source>
+      <translation>Effectuer des décalage</translation>
+    </message>
+  </context>
+  <context>
+    <name>Offset3d:base_shape</name>
+    <message>
+      <source>Shape:</source>
+      <translation>Forme:</translation>
+    </message>
+    <message>
+      <source>Select a shape to offset.</source>
+      <translation>Sélectionnez une forme à décaler.</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un objet</translation>
+    </message>
+  </context>
+  <context>
+    <name>Offset3d:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Offset3d:offset_value</name>
+    <message>
+      <source>Offset</source>
+      <translation>Décalage</translation>
+    </message>
+  </context>
+  <context>
+    <name>Offset3d:creation_method</name>
+    <message>
+      <source>Offset</source>
+      <translation>Décalage</translation>
+    </message>
+    <message>
+      <source>Partial offset</source>
+      <translation>Décalage partiel</translation>
+    </message>
+  </context>
+  <context>
+    <name>Offset3d:pipe_joint</name>
+    <message>
+      <source>Join by pipes</source>
+      <translation>Rejoindre par des tuyaux</translation>
+    </message>
+  </context>
+  <context>
+    <name>Offset3d:faces_to_offset</name>
+    <message>
+      <source>Faces to offset:</source>
+      <translation>Faces à décaler :</translation>
+    </message>
+    <message>
+      <source>Select faces of the main shape.</source>
+      <translation>Sélectionnez les faces de la forme principale.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Offset3d:faces_to_offset:FeaturesPlugin_ValidatorOffsetFacesSelection</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>Erreur : contexte vide.</translation>
+    </message>
+    <message>
+      <source>Error: No faces selected.</source>
+      <translation>Erreur: Aucun face sélectionné.</translation>
+    </message>
+  </context>
+
+  <!-- Thickness -->
+  <context>
+    <name>Thickness</name>
+    <message>
+      <source>Thickness</source>
+      <translation>Épaisseur</translation>
+    </message>
+    <message>
+      <source>Make a thickness or a hollowed solid</source>
+      <translation>Réaliser une épaisseur ou un solide creux</translation>
+    </message>
+  </context>
+  <context>
+    <name>Thickness:creation_method</name>
+    <message>
+      <source>Thickness</source>
+      <translation>Épaisseur</translation>
+    </message>
+    <message>
+      <source>Hollowed Solid</source>
+      <translation>Solide évidé</translation>
+    </message>
+  </context>
+  <context>
+    <name>Thickness:base_shape</name>
+    <message>
+      <source>Face or Shell:</source>
+      <translation>Face ou Coque:</translation>
+    </message>
+    <message>
+      <source>Select a face or a shell.</source>
+      <translation>Sélectionnez une face ou une coque.</translation>
+    </message>
+    <message>
+      <source>Solid:</source>
+      <translation>Solide:</translation>
+    </message>
+    <message>
+      <source>Select a solid.</source>
+      <translation>Sélectionnez un solide.</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un objet</translation>
+    </message>
+  </context>
+  <context>
+    <name>Thickness:base_shape:FeaturesPlugin_ValidatorThicknessSelection</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>Erreur : contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Thickness:faces_to_remove</name>
+    <message>
+      <source>Faces to remove:</source>
+      <translation>Faces à supprimer:</translation>
+    </message>
+    <message>
+      <source>Select faces of the main shape.</source>
+      <translation>Sélectionnez les faces de la forme principale.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Thickness:faces_to_remove:FeaturesPlugin_ValidatorThicknessSelection</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>Erreur : contexte vide.</translation>
+    </message>
+    <message>
+      <source>Error: No faces selected.</source>
+      <translation>Erreur: Aucun face sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Thickness:thickness_value</name>
+    <message>
+      <source>Thickness</source>
+      <translation>Épaisseur</translation>
+    </message>
+    <message>
+      <source>Thickness value</source>
+      <translation>Valeur d'épaisseur</translation>
+    </message>
+  </context>
+  <context>
+    <name>Thickness:is_inside</name>
+    <message>
+      <source>Thicken towards the inside</source>
+      <translation>Épaissir vers l'intérieur</translation>
+    </message>
+  </context>
+
   <!-- Partition -->
   <context>
     <name>Partition</name>
diff --git a/src/FeaturesPlugin/Test/TestOffset.py b/src/FeaturesPlugin/Test/TestOffset.py
new file mode 100644 (file)
index 0000000..8c2f511
--- /dev/null
@@ -0,0 +1,82 @@
+# Copyright (C) 2018-2024  CEA, EDF
+#
+# 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()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Box
+Box_1 = model.addBox(Part_1_doc, 200, 200, 200)
+Box_2 = model.addBox(Part_1_doc, 200, 200, 200)
+Box_3 = model.addBox(Part_1_doc, 200, 200, 200)
+
+### Create Shell
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Box_1_1/Top"),
+                                      model.selection("FACE", "Box_1_1/Front"),
+                                      model.selection("FACE", "Box_1_1/Left")])
+
+# Global offset (pipe joints)
+Offset_1 = model.addOffset(Part_1_doc, model.selection("SHELL", "Shell_1_1"), 70., True)
+
+# Global offset (intersection joints)
+Offset_2 = model.addOffset(Part_1_doc, model.selection("SOLID", "Box_2_1"), 60., False)
+
+# Partial offset
+Offset_3 = model.addOffsetPartial(Part_1_doc,
+                                  model.selection("SOLID", "Box_3_1"),
+                                  50.,
+                                  [model.selection("FACE", "Box_3_1/Top"),
+                                   model.selection("FACE", "Box_3_1/Back"),
+                                   model.selection("FACE", "Box_3_1/Right")])
+
+model.end()
+
+from GeomAPI import GeomAPI_Shape
+
+#test Offset_1
+model.testNbResults(Offset_1, 1)
+model.testNbSubResults(Offset_1, [0])
+model.testNbSubShapes(Offset_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Offset_1, GeomAPI_Shape.FACE, [7])
+model.testNbSubShapes(Offset_1, GeomAPI_Shape.EDGE, [27])
+model.testNbSubShapes(Offset_1, GeomAPI_Shape.VERTEX, [54])
+model.testResultsAreas(Offset_1, [193670.3477])
+
+#test Offset_2
+model.testNbResults(Offset_1, 1)
+model.testNbSubResults(Offset_2, [0])
+model.testNbSubShapes(Offset_2, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Offset_2, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Offset_2, GeomAPI_Shape.EDGE, [24])
+model.testNbSubShapes(Offset_2, GeomAPI_Shape.VERTEX, [48])
+model.testResultsVolumes(Offset_2, [32768000])
+
+#test Offset_3
+model.testNbResults(Offset_3, 1)
+model.testNbSubResults(Offset_3, [0])
+model.testNbSubShapes(Offset_3, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Offset_3, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Offset_3, GeomAPI_Shape.EDGE, [24])
+model.testNbSubShapes(Offset_3, GeomAPI_Shape.VERTEX, [48])
+model.testResultsVolumes(Offset_3, [15625000])
diff --git a/src/FeaturesPlugin/Test/TestThickness.py b/src/FeaturesPlugin/Test/TestThickness.py
new file mode 100644 (file)
index 0000000..f39a7c1
--- /dev/null
@@ -0,0 +1,83 @@
+# Copyright (C) 2018-2024  CEA, EDF
+#
+# 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()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Box
+Box_1 = model.addBox(Part_1_doc, 200, 200, 200)
+Box_2 = model.addBox(Part_1_doc, 200, 200, 200)
+Box_3 = model.addBox(Part_1_doc, 200, 200, 200)
+
+### Create Shell
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Box_1_1/Top"),
+                                      model.selection("FACE", "Box_1_1/Front"),
+                                      model.selection("FACE", "Box_1_1/Left")])
+Shell_2 = model.addShell(Part_1_doc, [model.selection("FACE", "Box_2_1/Top"),
+                                      model.selection("FACE", "Box_2_1/Front"),
+                                      model.selection("FACE", "Box_2_1/Left")])
+
+# Thickness mode 1: thicken a shell/face
+Thickness_1 = model.addThickness(Part_1_doc, model.selection("SHELL", "Shell_1_1"), 30, False)
+Thickness_2 = model.addThickness(Part_1_doc, model.selection("SHELL", "Shell_2_1"), 30, True)
+
+# Thickness mode 2: hollowed solid
+Thickness_3 = model.addHollowedSolid(Part_1_doc,
+                                     model.selection("SOLID", "Box_3_1"),
+                                     40,
+                                     [model.selection("FACE", "Box_3_1/Top"),
+                                      model.selection("FACE", "Box_3_1/Left")],
+                                     False)
+
+model.end()
+
+from GeomAPI import GeomAPI_Shape
+
+#test Thickness_1
+model.testNbResults(Thickness_1, 1)
+model.testNbSubResults(Thickness_1, [0])
+model.testNbSubShapes(Thickness_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Thickness_1, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Thickness_1, GeomAPI_Shape.EDGE, [48])
+model.testNbSubShapes(Thickness_1, GeomAPI_Shape.VERTEX, [96])
+model.testResultsVolumes(Thickness_1, [4167000])
+
+#test Thickness_2
+model.testNbResults(Thickness_1, 1)
+model.testNbSubResults(Thickness_2, [0])
+model.testNbSubShapes(Thickness_2, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Thickness_2, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Thickness_2, GeomAPI_Shape.EDGE, [48])
+model.testNbSubShapes(Thickness_2, GeomAPI_Shape.VERTEX, [96])
+model.testResultsVolumes(Thickness_2, [3087000])
+
+#test Thickness_3
+model.testNbResults(Thickness_3, 1)
+model.testNbSubResults(Thickness_3, [0])
+model.testNbSubShapes(Thickness_3, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Thickness_3, GeomAPI_Shape.FACE, [10])
+model.testNbSubShapes(Thickness_3, GeomAPI_Shape.EDGE, [48])
+model.testNbSubShapes(Thickness_3, GeomAPI_Shape.VERTEX, [96])
+model.testResultsVolumes(Thickness_3, [8128000])
index 43d13da812728109e42edb8a7f2b55499e2cb252..a89beaf800ae8c0aafa21dd39a5da73a0ac1b91c 100644 (file)
@@ -31,6 +31,7 @@ Features plug-in provides a set of common topological operations. It implements
    loftFeature.rst
    measurementFeature.rst
    normalToFaceFeature.rst
+   offsetFeature.rst
    pipeFeature.rst
    placementFeature.rst
    pointCoordinatesFeature.rst
@@ -42,5 +43,6 @@ Features plug-in provides a set of common topological operations. It implements
    rotationFeature.rst
    sewingFeature.rst
    symmetryFeature.rst
+   thicknessFeature.rst
    transformationFeature.rst
    translationFeature.rst
diff --git a/src/FeaturesPlugin/doc/TUI_offsetFeature.rst b/src/FeaturesPlugin/doc/TUI_offsetFeature.rst
new file mode 100644 (file)
index 0000000..d53f635
--- /dev/null
@@ -0,0 +1,11 @@
+
+  .. _tui_offset:
+
+offset
+======
+
+.. literalinclude:: examples/offset.py      
+    :linenos:
+    :language: python
+
+:download:`Download this script <examples/offset.py>`
diff --git a/src/FeaturesPlugin/doc/TUI_thicknessFeature.rst b/src/FeaturesPlugin/doc/TUI_thicknessFeature.rst
new file mode 100644 (file)
index 0000000..ded4f92
--- /dev/null
@@ -0,0 +1,11 @@
+
+  .. _tui_thickness:
+
+thickness
+=========
+
+.. literalinclude:: examples/thickness.py      
+    :linenos:
+    :language: python
+
+:download:`Download this script <examples/thickness.py>`
diff --git a/src/FeaturesPlugin/doc/examples/offset.py b/src/FeaturesPlugin/doc/examples/offset.py
new file mode 100644 (file)
index 0000000..2e14238
--- /dev/null
@@ -0,0 +1,30 @@
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Box
+Box_1 = model.addBox(Part_1_doc, 200, 200, 200)
+Box_2 = model.addBox(Part_1_doc, 200, 200, 200)
+
+### Create Shell
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Box_1_1/Top"),
+                                      model.selection("FACE", "Box_1_1/Front"),
+                                      model.selection("FACE", "Box_1_1/Left")])
+
+# Offset of the whole shape, pipe joints (isPipeJoint = True)
+Offset_1 = model.addOffset(Part_1_doc, model.selection("SHELL", "Shell_1_1"), 70., True)
+
+# Partial offset. Negative offset value means offset in direction, opposite to normale.
+Offset_2 = model.addOffsetPartial(Part_1_doc,
+                                  model.selection("SOLID", "Box_2_1"),
+                                  -50.,
+                                  [model.selection("FACE", "Box_2_1/Top")])
+
+model.end()
diff --git a/src/FeaturesPlugin/doc/examples/thickness.py b/src/FeaturesPlugin/doc/examples/thickness.py
new file mode 100644 (file)
index 0000000..364d13e
--- /dev/null
@@ -0,0 +1,34 @@
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Box
+Box_1 = model.addBox(Part_1_doc, 200, 200, 200)
+Box_2 = model.addBox(Part_1_doc, 200, 200, 200)
+
+### Create Shell
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Box_1_1/Top"),
+                                      model.selection("FACE", "Box_1_1/Front"),
+                                      model.selection("FACE", "Box_1_1/Left")])
+
+# Thickness mode 1: thicken a shell/face
+# isInside = False, so thicken towards outside
+Thickness_1 = model.addThickness(Part_1_doc, model.selection("SHELL", "Shell_1_1"), 30, False)
+
+# Thickness mode 2: hollowed solid
+# isInside = True, so thicken towards inside
+Thickness_2 = model.addHollowedSolid(Part_1_doc,
+                                     model.selection("SOLID", "Box_2_1"),
+                                     40,
+                                     [model.selection("FACE", "Box_2_1/Top"),
+                                      model.selection("FACE", "Box_2_1/Left")],
+                                     True)
+
+model.end()
diff --git a/src/FeaturesPlugin/doc/images/offset3D.png b/src/FeaturesPlugin/doc/images/offset3D.png
new file mode 100644 (file)
index 0000000..47e03cc
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/offset3D.png differ
diff --git a/src/FeaturesPlugin/doc/images/offset3D_partial.png b/src/FeaturesPlugin/doc/images/offset3D_partial.png
new file mode 100644 (file)
index 0000000..ced1d32
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/offset3D_partial.png differ
diff --git a/src/FeaturesPlugin/doc/images/offsetPartialPropertyPanel.png b/src/FeaturesPlugin/doc/images/offsetPartialPropertyPanel.png
new file mode 100644 (file)
index 0000000..15f3684
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/offsetPartialPropertyPanel.png differ
diff --git a/src/FeaturesPlugin/doc/images/offsetPropertyPanel.png b/src/FeaturesPlugin/doc/images/offsetPropertyPanel.png
new file mode 100644 (file)
index 0000000..272372c
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/offsetPropertyPanel.png differ
diff --git a/src/FeaturesPlugin/doc/images/offset_partial_result.png b/src/FeaturesPlugin/doc/images/offset_partial_result.png
new file mode 100644 (file)
index 0000000..a39dba1
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/offset_partial_result.png differ
diff --git a/src/FeaturesPlugin/doc/images/offset_result.png b/src/FeaturesPlugin/doc/images/offset_result.png
new file mode 100644 (file)
index 0000000..6404310
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/offset_result.png differ
diff --git a/src/FeaturesPlugin/doc/images/thickness.png b/src/FeaturesPlugin/doc/images/thickness.png
new file mode 100644 (file)
index 0000000..bee2928
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/thickness.png differ
diff --git a/src/FeaturesPlugin/doc/images/thickness2.png b/src/FeaturesPlugin/doc/images/thickness2.png
new file mode 100644 (file)
index 0000000..31b9e56
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/thickness2.png differ
diff --git a/src/FeaturesPlugin/doc/images/thicknessPropertyPanel.png b/src/FeaturesPlugin/doc/images/thicknessPropertyPanel.png
new file mode 100644 (file)
index 0000000..79cd361
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/thicknessPropertyPanel.png differ
diff --git a/src/FeaturesPlugin/doc/images/thicknessPropertyPanel2.png b/src/FeaturesPlugin/doc/images/thicknessPropertyPanel2.png
new file mode 100644 (file)
index 0000000..382f0e2
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/thicknessPropertyPanel2.png differ
diff --git a/src/FeaturesPlugin/doc/images/thickness_result.png b/src/FeaturesPlugin/doc/images/thickness_result.png
new file mode 100644 (file)
index 0000000..47ec5a0
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/thickness_result.png differ
diff --git a/src/FeaturesPlugin/doc/images/thickness_result2.png b/src/FeaturesPlugin/doc/images/thickness_result2.png
new file mode 100644 (file)
index 0000000..6a6087a
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/thickness_result2.png differ
diff --git a/src/FeaturesPlugin/doc/offsetFeature.rst b/src/FeaturesPlugin/doc/offsetFeature.rst
new file mode 100644 (file)
index 0000000..c32ea01
--- /dev/null
@@ -0,0 +1,108 @@
+.. |offset.icon|    image:: images/offset3D.png
+
+Offset
+======
+
+**Offset** feature translates each point of the **Shape**
+along a local normal by the given **Offset distance**
+(signed number, negative value means inner offset).
+
+To create an Offset in the active part:
+
+#. select in the Main Menu *Features - > Offset* item  or
+#. click |offset.icon| **Offset** button in the toolbar
+
+Two Offset algorithms are:
+
+.. figure:: images/offset3D.png
+   :align: left
+   :height: 24px
+
+offset the whole shape by the same value
+
+.. figure:: images/offset3D_partial.png
+   :align: left
+   :height: 24px
+
+offset selected faces by the given value, other faces by zero.
+
+--------------------------------------------------------------------------------
+
+Offset the whole shape by the same value
+----------------------------------------
+
+.. figure:: images/offsetPropertyPanel.png
+   :align: center
+
+   Offset by the same value property panel
+
+Input fields:
+
+- **Shape** defines the base shape (solid, shell or face) selected in 3D OCC viewer or object browser;
+- **Distance** defines the offset value. Negative value meaning inner offset;
+- **Join by pipes** check box defines the mode of filling the gaps between translated
+  adjacent surfaces:
+
+  - if <b>Join by pipes</b> is activated, they are filled with pipes;
+  - else the surfaces are extended and intersected, so that sharp edges are preserved;
+
+**TUI Command**:
+
+.. py:function:: model.addOffset(Part_doc, shape, dist, isPipeJoint)
+
+    :param part: The current part object.
+    :param object: A shape in format *model.selection(TYPE, shape)*.
+    :param real: Offset distance value.
+    :param boolean: Join by pipes/intersection flag.
+    :return: Created object.
+
+Result
+""""""
+
+Result of offset of a box. Join by pipes activated.
+
+.. figure:: images/offset_result.png
+   :align: center
+
+   Offset of a box
+
+**See Also** a sample TUI Script of :ref:`tui_offset` operation.
+
+
+Offset selected faces by the given value, other faces by zero
+-------------------------------------------------------------
+
+.. figure:: images/offsetPartialPropertyPanel.png
+   :align: center
+
+   Partial Offset property panel
+
+Input fields:
+
+- **Shape** defines the base shape (solid, shell or face) selected in 3D OCC viewer or object browser;
+- **Distance** defines the offset value. Negative value meaning inner offset;
+- **Faces to offset** defines the faces of the base shape, which should be offset;
+
+*Note*: In Partial Offset mode gaps are allways filled by intersection.
+
+**TUI Command**:
+
+.. py:function:: model.addOffsetPartial(Part_doc, shape, dist, faces)
+
+    :param part: The current part object.
+    :param object: A shape in format *model.selection(TYPE, shape)*.
+    :param real: Offset distance value.
+    :param objects: Faces of the shape in format *[model.selection(TYPE, shape), ...]*.
+    :return: Created object.
+
+Result
+""""""
+
+Result of partial offset of a box. Top and front faces selected.
+
+.. figure:: images/offset_partial_result.png
+   :align: center
+
+   Partial offset of a box
+
+**See Also** a sample TUI Script of :ref:`tui_offset` operation.
diff --git a/src/FeaturesPlugin/doc/thicknessFeature.rst b/src/FeaturesPlugin/doc/thicknessFeature.rst
new file mode 100644 (file)
index 0000000..fb8eba5
--- /dev/null
@@ -0,0 +1,100 @@
+.. |thickness.icon|    image:: images/thickness.png
+
+Thickness
+=========
+
+To create a **Thickness** or a **Hollowed Solid** in the active part:
+
+#. select in the Main Menu *Features - > Thickness* item or
+#. click |thickness.icon| **Thickness** button in the toolbar
+
+Two Thickness algorithms are:
+
+.. figure:: images/thickness.png    
+   :align: left
+   :height: 24px
+
+make a thickness of a shell or a face
+
+.. figure:: images/thickness2.png    
+   :align: left
+   :height: 24px
+
+make a hollowed solid
+
+--------------------------------------------------------------------------------
+
+Thickness of a shell or a face
+------------------------------
+
+.. figure:: images/thicknessPropertyPanel.png
+   :align: center
+
+   Thickness property panel
+
+Input fields:
+
+- **Shape** defines the base shape (shell or face) selected in 3D OCC viewer or object browser;
+- **Distance** defines the thickness value. Negative values are not allowed;
+- **Thicken towards the inside** check box defines the thickening direction;
+
+**TUI Command**:
+
+.. py:function:: model.addThickness(Part_doc, shape, dist, isInside)
+
+    :param part: The current part object.
+    :param object: A shape in format *model.selection(TYPE, shape)*.
+    :param real: Thickness value.
+    :param boolean: Inside/outside direction flag.
+    :return: Created object.
+
+Result
+""""""
+
+Result of thickness of a shell.
+
+.. figure:: images/thickness_result.png
+   :align: center
+
+   Thickness of a shell
+
+**See Also** a sample TUI Script of :ref:`tui_thickness` operation.
+
+
+Hollowed solid
+--------------
+
+.. figure:: images/thicknessPropertyPanel2.png
+   :align: center
+
+   Hollowed Solid property panel
+
+Input fields:
+
+- **Shape** defines the base shape (solid) selected in 3D OCC viewer or object browser;
+- **Distance** defines the thickness value. Negative values are not allowed;
+- **Faces to remove** defines the faces of the base solid, where the hole is done;
+- **Thicken towards the inside** check box defines the thickening direction;
+
+**TUI Command**:
+
+.. py:function:: model.addHollowedSolid(Part_doc, shape, dist, faces, isInside)
+
+    :param part: The current part object.
+    :param object: A shape in format *model.selection("SOLID", shape)*.
+    :param real: Thickness value.
+    :param objects: Faces of the solid in format *[model.selection("FACE", shape), ...]*.
+    :param boolean: Inside/outside direction flag.
+    :return: Created object.
+
+Result
+""""""
+
+Result of hollowed solid of a box. Left and front faces selected.
+
+.. figure:: images/thickness_result2.png
+   :align: center
+
+   Hollowed solid of a box
+
+**See Also** a sample TUI Script of :ref:`tui_thickness` operation.
diff --git a/src/FeaturesPlugin/icons/offset3D.png b/src/FeaturesPlugin/icons/offset3D.png
new file mode 100644 (file)
index 0000000..47e03cc
Binary files /dev/null and b/src/FeaturesPlugin/icons/offset3D.png differ
diff --git a/src/FeaturesPlugin/icons/offset3D_partial.png b/src/FeaturesPlugin/icons/offset3D_partial.png
new file mode 100644 (file)
index 0000000..ced1d32
Binary files /dev/null and b/src/FeaturesPlugin/icons/offset3D_partial.png differ
diff --git a/src/FeaturesPlugin/icons/thickness.png b/src/FeaturesPlugin/icons/thickness.png
new file mode 100644 (file)
index 0000000..bee2928
Binary files /dev/null and b/src/FeaturesPlugin/icons/thickness.png differ
diff --git a/src/FeaturesPlugin/icons/thickness2.png b/src/FeaturesPlugin/icons/thickness2.png
new file mode 100644 (file)
index 0000000..31b9e56
Binary files /dev/null and b/src/FeaturesPlugin/icons/thickness2.png differ
diff --git a/src/FeaturesPlugin/offset_widget.xml b/src/FeaturesPlugin/offset_widget.xml
new file mode 100644 (file)
index 0000000..8418dda
--- /dev/null
@@ -0,0 +1,33 @@
+<source>
+  <shape_selector id="base_shape"
+                  label="Shape:"
+                  tooltip="Select a shape to offset."
+                  shape_types="objects"
+                  concealment="true">
+    <validator id="GeomValidators_ShapeType" parameters="face,shell,solid"/>
+  </shape_selector>
+  <doublevalue id="offset_value"
+               label="Offset"
+               step="1.0"
+               default="1.0"
+               icon="icons/Features/dimension_v.png"
+               tooltip="Offset"/>
+  <toolbox id="creation_method">
+    <box id="offset_equal"
+         title="Offset"
+         icon="icons/Features/offset3D.png">
+      <boolvalue id="pipe_joint" label="Join by pipes" default="true" tooltip="Join by pipes"/>
+    </box>
+    <box id="offset_partial"
+         title="Partial offset"
+         icon="icons/Features/offset3D_partial.png">
+      <multi_selector id="faces_to_offset"
+                      label="Faces to offset:"
+                      tooltip="Select faces of the main shape."
+                      shape_types="faces"
+                      clear_in_neutral_point="false">
+        <validator id="FeaturesPlugin_ValidatorOffsetFacesSelection"/>
+      </multi_selector>
+    </box>
+  </toolbox>
+</source>
index 3bebe12a5e9fc07aae90ce4b15fa4c208e82cf5a..113c0ab4c4f469a836393ab37463f98d98a375a6 100644 (file)
@@ -5,6 +5,10 @@
                icon="icons/Features/scale.png" helpfile="transformationFeature.html">
         <source path="scale_widget.xml"/>
       </feature>
+      <feature id="Offset3d" title="Offset" tooltip="Perform offset"
+               icon="icons/Features/offset3D.png" helpfile="offsetFeature.html">
+        <source path="offset_widget.xml"/>
+      </feature>
     </group>
     <group id="Extrusion">
       <feature id="Extrusion" title="Extrusion" tooltip="Create a solid by extrusion of a face"
                icon="icons/Features/loft.png" helpfile="loftFeature.html">
         <source path="loft_widget.xml"/>
       </feature>
+      <feature id="Thickness" title="Thickness" tooltip="Make a thickness or a hollowed solid"
+               icon="icons/Features/thickness.png" helpfile="thicknessFeature.html">
+        <source path="thickness_widget.xml"/>
+      </feature>
     </group>
     <group id="Boolean" toolbar="yes">
       <feature id="Cut" title="Cut" tooltip="Perform boolean cut operation with objects"
index 25a67737eec715f51497082786dfd83495113ddb..27d9199dcf6086061a15e859675ad597ed674240 100644 (file)
@@ -532,6 +532,8 @@ SET(TEST_NAMES_PARA
                Test23885.py
                TestNormalToFace.py
                TestLoft.py
+               TestOffset.py
+               TestThickness.py
                TestSewing_Manifold.py
                TestSewing_NonManifold.py
                TestSewing_Groups.py
diff --git a/src/FeaturesPlugin/thickness_widget.xml b/src/FeaturesPlugin/thickness_widget.xml
new file mode 100644 (file)
index 0000000..854f869
--- /dev/null
@@ -0,0 +1,44 @@
+<source>
+  <toolbox id="creation_method">
+    <box id="thickness"
+         title="Thickness"
+         icon="icons/Features/thickness.png">
+      <shape_selector id="base_shape"
+                      label="Face or Shell:"
+                      tooltip="Select a face or a shell."
+                      shape_types="objects"
+                      concealment="true">
+        <validator id="GeomValidators_ShapeType" parameters="face,shell,solid"/>
+        <validator id="FeaturesPlugin_ValidatorThicknessSelection"/>
+      </shape_selector>
+    </box>
+    <box id="hollowed_solid"
+         title="Hollowed Solid"
+         icon="icons/Features/thickness2.png">
+      <shape_selector id="base_shape"
+                      label="Solid:"
+                      tooltip="Select a solid."
+                      shape_types="objects"
+                      concealment="true">
+        <validator id="GeomValidators_ShapeType" parameters="face,shell,solid"/>
+        <validator id="FeaturesPlugin_ValidatorThicknessSelection"/>
+      </shape_selector>
+      <multi_selector id="faces_to_remove"
+                      label="Faces to remove:"
+                      tooltip="Select faces of the main shape."
+                      shape_types="faces"
+                      clear_in_neutral_point="false">
+        <validator id="FeaturesPlugin_ValidatorThicknessSelection"/>
+      </multi_selector>
+    </box>
+  </toolbox>
+  <doublevalue id="thickness_value"
+               label="Thickness"
+               step="1.0"
+               default="1.0"
+               min="1e-07"
+               icon="icons/Features/dimension_v.png"
+               tooltip="Thickness value"/>
+  <boolvalue id="is_inside"
+             label="Thicken towards the inside" default="false" tooltip="Thicken towards the inside"/>
+</source>
index e01dbf2c76e786c589d4f4d8b565a34744cd3876..65dffd5443be7533a48edeb5deb67ce8df2228a7 100644 (file)
@@ -88,6 +88,7 @@ SET(PROJECT_HEADERS
     GeomAlgoAPI_CurveBuilder.h
     GeomAlgoAPI_NExplode.h
     GeomAlgoAPI_Offset.h
+    GeomAlgoAPI_Thickness.h
     GeomAlgoAPI_SolidClassifier.h
     GeomAlgoAPI_MapShapesAndAncestors.h
     GeomAlgoAPI_Projection.h
@@ -97,7 +98,7 @@ SET(PROJECT_HEADERS
     GeomAlgoAPI_NormalToFace.h
     GeomAlgoAPI_Tube.h
     GeomAlgoAPI_ShapeInfo.h
-         GeomAlgoAPI_CanonicalRecognition.h
+    GeomAlgoAPI_CanonicalRecognition.h
     GeomAlgoAPI_GlueFaces.h
     GeomAlgoAPI_LimitTolerance.h
     GeomAlgoAPI_Utils.h
@@ -169,6 +170,7 @@ SET(PROJECT_SOURCES
     GeomAlgoAPI_CurveBuilder.cpp
     GeomAlgoAPI_NExplode.cpp
     GeomAlgoAPI_Offset.cpp
+    GeomAlgoAPI_Thickness.cpp
     GeomAlgoAPI_SolidClassifier.cpp
     GeomAlgoAPI_MapShapesAndAncestors.cpp
     GeomAlgoAPI_Projection.cpp
@@ -178,9 +180,8 @@ SET(PROJECT_SOURCES
     GeomAlgoAPI_NormalToFace.cpp
     GeomAlgoAPI_Tube.cpp
     GeomAlgoAPI_ShapeInfo.cpp
-         GeomAlgoAPI_CanonicalRecognition.cpp
+    GeomAlgoAPI_CanonicalRecognition.cpp
     GeomAlgoAPI_GlueFaces.cpp
-       GeomAlgoAPI_CanonicalRecognition.cpp
     GeomAlgoAPI_LimitTolerance.cpp
     GeomAlgoAPI_Utils.cpp
     GeomAlgoAPI_NonPlanarFace.cpp
index 1206dd3ee5cb8ce5a4c177568a055b0545588638..1e0b54dbc5125645e8c3c8ad58b0e894aef3c585 100644 (file)
@@ -24,6 +24,7 @@
 #include <BRepBuilderAPI_MakeShape.hxx>
 #include <BRepCheck_Analyzer.hxx>
 #include <BRepGProp.hxx>
+#include <BRepOffset_MakeOffset.hxx>
 #include <GProp_GProps.hxx>
 #include <Precision.hxx>
 #include <TopExp_Explorer.hxx>
@@ -102,6 +103,9 @@ void GeomAlgoAPI_MakeShape::generated(const GeomShapePtr theOldShape,
   } else if(myBuilderType == OCCT_BOPAlgo_Builder) {
     BOPAlgo_Builder* aBOPBuilder = implPtr<BOPAlgo_Builder>();
     aList = aBOPBuilder->Generated(theOldShape->impl<TopoDS_Shape>());
+  } else if(myBuilderType == OCCT_BRepOffset_MakeOffset) {
+    BRepOffset_MakeOffset* aMakeOffset = implPtr<BRepOffset_MakeOffset>();
+    aList = aMakeOffset->Generated(theOldShape->impl<TopoDS_Shape>());
   }
   for(TopTools_ListIteratorOfListOfShape anIt(aList); anIt.More(); anIt.Next()) {
     GeomShapePtr aShape(new GeomAPI_Shape());
@@ -126,6 +130,12 @@ void GeomAlgoAPI_MakeShape::modified(const GeomShapePtr theOldShape,
   } else if(myBuilderType == OCCT_BOPAlgo_Builder) {
     BOPAlgo_Builder* aBOPBuilder = implPtr<BOPAlgo_Builder>();
     aList = aBOPBuilder->Modified(theOldShape->impl<TopoDS_Shape>());
+  } else if(myBuilderType == OCCT_BRepOffset_MakeOffset) {
+    BRepOffset_MakeOffset* aMakeOffset = implPtr<BRepOffset_MakeOffset>();
+    try {
+      aList = aMakeOffset->Modified(theOldShape->impl<TopoDS_Shape>());
+    } catch(Standard_NoSuchObject const&) {
+    }
   }
   for(TopTools_ListIteratorOfListOfShape anIt(aList); anIt.More(); anIt.Next()) {
     GeomShapePtr aShape(new GeomAPI_Shape());
@@ -163,6 +173,9 @@ bool GeomAlgoAPI_MakeShape::isDeleted(const GeomShapePtr theOldShape)
   } else if(myBuilderType == OCCT_BOPAlgo_Builder) {
     BOPAlgo_Builder* aBOPBuilder = implPtr<BOPAlgo_Builder>();
     isDeleted = aBOPBuilder->IsDeleted(theOldShape->impl<TopoDS_Shape>()) == Standard_True;
+  } else if(myBuilderType == OCCT_BRepOffset_MakeOffset) {
+    BRepOffset_MakeOffset* aMakeOffset = implPtr<BRepOffset_MakeOffset>();
+    isDeleted = aMakeOffset->IsDeleted(theOldShape->impl<TopoDS_Shape>()) == Standard_True;
   }
 
   return isDeleted;
@@ -257,6 +270,12 @@ void GeomAlgoAPI_MakeShape::initialize()
       myShape->setImpl(new TopoDS_Shape(implPtr<BOPAlgo_Builder>()->Shape()));
       break;
     }
+    case OCCT_BRepOffset_MakeOffset: {
+      myDone = implPtr<BRepOffset_MakeOffset>()->IsDone() == Standard_True;
+      myShape.reset(new GeomAPI_Shape());
+      myShape->setImpl(new TopoDS_Shape(implPtr<BRepOffset_MakeOffset>()->Shape()));
+      break;
+    }
     default:
       break;
   }
index 7acd2291a925dc869fd94a18fcf6b86688597d1b..29abccfb78f78466264c21913a5b4433ec9a1686 100644 (file)
@@ -38,7 +38,8 @@ public:
   enum BuilderType {
     Unknown,
     OCCT_BRepBuilderAPI_MakeShape,
-    OCCT_BOPAlgo_Builder
+    OCCT_BOPAlgo_Builder,
+    OCCT_BRepOffset_MakeOffset
   };
 
 public:
index 590b37bbc6d4b5980852e1d2a07c747db8e77c25..2d74029e64047c62d291ed7c8ed4ef074b2202f7 100644 (file)
 #include <BRepBuilderAPI_MakeWire.hxx>
 #include <BRepBuilderAPI_MakeFace.hxx>
 
+#include <TopExp_Explorer.hxx>
 #include <TopoDS.hxx>
 #include <TopoDS_Wire.hxx>
 
 GeomAlgoAPI_Offset::GeomAlgoAPI_Offset(const GeomShapePtr& theShape,
-                                       const double theOffsetValue)
+                                       const double        theOffsetValue)
 {
-  build(theShape, theOffsetValue);
+  buildSimple(theShape, theOffsetValue);
 }
 
-void GeomAlgoAPI_Offset::build(const GeomShapePtr& theShape, const double theOffsetValue)
+GeomAlgoAPI_Offset::GeomAlgoAPI_Offset(const GeomShapePtr& theShape,
+                                       const double        theOffsetValue,
+                                       const bool          isPipeJoint)
+{
+  buildByJoin(theShape, theOffsetValue, isPipeJoint);
+}
+
+GeomAlgoAPI_Offset::GeomAlgoAPI_Offset(const GeomShapePtr& theShape,
+                                       const ListOfShape&  theFaces,
+                                       const double        theOffsetValue)
+{
+  buildPartial(theShape, theFaces, theOffsetValue);
+}
+
+GeomAlgoAPI_Offset::GeomAlgoAPI_Offset(const GeomPlanePtr& thePlane,
+                                       const GeomShapePtr& theEdgeOrWire,
+                                       const double theOffsetValue,
+                                       const GeomAlgoAPI_OffsetJoint theJoint,
+                                       const bool theIsApprox)
+{
+  build2d(thePlane, theEdgeOrWire, theOffsetValue, theJoint, theIsApprox);
+}
+
+void GeomAlgoAPI_Offset::generated(const GeomShapePtr theOldShape,
+                                   ListOfShape& theNewShapes)
+{
+  try {
+    GeomAlgoAPI_MakeShape::generated(theOldShape, theNewShapes);
+  } catch(...) {
+    // nothing is generated
+  }
+}
+
+void GeomAlgoAPI_Offset::buildSimple(const GeomShapePtr& theShape,
+                                     const double        theOffsetValue)
 {
   BRepOffsetAPI_MakeOffsetShape* anOffsetAlgo = new BRepOffsetAPI_MakeOffsetShape;
   anOffsetAlgo->PerformBySimple(theShape->impl<TopoDS_Shape>(), theOffsetValue);
@@ -52,21 +87,96 @@ void GeomAlgoAPI_Offset::build(const GeomShapePtr& theShape, const double theOff
   }
 }
 
-void GeomAlgoAPI_Offset::generated(const GeomShapePtr theOldShape,
-                                   ListOfShape& theNewShapes)
+void GeomAlgoAPI_Offset::buildByJoin(const GeomShapePtr& theShape,
+                                     const double        theOffsetValue,
+                                     const bool          isPipeJoint)
 {
-  try {
-    GeomAlgoAPI_MakeShape::generated(theOldShape, theNewShapes);
-  } catch(...) {
-    // nothing is generated
+  Standard_Real aTol = Precision::Confusion();
+  BRepOffset_Mode aMode = BRepOffset_Skin;
+  Standard_Boolean anIntersection = Standard_False;
+  Standard_Boolean aSelfInter = Standard_False;
+
+  BRepOffsetAPI_MakeOffsetShape* anOffsetAlgo = new BRepOffsetAPI_MakeOffsetShape;
+  anOffsetAlgo->PerformByJoin(theShape->impl<TopoDS_Shape>(),
+                              theOffsetValue,
+                              aTol,
+                              aMode,
+                              anIntersection,
+                              aSelfInter,
+                              isPipeJoint ? GeomAbs_Arc : GeomAbs_Intersection);
+  setImpl(anOffsetAlgo);
+  setBuilderType(OCCT_BRepBuilderAPI_MakeShape);
+
+  if (anOffsetAlgo->IsDone()) {
+    const TopoDS_Shape& aResult = anOffsetAlgo->Shape();
+    std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
+    aShape->setImpl(new TopoDS_Shape(aResult));
+    setShape(aShape);
+    setDone(true);
   }
 }
 
-GeomAlgoAPI_Offset::GeomAlgoAPI_Offset(const GeomPlanePtr& thePlane,
-                                       const GeomShapePtr& theEdgeOrWire,
-                                       const double theOffsetValue,
-                                       const GeomAlgoAPI_OffsetJoint theJoint,
-                                       const bool theIsApprox)
+void GeomAlgoAPI_Offset::buildPartial(const GeomShapePtr& theShape,
+                                      const ListOfShape&  theFaces,
+                                      const double        theOffsetValue)
+{
+  if (theFaces.empty())
+    return;
+
+  TopoDS_Shape aShapeBase = theShape->impl<TopoDS_Shape>();
+
+  Standard_Real aTol = Precision::Confusion();
+  BRepOffset_Mode aMode = BRepOffset_Skin;
+  Standard_Boolean anIntersection = Standard_False;
+  Standard_Boolean aSelfInter = Standard_False;
+
+  BRepOffset_MakeOffset* aMakeOffset = new BRepOffset_MakeOffset;
+  aMakeOffset->Initialize(aShapeBase,
+                          theOffsetValue, // set offset on all faces to anOffset
+                          aTol,
+                          aMode,
+                          anIntersection,
+                          aSelfInter,
+                          GeomAbs_Intersection,
+                          Standard_False);
+
+  // put selected faces into a map
+  TopTools_MapOfShape aMapFaces;
+  for (ListOfShape::const_iterator anIt = theFaces.begin();
+       anIt != theFaces.end(); ++anIt) {
+    if ((*anIt)->isFace())
+      aMapFaces.Add((*anIt)->impl<TopoDS_Shape>());
+  }
+
+  // set offset on non-selected faces to zero
+  TopExp_Explorer anExp (aShapeBase, TopAbs_FACE);
+  for (; anExp.More(); anExp.Next()) {
+    const TopoDS_Shape &aFace = anExp.Current();
+    if (!aMapFaces.Contains(aFace)) {
+      aMakeOffset->SetOffsetOnFace(TopoDS::Face(aFace), 0.0);
+    }
+  }
+
+  // perform offset operation
+  aMakeOffset->MakeOffsetShape();
+
+  setImpl(aMakeOffset);
+  setBuilderType(OCCT_BRepOffset_MakeOffset);
+
+  if (aMakeOffset->IsDone()) {
+    const TopoDS_Shape& aResult = aMakeOffset->Shape();
+    std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
+    aShape->setImpl(new TopoDS_Shape(aResult));
+    setShape(aShape);
+    setDone(true);
+  }
+}
+
+void GeomAlgoAPI_Offset::build2d(const GeomPlanePtr& thePlane,
+                                 const GeomShapePtr& theEdgeOrWire,
+                                 const double theOffsetValue,
+                                 const GeomAlgoAPI_OffsetJoint theJoint,
+                                 const bool theIsApprox)
 {
   // 1. Make wire from edge, if need
   TopoDS_Wire aWire;
index 7c58f8e7015efb609ae5b26ef3af0dab971a2f27..5bc01a6b6fce5406e291fc23885c1c0522d10dab 100644 (file)
@@ -41,11 +41,31 @@ enum class GeomAlgoAPI_OffsetJoint { KeepDistance, Arcs, Lines };
 class GeomAlgoAPI_Offset : public GeomAlgoAPI_MakeShape
 {
 public:
-  /// \brief Construct offset.
+  /// \brief Perform simple offset.
+  /// \param[in] theShape base shape
+  /// \param[in] theOffsetValue offset distance, it can be negative
   GEOMALGOAPI_EXPORT GeomAlgoAPI_Offset(const GeomShapePtr& theShape,
                                         const double theOffsetValue);
 
-  /// \brief Perform the offset algorithm on the plane
+  /// \brief Perform 3d offset algorithm
+  /// \param[in] theShape base shape
+  /// \param[in] theOffsetValue offset distance, it can be negative
+  /// \param[in] isPipeJoint type of joint of faces (pipes or intersections)
+  GEOMALGOAPI_EXPORT GeomAlgoAPI_Offset
+    (const GeomShapePtr& theShape,
+     const double        theOffsetValue,
+     const bool          isPipeJoint);
+
+  /// \brief Perform partial 3d offset algorithm
+  /// \param[in] theShape base shape
+  /// \param[in] theFaces list of faces to be offset
+  /// \param[in] theOffsetValue offset distance for selected faces, it can be negative
+  GEOMALGOAPI_EXPORT GeomAlgoAPI_Offset
+    (const GeomShapePtr& theShape,
+     const ListOfShape&  theFaces,
+     const double        theOffsetValue);
+
+  /// \brief Perform 2d offset algorithm on the plane
   /// \param[in] thePlane base plane for all offsets
   /// \param[in] theEdgesOrWire base shapes
   /// \param[in] theOffsetValue offset distance, it can be negative
@@ -63,10 +83,27 @@ public:
   GEOMALGOAPI_EXPORT virtual void generated(const GeomShapePtr theOldShape,
                                             ListOfShape& theNewShapes);
 
-
 private:
-  /// \brief Perform offset operation
-  void build(const GeomShapePtr& theShape, const double theOffsetValue);
+  /// \brief Perform simple offset operation
+  void buildSimple(const GeomShapePtr& theShape,
+                   const double        theOffsetValue);
+
+  /// \brief Perform 3d offset algorithm by join
+  void buildByJoin(const GeomShapePtr& theShape,
+                   const double        theOffsetValue,
+                   const bool          isPipeJoint);
+
+  /// \brief Perform partial 3d offset algorithm
+  void buildPartial(const GeomShapePtr& theShape,
+                    const ListOfShape&  theFaces,
+                    const double        theOffsetValue);
+
+  /// \brief Perform 2d offset algorithm on the plane
+  void build2d(const std::shared_ptr<GeomAPI_Pln>& thePlane,
+               const GeomShapePtr& theEdgeOrWire,
+               const double theOffsetValue,
+               const GeomAlgoAPI_OffsetJoint theJoint = GeomAlgoAPI_OffsetJoint::KeepDistance,
+               const bool theIsApprox = false);
 };
 
 #endif
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Thickness.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Thickness.cpp
new file mode 100644 (file)
index 0000000..179a5b8
--- /dev/null
@@ -0,0 +1,273 @@
+// Copyright (C) 2019-2024  CEA, EDF
+//
+// 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_Thickness.h"
+
+#include <GeomAPI_Pln.h>
+
+#include <BRepClass3d_SolidClassifier.hxx>
+#include <BRepOffsetAPI_MakeThickSolid.hxx>
+#include <BRepOffset_MakeOffset.hxx>
+
+#include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
+#include <TopTools_MapOfShape.hxx>
+
+static GeomShapePtr convert(const TopoDS_Shape& theShape)
+{
+  GeomShapePtr aNewShape(new GeomAPI_Shape);
+  aNewShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(theShape));
+  return aNewShape;
+}
+
+GeomAlgoAPI_Thickness::GeomAlgoAPI_Thickness(const GeomShapePtr& theShape,
+                                             const double        theThickness,
+                                             const bool          isInside)
+{
+  buildThickening(theShape, theThickness, isInside);
+}
+
+GeomAlgoAPI_Thickness::GeomAlgoAPI_Thickness(const GeomShapePtr& theShape,
+                                             const ListOfShape&  theFaces,
+                                             const double        theThickness,
+                                             const bool          isInside)
+{
+  buildHollowedSolid(theShape, theFaces, theThickness, isInside);
+}
+
+void GeomAlgoAPI_Thickness::generated(const GeomShapePtr theOldShape,
+                                      ListOfShape& theNewShapes)
+{
+  GeomAlgoAPI_MakeShape::generated(theOldShape, theNewShapes);
+
+  MapModified::iterator aFound = myGenerated.find(theOldShape);
+  if (aFound != myGenerated.end())
+    theNewShapes.insert(theNewShapes.end(),
+                        aFound->second.begin(), aFound->second.end());
+}
+
+void GeomAlgoAPI_Thickness::buildThickening(const GeomShapePtr& theShape,
+                                            const double        theThickness,
+                                            const bool          isInside)
+{
+  Standard_Real aTol = Precision::Confusion();
+  if (theThickness < aTol) {
+    myError = "The thickness value is Too small or negative";
+    return;
+  }
+
+  Standard_Real anOffset = theThickness;
+  if (isInside)
+    anOffset = -anOffset;
+
+  const TopoDS_Shape& aShapeBase = theShape->impl<TopoDS_Shape>();
+  const TopAbs_ShapeEnum aType = aShapeBase.ShapeType();
+
+  if (aType != TopAbs_FACE && aType != TopAbs_SHELL) {
+    myError = "The base shape for thickening should be a face or a shell";
+    return;
+  }
+
+  BRepClass3d_SolidClassifier aClassifier(aShapeBase);
+  aClassifier.PerformInfinitePoint(Precision::Confusion());
+  if (aClassifier.State()==TopAbs_IN) {
+    // If the generated pipe faces normals are oriented towards the inside,
+    // the offset is negative, so that the thickening is still towards outside
+    anOffset = -anOffset;
+  }
+
+  Standard_Boolean anIntersection = Standard_False;
+  Standard_Boolean aSelfInter = Standard_False;
+  Standard_Boolean isThickening = Standard_True;
+
+  BRepOffset_MakeOffset* aMakeOffset =
+    new BRepOffset_MakeOffset(aShapeBase,
+                              anOffset,
+                              aTol,
+                              BRepOffset_Skin,
+                              anIntersection,
+                              aSelfInter,
+                              GeomAbs_Intersection,
+                              isThickening);
+
+  setImpl(aMakeOffset);
+  setBuilderType(OCCT_BRepOffset_MakeOffset);
+
+  if (aMakeOffset->IsDone()) {
+    TopoDS_Shape aResult = aMakeOffset->Shape();
+
+    // Control the solid orientation. This is mostly done to fix a bug in case
+    // of extrusion of a circle. The built solid is then badly oriented.
+    BRepClass3d_SolidClassifier anotherClassifier(aResult);
+    anotherClassifier.PerformInfinitePoint(Precision::Confusion());
+    if (anotherClassifier.State() == TopAbs_IN) {
+      aResult.Reverse();
+    }
+
+    std::shared_ptr<GeomAPI_Shape> aShape (new GeomAPI_Shape());
+    aShape->setImpl(new TopoDS_Shape(aResult));
+    setShape(aShape);
+    setDone(true);
+
+    // History for ThickShell is incomplete (OCCT bug 33844)
+    // Here we try to add generated walls (FACE from EDGE or VERTEX)
+
+    // 1. Gather all generated/modified/initial faces in a map
+    //    (for that faces we don't need to adjust history).
+    //    Collect also edges and vertices of initial shape in a separate map.
+    TopTools_MapOfShape aFacesMap;
+    TopTools_MapOfShape anInitialMap;
+    TopTools_ListOfShape aList, aListTmp;
+    {
+      TopExp_Explorer anExp (aShapeBase, TopAbs_FACE);
+      for (; anExp.More(); anExp.Next()) {
+        TopoDS_Shape aFace = anExp.Current();
+        aList.Append(aFace);
+
+        aListTmp = aMakeOffset->Modified(aFace);
+        aList.Append(aListTmp);
+        aListTmp = aMakeOffset->Generated(aFace);
+        aList.Append(aListTmp);
+      }
+    }
+    {
+      TopExp_Explorer anExp (aShapeBase, TopAbs_EDGE);
+      for (; anExp.More(); anExp.Next()) {
+        TopoDS_Shape anEdge = anExp.Current();
+        anInitialMap.Add(anEdge);
+
+        aListTmp = aMakeOffset->Modified(anEdge);
+        aList.Append(aListTmp);
+        aListTmp = aMakeOffset->Generated(anEdge);
+        aList.Append(aListTmp);
+      }
+    }
+    {
+      TopExp_Explorer anExp (aShapeBase, TopAbs_VERTEX);
+      for (; anExp.More(); anExp.Next()) {
+        TopoDS_Shape aVertex = anExp.Current();
+        anInitialMap.Add(aVertex);
+
+        aListTmp = aMakeOffset->Modified(aVertex);
+        aList.Append(aListTmp);
+        aListTmp = aMakeOffset->Generated(aVertex);
+        aList.Append(aListTmp);
+      }
+    }
+    TopTools_ListIteratorOfListOfShape anIt (aList);
+    for (; anIt.More(); anIt.Next()) {
+      TopoDS_Shape aSh = anIt.Value();
+      if (aSh.ShapeType() == TopAbs_FACE) {
+        aFacesMap.Add(aSh);
+      }
+    }
+
+    // 2. Explode result shape into faces, try to construct new
+    //    history for the faces, that are not in the map.
+    TopExp_Explorer anExp (aResult, TopAbs_FACE);
+    for (; anExp.More(); anExp.Next()) {
+      TopoDS_Shape aFace = anExp.Current();
+      if (!aFacesMap.Contains(aFace)) {
+        bool isFound = false;
+        // a. Try to find initial edge in this face
+        TopExp_Explorer anExpE (aFace, TopAbs_EDGE);
+        for (; anExpE.More() && !isFound; anExpE.Next()) {
+          TopoDS_Shape anEdge = anExpE.Current();
+          if (anInitialMap.Contains(anEdge)) {
+            myGenerated[convert(anEdge)].push_back(convert(aFace));
+            isFound = true;
+          }
+        }
+        if (!isFound) {
+          // b. Try to find initial vertex in this face
+          TopExp_Explorer anExpV (aFace, TopAbs_VERTEX);
+          for (; anExpV.More() && !isFound; anExpV.Next()) {
+            TopoDS_Shape aVertex = anExpV.Current();
+            if (anInitialMap.Contains(aVertex)) {
+              myGenerated[convert(aVertex)].push_back(convert(aFace));
+              isFound = true;
+            }
+          }
+        }
+      }
+    }
+    // END: history adjustment
+  }
+}
+
+void GeomAlgoAPI_Thickness::buildHollowedSolid(const GeomShapePtr& theShape,
+                                               const ListOfShape&  theFaces,
+                                               const double        theThickness,
+                                               const bool          isInside)
+{
+  if (theFaces.empty())
+    return;
+
+  Standard_Real aTol = Precision::Confusion();
+  if (theThickness < aTol) {
+    myError = "The thickness value is Too small or negative";
+    return;
+  }
+
+  Standard_Real anOffset = theThickness;
+  if (isInside)
+    anOffset = -anOffset;
+
+  //TopoDS_Shape aShapeBase = theShape->impl<TopoDS_Shape>();
+  const TopoDS_Shape& aShapeBase = theShape->impl<TopoDS_Shape>();
+  const TopAbs_ShapeEnum aType = aShapeBase.ShapeType();
+
+  if (aType != TopAbs_SOLID) {
+    myError = "The base shape for hollowed solid creation should be a solid";
+    return;
+  }
+
+  // put selected faces into a list
+  TopTools_ListOfShape aFacesToRm;
+  for (ListOfShape::const_iterator anIt = theFaces.begin();
+       anIt != theFaces.end(); ++anIt) {
+    if ((*anIt)->isFace())
+      aFacesToRm.Append((*anIt)->impl<TopoDS_Shape>());
+  }
+
+  Standard_Boolean anIntersection = Standard_False;
+  Standard_Boolean aSelfInter = Standard_False;
+
+  // Create a hollowed solid.
+  BRepOffsetAPI_MakeThickSolid* aMkSolid = new BRepOffsetAPI_MakeThickSolid();
+  aMkSolid->MakeThickSolidByJoin(aShapeBase,
+                                 aFacesToRm,
+                                 anOffset,
+                                 aTol,
+                                 BRepOffset_Skin,
+                                 anIntersection,
+                                 aSelfInter,
+                                 GeomAbs_Intersection);
+
+  setImpl(aMkSolid);
+  setBuilderType(OCCT_BRepBuilderAPI_MakeShape);
+
+  if (aMkSolid->IsDone()) {
+    const TopoDS_Shape& aResult = aMkSolid->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_Thickness.h b/src/GeomAlgoAPI/GeomAlgoAPI_Thickness.h
new file mode 100644 (file)
index 0000000..dcd304e
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright (C) 2019-2024  CEA, EDF
+//
+// 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_Thickness_H_
+#define GeomAlgoAPI_Thickness_H_
+
+#include <GeomAlgoAPI.h>
+#include <GeomAlgoAPI_MakeShape.h>
+
+/// \class GeomAlgoAPI_Thickness
+/// \ingroup DataAlgo
+/// \brief Perform Thickness or Hollowed Solid algorithm for the shape
+class GeomAlgoAPI_Thickness : public GeomAlgoAPI_MakeShape
+{
+  typedef std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator> MapModified;
+
+public:
+  /// \brief Perform thickening algorithm
+  /// \param[in] theShape base shape (Face or Shell)
+  /// \param[in] theThickness thickness of the resulting solid
+  /// \param[in] isInside if true, the thickness is applied towards inside
+  GEOMALGOAPI_EXPORT GeomAlgoAPI_Thickness
+    (const GeomShapePtr& theShape,
+     const double        theThickness,
+     const bool          isInside);
+
+  /// \brief Perform hollowed solid algorithm
+  /// \param[in] theShape base shape (Solid)
+  /// \param[in] theFaces the list of faces to be removed from the result
+  /// \param[in] theThickness thickness of the resulting solid
+  /// \param[in] isInside if true, the thickness is applied towards inside
+  GEOMALGOAPI_EXPORT GeomAlgoAPI_Thickness
+    (const GeomShapePtr& theShape,
+     const ListOfShape&  theFaces,
+     const double        theThickness,
+     const bool          isInside);
+
+  /// \return the list of shapes generated from the shape \a theShape.
+  /// \param[in] theOldShape base shape.
+  /// \param[out] theNewShapes shapes generated from \a theShape. Does not cleared!
+  GEOMALGOAPI_EXPORT virtual void generated(const GeomShapePtr theOldShape,
+                                            ListOfShape& theNewShapes);
+
+private:
+  /// \brief Perform thickening algorithm
+  void buildThickening(const GeomShapePtr& theShape,
+                       const double        theThickness,
+                       const bool          isInside);
+
+  /// \brief Perform hollowed solid algorithm
+  void buildHollowedSolid(const GeomShapePtr& theShape,
+                          const ListOfShape&  theFaces,
+                          const double        theThickness,
+                          const bool          isInside);
+
+private:
+  MapModified myGenerated;
+};
+
+#endif
index ba9b2542c43e940f2f0e1679dddc338db82b026a..c591bfc1485f3d686990f5e9034847de873cae59 100644 (file)
@@ -24,6 +24,7 @@ from FeaturesAPI import addMultiTranslation, addMultiRotation
 from FeaturesAPI import addExtrusion, addExtrusionCut, addExtrusionFuse
 from FeaturesAPI import addRevolution, addRevolutionCut, addRevolutionFuse
 from FeaturesAPI import addPipe, addLoft
+from FeaturesAPI import addOffset, addOffsetPartial, addThickness, addHollowedSolid
 from FeaturesAPI import addCut, addFuse, addCommon, addSmash, addSplit
 from FeaturesAPI import addIntersection, addPartition, addUnion, addRemoveSubShapes
 from FeaturesAPI import addRecover
index ed2f9f047d06deb87403fcd8c27dfe58710719be..14dc236c489fbc85934958104b9428414f199033 100644 (file)
     <parameter name="Features/Intersection" value=""/>
     <parameter name="Features/LimitTolerance" value=""/>
     <parameter name="Features/Loft" value=""/>
+    <parameter name="Features/Offset3d" value=""/>
     <parameter name="Features/Partition" value=""/>
     <parameter name="Features/Pipe" value=""/>
     <parameter name="Features/Recover" value=""/>
     <parameter name="Features/SketchCopy" value=""/>
     <parameter name="Features/Smash" value=""/>
     <parameter name="Features/Split" value=""/>
+    <parameter name="Features/Thickness" value=""/>
     <parameter name="File/Export/Part" value=""/>
     <parameter name="File/Export/PartSet" value=""/>
     <parameter name="File/Export/Shape" value=""/>
index e2cd0c86933cd68ef0ea70fba24a65a676a606be..efe8875298f74830a70489a50d975cc839b978fe 100644 (file)
                             }
                         }
                     },
+                    "Offset3d": {
+                        "iconPath": "%SHAPER_ROOT_DIR%/share/salome/resources/shaper/icons/Features/offset3D.png",
+                        "langDependentAssets": {
+                            "en": {
+                                "name": "Offset (3D)",
+                                "tooltip": "Offset face or shell"
+                            },
+                            "fr": {
+                                "name": "Offset (3D)",
+                                "tooltip": "Face ou coque décalée"
+                            }
+                        }
+                    },
                     "Partition": {
                         "iconPath": "%SHAPER_ROOT_DIR%/share/salome/resources/shaper/icons/Features/partition.png",
                         "langDependentAssets": {
                                 "tooltip": "Effectuer l'opération booléenne division avec des objets"
                             }
                         }
+                    },
+                    "Thickness": {
+                        "iconPath": "%SHAPER_ROOT_DIR%/share/salome/resources/shaper/icons/Features/thickness.png",
+                        "langDependentAssets": {
+                            "en": {
+                                "name": "Thickness (3D)",
+                                "tooltip": "Thicken faces"
+                            },
+                            "fr": {
+                                "name": "Thickness (3D)",
+                                "tooltip": "Épaissir les visages"
+                            }
+                        }
                     }
                 }
             },
index 9e7d3667dc334dbda8eaa350085938bf0f27e21d..65b12733f45774dbac032f9140d765b707cb30ee 100644 (file)
@@ -18,7 +18,7 @@
 #
 
 """
-    TestOffset.py
+    TestOffset1.py
     Unit test of SketchPlugin_Offset class
 
     SketchPlugin_Offset