]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
CEA - Lot3 : Add LOFT Feature
authorlucasjerome <jerome.lucas@cegsenslab.fr>
Wed, 27 Jan 2021 18:38:10 +0000 (19:38 +0100)
committerNicolas Rechatin <nicolas.rechatin@cea.fr>
Tue, 30 Aug 2022 07:52:43 +0000 (09:52 +0200)
28 files changed:
src/FeaturesAPI/CMakeLists.txt
src/FeaturesAPI/FeaturesAPI.i
src/FeaturesAPI/FeaturesAPI_Loft.cpp [new file with mode: 0644]
src/FeaturesAPI/FeaturesAPI_Loft.h [new file with mode: 0644]
src/FeaturesAPI/FeaturesAPI_swig.h
src/FeaturesPlugin/CMakeLists.txt
src/FeaturesPlugin/FeaturesPlugin_Loft.cpp [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_Loft.h [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.h
src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts
src/FeaturesPlugin/Test/TestLoft.py [new file with mode: 0644]
src/FeaturesPlugin/doc/FeaturesPlugin.rst
src/FeaturesPlugin/doc/TUI_loftFeature.rst [new file with mode: 0644]
src/FeaturesPlugin/doc/examples/loft.py [new file with mode: 0644]
src/FeaturesPlugin/doc/images/loft.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/loftPropertyPanel.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/resultLoft.png [new file with mode: 0644]
src/FeaturesPlugin/doc/loftFeature.rst [new file with mode: 0644]
src/FeaturesPlugin/icons/loft.png [new file with mode: 0644]
src/FeaturesPlugin/loft_widget.xml [new file with mode: 0644]
src/FeaturesPlugin/plugin-Features.xml
src/FeaturesPlugin/tests.set
src/GeomAlgoAPI/CMakeLists.txt
src/GeomAlgoAPI/GeomAlgoAPI_Loft.cpp [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_Loft.h [new file with mode: 0644]
src/PythonAPI/model/features/__init__.py

index 2d641033f9cfc898b4ac8fe351e9e86373d8c82d..2400977869e8e6749063b0bcbbad7ef822263a44 100644 (file)
@@ -37,6 +37,7 @@ SET(PROJECT_HEADERS
   FeaturesAPI_MultiTranslation.h
   FeaturesAPI_Partition.h
   FeaturesAPI_Pipe.h
+  FeaturesAPI_Loft.h
   FeaturesAPI_Placement.h
   FeaturesAPI_Recover.h
   FeaturesAPI_RemoveResults.h
@@ -74,6 +75,7 @@ SET(PROJECT_SOURCES
   FeaturesAPI_MultiTranslation.cpp
   FeaturesAPI_Partition.cpp
   FeaturesAPI_Pipe.cpp
+  FeaturesAPI_Loft.cpp
   FeaturesAPI_Placement.cpp
   FeaturesAPI_Recover.cpp
   FeaturesAPI_RemoveResults.cpp
index d2b6dbfce82eedcc949596c188641f34ae35bf0f..75b33fb2216d55b9f235c69aafdbde18bb0bd55c 100644 (file)
@@ -76,6 +76,7 @@
 %shared_ptr(FeaturesAPI_MultiTranslation)
 %shared_ptr(FeaturesAPI_Partition)
 %shared_ptr(FeaturesAPI_Pipe)
+%shared_ptr(FeaturesAPI_Loft)
 %shared_ptr(FeaturesAPI_Placement)
 %shared_ptr(FeaturesAPI_Recover)
 %shared_ptr(FeaturesAPI_RemoveSubShapes)
 %include "FeaturesAPI_MultiTranslation.h"
 %include "FeaturesAPI_Partition.h"
 %include "FeaturesAPI_Pipe.h"
+%include "FeaturesAPI_Loft.h"
 %include "FeaturesAPI_Placement.h"
 %include "FeaturesAPI_Recover.h"
 %include "FeaturesAPI_RemoveSubShapes.h"
diff --git a/src/FeaturesAPI/FeaturesAPI_Loft.cpp b/src/FeaturesAPI/FeaturesAPI_Loft.cpp
new file mode 100644 (file)
index 0000000..ad21aa5
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright (C) 2014-2022  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "FeaturesAPI_Loft.h"
+
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Tools.h>
+
+//==================================================================================================
+FeaturesAPI_Loft::FeaturesAPI_Loft(const std::shared_ptr<ModelAPI_Feature>& theFeature)
+: ModelHighAPI_Interface(theFeature)
+{
+  initialize();
+}
+
+//==================================================================================================
+FeaturesAPI_Loft::FeaturesAPI_Loft(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                   const ModelHighAPI_Selection& theFirstObject,
+                                   const ModelHighAPI_Selection& theSecondObject)
+: ModelHighAPI_Interface(theFeature)
+{
+  if(initialize()) {
+    fillAttribute(theFirstObject, myfisrstObject);
+    fillAttribute(theSecondObject, mysecondObject);
+    execute();
+  }
+}
+
+//==================================================================================================
+FeaturesAPI_Loft::~FeaturesAPI_Loft()
+{
+
+}
+
+//==================================================================================================
+void FeaturesAPI_Loft::dump(ModelHighAPI_Dumper& theDumper) const
+{
+  FeaturePtr aBase = feature();
+  const std::string& aDocName = theDumper.name(aBase->document());
+
+  AttributeSelectionPtr anAttrFirstObject =
+                                    aBase->selection(FeaturesPlugin_Loft::FIRST_OBJECT_ID());
+  AttributeSelectionPtr anAttrSecondObject =
+                                    aBase->selection(FeaturesPlugin_Loft::SECOND_OBJECT_ID());
+
+  theDumper << aBase << " = model.addLoft(" << aDocName << ", "
+            << anAttrFirstObject << ", " << anAttrSecondObject;
+
+  theDumper << ")" << std::endl;
+}
+
+//==================================================================================================
+LoftPtr addLoft(const std::shared_ptr<ModelAPI_Document>& thePart,
+                const ModelHighAPI_Selection& theFirstObject,
+                const ModelHighAPI_Selection& theSecondObject)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_Loft::ID());
+
+  return LoftPtr(new FeaturesAPI_Loft(aFeature, theFirstObject, theSecondObject));
+}
+
diff --git a/src/FeaturesAPI/FeaturesAPI_Loft.h b/src/FeaturesAPI/FeaturesAPI_Loft.h
new file mode 100644 (file)
index 0000000..aabe0dc
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright (C) 2014-2022  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef FeaturesAPI_Loft_H_
+#define FeaturesAPI_Loft_H_
+
+#include "FeaturesAPI.h"
+
+#include <FeaturesPlugin_Loft.h>
+
+#include <ModelHighAPI_Interface.h>
+#include <ModelHighAPI_Macro.h>
+
+class ModelHighAPI_Dumper;
+class ModelHighAPI_Selection;
+
+/// \class FeaturesAPI_Loft
+/// \ingroup CPPHighAPI
+/// \brief Interface for Loft feature.
+class FeaturesAPI_Loft: public ModelHighAPI_Interface
+{
+public:
+  /// Constructor without values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_Loft(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+  /// Constructor with values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_Loft(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                            const ModelHighAPI_Selection& theFirstObject,
+                            const ModelHighAPI_Selection& theSecondObject);
+
+  /// Destructor.
+  FEATURESAPI_EXPORT
+  virtual ~FeaturesAPI_Loft();
+
+  INTERFACE_2(FeaturesPlugin_Loft::ID(),
+              fisrstObject, FeaturesPlugin_Loft::FIRST_OBJECT_ID(),
+              ModelAPI_AttributeSelection, /** First object */,
+              secondObject, FeaturesPlugin_Loft::SECOND_OBJECT_ID(),
+              ModelAPI_AttributeSelection, /** second objexct */)
+
+  /// Dump wrapped feature
+  FEATURESAPI_EXPORT
+  virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+};
+
+/// Pointer on Loft object.
+typedef std::shared_ptr<FeaturesAPI_Loft> LoftPtr;
+
+/// \ingroup CPPHighAPI
+/// \brief Create Loft feature.
+FEATURESAPI_EXPORT
+LoftPtr addLoft(const std::shared_ptr<ModelAPI_Document>& thePart,
+                const ModelHighAPI_Selection& theFirstObject,
+                const ModelHighAPI_Selection& theSecondObject);
+
+#endif // FeaturesAPI_Loft_H_
index 066aa098f53a3d4d562b1f052ef9b943f5196ca8..32e9e24fe2deba7945f0a7756726782f60eb599c 100644 (file)
@@ -40,6 +40,7 @@
   #include "FeaturesAPI_MultiTranslation.h"
   #include "FeaturesAPI_Partition.h"
   #include "FeaturesAPI_Pipe.h"
+  #include "FeaturesAPI_Loft.h"
   #include "FeaturesAPI_Placement.h"
   #include "FeaturesAPI_Recover.h"
   #include "FeaturesAPI_RemoveSubShapes.h"
index 1d031c8ce0cabdbb9f24d20fd516b71ad9610921..b4a9907c56d7dacf97b2f22ff7b77c79fd30d673 100644 (file)
@@ -39,6 +39,7 @@ SET(PROJECT_HEADERS
     FeaturesPlugin_Intersection.h
     FeaturesPlugin_Partition.h
     FeaturesPlugin_Pipe.h
+    FeaturesPlugin_Loft.h
     FeaturesPlugin_Placement.h
     FeaturesPlugin_CompositeBoolean.h
     FeaturesPlugin_CompositeSketch.h
@@ -93,6 +94,7 @@ SET(PROJECT_SOURCES
     FeaturesPlugin_Intersection.cpp
     FeaturesPlugin_Partition.cpp
     FeaturesPlugin_Pipe.cpp
+    FeaturesPlugin_Loft.cpp
     FeaturesPlugin_Placement.cpp
     FeaturesPlugin_CompositeBoolean.cpp
     FeaturesPlugin_CompositeSketch.cpp
@@ -150,6 +152,7 @@ SET(XML_RESOURCES
   placement_widget.xml
   intersection_widget.xml
   pipe_widget.xml
+  loft_widget.xml
   remove_subshapes_widget.xml
   union_widget.xml
   symmetry_widget.xml
@@ -221,16 +224,16 @@ ADD_UNIT_TESTS(
 IF(${HAVE_SALOME})
   enable_testing()
   set(TEST_INSTALL_DIRECTORY "${SALOME_SHAPER_INSTALL_TESTS}/FeaturesPlugin")
-  
+
   install(FILES CTestTestfileInstall.cmake
   DESTINATION ${TEST_INSTALL_DIRECTORY}
   RENAME CTestTestfile.cmake)
   install(FILES tests.set DESTINATION ${TEST_INSTALL_DIRECTORY})
-  
+
   set(TMP_TESTS_NAMES)
   foreach(tfile ${TEST_NAMES})
     list(APPEND TMP_TESTS_NAMES "Test/${tfile}")
   endforeach(tfile ${TEST_NAMES})
-  
+
   install(FILES ${TMP_TESTS_NAMES} DESTINATION ${TEST_INSTALL_DIRECTORY})
 ENDIF(${HAVE_SALOME})
diff --git a/src/FeaturesPlugin/FeaturesPlugin_Loft.cpp b/src/FeaturesPlugin/FeaturesPlugin_Loft.cpp
new file mode 100644 (file)
index 0000000..48722db
--- /dev/null
@@ -0,0 +1,185 @@
+// Copyright (C) 2014-2022  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "FeaturesPlugin_Loft.h"
+#include "FeaturesPlugin_Tools.h"
+
+#include <ModelAPI_AttributeSelection.h>
+
+#include <GeomAlgoAPI_Copy.h>
+#include <GeomAlgoAPI_Filling.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+#include <GeomAlgoAPI_Tools.h>
+#include <GeomAPI_Pnt.h>
+#include <GeomAPI_ShapeExplorer.h>
+
+#include <cmath>
+
+//==================================================================================================
+FeaturesPlugin_Loft::FeaturesPlugin_Loft()
+{
+}
+
+//==================================================================================================
+void FeaturesPlugin_Loft::initAttributes()
+{
+  data()->addAttribute(FIRST_OBJECT_ID(), ModelAPI_AttributeSelection::typeId());
+  data()->addAttribute(SECOND_OBJECT_ID(), ModelAPI_AttributeSelection::typeId());
+}
+
+//==================================================================================================
+void FeaturesPlugin_Loft::execute()
+{
+  AttributeSelectionPtr aFirstSelection = selection(FIRST_OBJECT_ID());
+  AttributeSelectionPtr aSecondelection = selection(SECOND_OBJECT_ID());
+
+  if (aFirstSelection->isInitialized() && aSecondelection->isInitialized()) {
+
+    GeomShapePtr aFirstShape, aSecondShape;
+
+    if (aFirstSelection && aSecondelection) {
+      aFirstShape = aFirstSelection->value();
+      if (!aFirstShape && aFirstSelection->context())
+        aFirstShape = aFirstSelection->context()->shape();
+
+      aSecondShape = aSecondelection->value();
+      if (!aSecondShape && aSecondelection->context())
+        aSecondShape = aSecondelection->context()->shape();
+
+    }
+    // Loft for two edges
+    if(aFirstShape->isEdge()) {
+
+      std::shared_ptr<GeomAlgoAPI_Filling> aFilling(
+                          new GeomAlgoAPI_Filling(2.0, 5.0, 0, 0.0001, 0.0001 ));
+
+      // collect base shapes
+      GeomEdgePtr aFirstEdge = toEdge(aFirstShape);
+      if (!aFirstEdge) {
+        myLastEdgeStartPoint = GeomPointPtr();
+        myLastEdgeEndPoint = GeomPointPtr();
+        return;
+      }
+      aFilling->add(aFirstEdge);
+
+      GeomEdgePtr aSecondEdge = toEdge(aSecondShape);
+      if (!aSecondEdge) {
+        myLastEdgeStartPoint = GeomPointPtr();
+        myLastEdgeEndPoint = GeomPointPtr();
+        return;
+      }
+      aFilling->add(aSecondEdge);
+      myLastEdgeStartPoint = GeomPointPtr();
+      myLastEdgeEndPoint = GeomPointPtr();
+
+      // build result
+      aFilling->build();
+      std::string anError;
+      if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aFilling, getKind(), anError)) {
+        setError(anError);
+        removeResults(0);
+        return;
+      }
+
+      /// store result
+      GeomShapePtr aCreatedFace = aFilling->shape();
+      ResultBodyPtr aResultBody = document()->createBody(data());
+      aResultBody->store(aCreatedFace);
+      // store edges
+      for(GeomAPI_ShapeExplorer anExp(aCreatedFace, GeomAPI_Shape::EDGE);
+                                anExp.more(); anExp.next()) {
+        GeomShapePtr anEdge = anExp.current();
+        aResultBody->generated(anEdge, "Loft_Edge");
+      }
+      setResult(aResultBody, 0);
+
+    } else {
+
+      std::shared_ptr<GeomAlgoAPI_Loft> aLoftAlgo(new GeomAlgoAPI_Loft(aFirstShape, aSecondShape));
+
+      std::string anError;
+
+      if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aLoftAlgo, getKind(), anError)) {
+        setError(anError);
+        return;
+      }
+      ListOfShape  theBoundaryShapes;
+      theBoundaryShapes.push_back(aFirstShape);
+      theBoundaryShapes.push_back(aSecondShape);
+
+      // Create result body.
+      ResultBodyPtr aResultBody = document()->createBody(data());
+
+      aResultBody->store(aLoftAlgo->shape());
+      // store Faces
+      for(GeomAPI_ShapeExplorer anExp(aLoftAlgo->shape(), GeomAPI_Shape::FACE);
+                                anExp.more(); anExp.next()) {
+        GeomShapePtr anEdge = anExp.current();
+        aResultBody->generated(anEdge, "Loft_Face");
+      }
+      setResult(aResultBody, 0);
+    }
+  }
+}
+
+//=================================================================================================
+GeomEdgePtr FeaturesPlugin_Loft::toEdge(const GeomShapePtr& theShape)
+{
+  GeomEdgePtr anEdge = GeomEdgePtr(new GeomAPI_Edge(GeomAlgoAPI_Copy(theShape).shape()));
+
+  if (!anEdge || anEdge->empty()) {
+    static const std::string aFeatureError =
+        "Error: incorrect type of input feature (edges are supported only).";
+    setError(aFeatureError);
+    return anEdge;
+  }
+
+  // correct edge orientation according to filling method
+  // check the distance to previous edge boundaries, reverse edge if necessary
+  GeomPointPtr aStartPnt = anEdge->firstPoint();
+  GeomPointPtr aEndPnt = anEdge->lastPoint();
+  if (anEdge->orientation() == GeomAPI_Shape::REVERSED) {
+    aStartPnt = anEdge->lastPoint();
+    aEndPnt = anEdge->firstPoint();
+  }
+  bool isReverse = false;
+  if (myLastEdgeStartPoint) {
+    double d1 = myLastEdgeStartPoint->distance(aStartPnt)
+              + myLastEdgeEndPoint->distance(aEndPnt);
+    double d2 = myLastEdgeStartPoint->distance(aEndPnt)
+              + myLastEdgeEndPoint->distance(aStartPnt);
+    if (fabs(d1 - d2) < 1.e-7) {
+      // undefined case => check distance to start point only
+      d1 = myLastEdgeStartPoint->distance(aStartPnt);
+      d2 = myLastEdgeStartPoint->distance(aEndPnt);
+    }
+    isReverse = d2 < d1;
+  }
+
+  if (isReverse) {
+    anEdge->reverse();
+    myLastEdgeStartPoint = aEndPnt;
+    myLastEdgeEndPoint = aStartPnt;
+  } else {
+    myLastEdgeStartPoint = aStartPnt;
+    myLastEdgeEndPoint = aEndPnt;
+  }
+
+  return anEdge;
+}
diff --git a/src/FeaturesPlugin/FeaturesPlugin_Loft.h b/src/FeaturesPlugin/FeaturesPlugin_Loft.h
new file mode 100644 (file)
index 0000000..4ca8cb3
--- /dev/null
@@ -0,0 +1,90 @@
+// Copyright (C) 2014-2022  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef FeaturesPlugin_Loft_H_
+#define FeaturesPlugin_Loft_H_
+
+#include "FeaturesPlugin.h"
+
+#include <GeomAlgoAPI_Loft.h>
+
+#include <ModelAPI_Feature.h>
+#include <ModelAPI_ResultBody.h>
+
+class GeomAPI_Pnt;
+
+/// \class FeaturesPlugin_Loft
+/// \ingroup Plugins
+/// \brief Feature for creation of extrusion along a path.
+/// Pipe creates extrusion of objects along a path.
+/// It produces the following results from objects:
+/// Vertex -> Edge
+/// Edge -> Face
+/// Wire -> Shell
+/// Face -> Solid
+class FeaturesPlugin_Loft : public ModelAPI_Feature
+{
+public:
+  /// Feature kind.
+  inline static const std::string& ID()
+  {
+    static const std::string MY_FEATURE_ID("Loft");
+    return MY_FEATURE_ID;
+  }
+
+  /// Attribute name for first object selected.
+  inline static const std::string& FIRST_OBJECT_ID()
+  {
+    static const std::string MY_FIRST_OBJECT("first_object");
+    return MY_FIRST_OBJECT;
+  }
+
+  /// Attribute name for second object selected.
+  inline static const std::string& SECOND_OBJECT_ID()
+  {
+    static const std::string MY_SECOND_OBJECT("second_object");
+    return MY_SECOND_OBJECT;
+  }
+
+  /// \return the kind of a feature.
+  FEATURESPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = FeaturesPlugin_Loft::ID();
+    return MY_KIND;
+  }
+
+  /// Performs the algorithm and stores results it in the data structure.
+  FEATURESPLUGIN_EXPORT virtual void execute();
+
+  /// Request for initialization of data model of the feature: adding all attributes
+  FEATURESPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Use plugin manager for features creation
+  FeaturesPlugin_Loft();
+
+  private:
+  /// Convert shape to edge
+  std::shared_ptr<GeomAPI_Edge> toEdge(const std::shared_ptr<GeomAPI_Shape>& theShape);
+
+  private:
+  std::shared_ptr<GeomAPI_Pnt> myLastEdgeStartPoint;
+  std::shared_ptr<GeomAPI_Pnt> myLastEdgeEndPoint;
+};
+
+#endif
index 795bc77b51be6f05123c6d623600672985bc882f..ead520eb9c62267c814264a73c5ba9264464e258 100644 (file)
@@ -43,6 +43,7 @@
 #include <FeaturesPlugin_NormalToFace.h>
 #include <FeaturesPlugin_Partition.h>
 #include <FeaturesPlugin_Pipe.h>
+#include <FeaturesPlugin_Loft.h>
 #include <FeaturesPlugin_Placement.h>
 #include <FeaturesPlugin_Recover.h>
 #include <FeaturesPlugin_RemoveSubShapes.h>
@@ -86,6 +87,8 @@ FeaturesPlugin_Plugin::FeaturesPlugin_Plugin()
                               new FeaturesPlugin_ValidatorPipeLocations);
   aFactory->registerValidator("FeaturesPlugin_ValidatorPipeLocationsNumber",
                               new FeaturesPlugin_ValidatorPipeLocationsNumber);
+  aFactory->registerValidator("FeaturesPlugin_ValidatorLoftSameTypeShape",
+                              new FeaturesPlugin_ValidatorLoftSameTypeShape);
   aFactory->registerValidator("FeaturesPlugin_ValidatorExtrusionDir",
                               new FeaturesPlugin_ValidatorExtrusionDir);
   aFactory->registerValidator("FeaturesPlugin_ValidatorExtrusionBoundary",
@@ -161,6 +164,8 @@ FeaturePtr FeaturesPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new FeaturesPlugin_Partition);
   } else if (theFeatureID == FeaturesPlugin_Pipe::ID()) {
     return FeaturePtr(new FeaturesPlugin_Pipe);
+  } else if (theFeatureID == FeaturesPlugin_Loft::ID()) {
+    return FeaturePtr(new FeaturesPlugin_Loft);
   } else if (theFeatureID == FeaturesPlugin_Placement::ID()) {
     return FeaturePtr(new FeaturesPlugin_Placement);
   } else if (theFeatureID == FeaturesPlugin_Recover::ID()) {
index 3181fc925bead505efef23cf7f526ba214ab234d..68fcb043fca7975f05b3aed6c61625b67b7f010e 100644 (file)
@@ -228,6 +228,57 @@ bool FeaturesPlugin_ValidatorPipeLocationsNumber::isValid(
 }
 // LCOV_EXCL_STOP
 
+//==================================================================================================
+bool FeaturesPlugin_ValidatorLoftSameTypeShape::isValid(
+                                                const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                                const std::list<std::string>& theArguments,
+                                                Events_InfoMessage& theError) const
+{
+  static const std::string aFirstObjetcID = "first_object";
+  static const std::string aSecondObjetcID = "second_object";
+
+  if (theFeature->getKind() != "Loft") {
+    theError = "Error: Feature \"%1\" does not supported by this validator.";
+    theError.arg(theFeature->getKind());
+    return false;
+  }
+
+  AttributeSelectionPtr aFirstObjectsSelection = theFeature->selection(aFirstObjetcID);
+  if ( !aFirstObjectsSelection->isInitialized()) {
+    theError = "Error: Could not get \"%1\" attribute.";
+    theError.arg(aFirstObjetcID);
+    return false;
+  }
+
+  AttributeSelectionPtr aSecondObjectsSelection = theFeature->selection(aSecondObjetcID);
+  if (!aSecondObjectsSelection->isInitialized()) {
+    theError = "Error: Could not get \"%1\" attribute.";
+    theError.arg(aSecondObjetcID);
+    return false;
+  }
+
+  GeomShapePtr aFirstShape  = aFirstObjectsSelection->value();
+  if (!aFirstShape.get()) {
+    aFirstShape = aFirstObjectsSelection->context()->shape();
+  }
+  GeomShapePtr aSecondShape  = aSecondObjectsSelection->value();
+  if (!aSecondShape.get()) {
+    aSecondShape = aSecondObjectsSelection->context()->shape();
+  }
+
+  if (aFirstShape->isEqual(aSecondShape)) {
+    theError = "Error: the shapes are equal";
+    return false;
+  }
+
+  if (aFirstShape->shapeType()!=aSecondShape->shapeType()) {
+    theError = "Error: the shapes have different type";
+    return false;
+  }
+
+  return true;
+}
+
 //==================================================================================================
 bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theAttribute,
                                                         const std::list<std::string>& theArguments,
index b868e23b8210b57edbc7144d678d00321688c9c3..adfb0cd3f6d9d58a75a8ccafdd42dbbf32621293 100644 (file)
@@ -68,6 +68,21 @@ class FeaturesPlugin_ValidatorPipeLocationsNumber: public ModelAPI_FeatureValida
                        Events_InfoMessage& theError) const;
 };
 
+/// \class FeaturesPlugin_ValidatorLoftSameTypeShape
+/// \ingroup Validators
+/// \brief Validator for the same type of shape.
+class FeaturesPlugin_ValidatorLoftSameTypeShape: public ModelAPI_FeatureValidator
+{
+ public:
+  //! \return true if the type of selected are the same
+  //! \param theFeature the checked feature
+  //! \param theArguments arguments of the feature (not used)
+  //! \param theError error message
+  virtual bool isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                       const std::list<std::string>& theArguments,
+                       Events_InfoMessage& theError) const;
+};
+
 /// \class FeaturesPlugin_ValidatorBaseForGeneration
 /// \ingroup Validators
 /// \brief A validator for selection base for generation. Allows to select faces on sketch,
index 878c1f4d5b97b1bad9fdab6ec1d76f3155b3364f..653d085b8e3e5f43680376a611b7936bc0d28863 100644 (file)
       <source>Pipe</source>
       <translation>Tuyau</translation>
     </message>
+    <message>
+      <source>Loft</source>
+      <translation>Lissage</translation>
+    </message>
     <message>
       <source>Recover</source>
       <translation>Récupérer</translation>
     </message>
   </context>
 
+  <!-- Loft -->
+  <context>
+    <name>Loft</name>
+    <message>
+      <source>Loft</source>
+      <translation>Lissage</translation>
+    </message>
+  </context>
+  <context>
+    <name>Loft:first_object</name>
+    <message>
+      <source>First object:</source>
+      <translation>Premier objet:</translation>
+    </message>
+  </context>
+    <context>
+      <name>Loft:second_object</name>
+    <message>
+      <source>Second object:</source>
+      <translation>Deuxième objet:</translation>
+    </message>
+  </context>
   <!-- Recover -->
   <context>
     <name>Recover</name>
diff --git a/src/FeaturesPlugin/Test/TestLoft.py b/src/FeaturesPlugin/Test/TestLoft.py
new file mode 100644 (file)
index 0000000..2744522
--- /dev/null
@@ -0,0 +1,198 @@
+# Copyright (C) 2018-2022  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Sketch
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+
+### Create SketchLine
+SketchLine_1 = Sketch_1.addLine(65.56914119359536, 34.84279475982533, -62.33478893740904, 34.84279475982533)
+
+### Create SketchLine
+SketchLine_2 = Sketch_1.addLine(-62.33478893740904, 34.84279475982533, -62.33478893740904, -28.08005822416302)
+
+### Create SketchLine
+SketchLine_3 = Sketch_1.addLine(-62.33478893740904, -28.08005822416302, 65.56914119359536, -28.08005822416302)
+
+### Create SketchLine
+SketchLine_4 = Sketch_1.addLine(65.56914119359536, -28.08005822416302, 65.56914119359536, 34.84279475982533)
+Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+Sketch_1.setHorizontal(SketchLine_1.result())
+Sketch_1.setVertical(SketchLine_2.result())
+Sketch_1.setHorizontal(SketchLine_3.result())
+Sketch_1.setVertical(SketchLine_4.result())
+model.do()
+
+### Create Plane
+Plane_4 = model.addPlane(Part_1_doc, model.selection("EDGE", "Sketch_1/SketchLine_4"), model.selection("VERTEX", "Sketch_1/SketchLine_3_StartVertex"), False)
+
+### Create Plane
+Plane_5 = model.addPlane(Part_1_doc, model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f"), 100, False)
+
+### Create Sketch
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("YOZ"))
+
+### Create SketchCircle
+SketchCircle_1 = Sketch_2.addCircle(60.9581866489876, 39.76685108527785, 26.86156014153439)
+model.do()
+
+### Create Plane
+Plane_6 = model.addPlane(Part_1_doc, model.selection("FACE", "Sketch_2/Face-SketchCircle_1_2r"), 100, False)
+
+### Create Box
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+
+### Create Box
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+
+### Create Translation
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("COMPOUND", "all-in-Box_2")], axis = model.selection("EDGE", "PartSet/OY"), distance = 100, keepSubResults = True)
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"),
+                  model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"),
+                  model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"),
+                  model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Wire
+Wire_2_objects = [model.selection("EDGE", "[Translation_1_1_1/MF:Translated&Box_2_1/Left][Translation_1_1_1/MF:Translated&Box_2_1/Top]"),
+                  model.selection("EDGE", "[Translation_1_1_1/MF:Translated&Box_2_1/Front][Translation_1_1_1/MF:Translated&Box_2_1/Left]"),
+                  model.selection("EDGE", "[Translation_1_1_1/MF:Translated&Box_2_1/Left][Translation_1_1_1/MF:Translated&Box_2_1/Bottom]"),
+                  model.selection("EDGE", "[Translation_1_1_1/MF:Translated&Box_2_1/Back][Translation_1_1_1/MF:Translated&Box_2_1/Left]")]
+Wire_2 = model.addWire(Part_1_doc, Wire_2_objects, False)
+
+### Create Box
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+
+### Create Wire
+Wire_3 = model.addWire(Part_1_doc, [model.selection("EDGE", "[Box_3_1/Left][Box_3_1/Top]"), model.selection("EDGE", "[Box_3_1/Front][Box_3_1/Left]")], False)
+
+### Create Box
+Box_4 = model.addBox(Part_1_doc, 10, 10, 10)
+
+### Create Translation
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("COMPOUND", "all-in-Box_4")], axis = model.selection("EDGE", "PartSet/OY"), distance = 40, keepSubResults = True)
+
+### Create Wire
+Wire_4 = model.addWire(Part_1_doc, [model.selection("EDGE", "[Translation_2_1_1/MF:Translated&Box_4_1/Left][Translation_2_1_1/MF:Translated&Box_4_1/Top]"), model.selection("EDGE", "[Translation_2_1_1/MF:Translated&Box_4_1/Front][Translation_2_1_1/MF:Translated&Box_4_1/Left]")], False)
+
+### Create Loft
+Loft_1 = model.addLoft(Part_1_doc, model.selection("FACE", "Plane_2"), model.selection("FACE", "Plane_1"))
+
+### Create Loft
+Loft_2 = model.addLoft(Part_1_doc, model.selection("WIRE", "Wire_2_1"), model.selection("WIRE", "Wire_1_1"))
+
+### Create Loft
+Loft_3 = model.addLoft(Part_1_doc, model.selection("WIRE", "Wire_3_1"), model.selection("WIRE", "Wire_4_1"))
+
+### Create Loft
+Loft_4 = model.addLoft(Part_1_doc, model.selection("EDGE", "Sketch_1/SketchLine_2"), model.selection("EDGE", "Sketch_1/SketchLine_4"))
+
+# # Errors tests
+# Wire and Edge
+Box_5 = model.addBox(Part_1_doc, 10, 10, 10)
+Wire_5_objects = [model.selection("EDGE", "[Box_5_1/Back][Box_5_1/Left]"),
+                  model.selection("EDGE", "[Box_5_1/Left][Box_5_1/Top]"),
+                  model.selection("EDGE", "[Box_5_1/Front][Box_5_1/Left]"),
+                  model.selection("EDGE", "[Box_5_1/Left][Box_5_1/Bottom]")]
+Wire_5 = model.addWire(Part_1_doc, Wire_5_objects, False)
+Box_6 = model.addBox(Part_1_doc, 10, 10, 10)
+Loft_5 = model.addLoft(Part_1_doc, model.selection("WIRE", "Wire_5_1"), model.selection("EDGE", "[Box_6_1/Right][Box_6_1/Top]"))
+assert(Loft_5.feature().error() == "Error: the shapes have different type")
+
+# Wire and Face
+Wire_6_objects = [model.selection("EDGE", "[Loft_1_1/Loft_Face_1][Loft_1_1/Loft_Face_5]"),
+                  model.selection("EDGE", "[Loft_1_1/Loft_Face_1][Loft_1_1/Loft_Face_4]"),
+                  model.selection("EDGE", "[Loft_1_1/Loft_Face_1][Loft_1_1/Loft_Face_2]"),
+                  model.selection("EDGE", "[Loft_1_1/Loft_Face_1][Loft_1_1/Loft_Face_6]")]
+Wire_6 = model.addWire(Part_1_doc, Wire_6_objects, False)
+Loft_6 = model.addLoft(Part_1_doc, model.selection("WIRE", "Wire_6_1"), model.selection("EDGE", "Plane_3"))
+assert(Loft_6.feature().error() == "Error: the shapes have different type")
+
+# Only one element
+Box_7 = model.addBox(Part_1_doc, 10, 10, 10)
+Loft_7 = model.addLoft(Part_1_doc, model.selection("SOLID", "Box_7_1"), model.selection())
+assert(Loft_7.feature().error() == 'Error: Could not get "second_object" attribute.')
+
+# Two faces with different number of edges
+Cone_1 = model.addCone(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 10, 5, 10)
+Loft_8 = model.addLoft(Part_1_doc, model.selection("FACE", "Cone_1_1/Face_2"), model.selection("EDGE", "Plane_3"))
+
+model.end()
+
+from GeomAPI import GeomAPI_Shape
+
+#test loft with two face
+model.testNbResults(Loft_1, 1)
+model.testNbSubResults(Loft_1, [0])
+model.testNbSubShapes(Loft_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Loft_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Loft_1, GeomAPI_Shape.EDGE, [24])
+model.testNbSubShapes(Loft_1, GeomAPI_Shape.VERTEX, [48])
+model.testResultsVolumes(Loft_1, [996988.58940])
+
+#test loft with two wire
+model.testNbResults(Loft_2, 1)
+model.testNbSubResults(Loft_2, [0])
+model.testNbSubShapes(Loft_2, GeomAPI_Shape.SHELL, [1])
+model.testNbSubShapes(Loft_2, GeomAPI_Shape.FACE, [4])
+model.testNbSubShapes(Loft_2, GeomAPI_Shape.EDGE, [16])
+model.testNbSubShapes(Loft_2, GeomAPI_Shape.VERTEX, [32])
+model.testResultsVolumes(Loft_2, [0.0])
+
+#test loft with two wire
+model.testNbResults(Loft_3, 1)
+model.testNbSubResults(Loft_3, [0])
+model.testNbSubShapes(Loft_3, GeomAPI_Shape.SHELL, [1])
+model.testNbSubShapes(Loft_3, GeomAPI_Shape.FACE, [2])
+model.testNbSubShapes(Loft_3, GeomAPI_Shape.EDGE, [8])
+model.testNbSubShapes(Loft_3, GeomAPI_Shape.VERTEX, [16])
+model.testResultsVolumes(Loft_3, [0.0])
+
+#test loft with two edge
+model.testNbResults(Loft_4, 1)
+model.testNbSubResults(Loft_4, [0])
+model.testNbSubShapes(Loft_4, GeomAPI_Shape.FACE, [1])
+model.testNbSubShapes(Loft_4, GeomAPI_Shape.EDGE, [4])
+model.testNbSubShapes(Loft_4, GeomAPI_Shape.VERTEX, [8])
+model.testResultsVolumes(Loft_4, [0.0])
+
+#test loft with faces with different number of edges
+model.testNbResults(Loft_8, 1)
+model.testNbSubResults(Loft_8, [0])
+model.testNbSubShapes(Loft_8, GeomAPI_Shape.FACE, [7])
+model.testNbSubShapes(Loft_8, GeomAPI_Shape.EDGE, [30])
+model.testNbSubShapes(Loft_8, GeomAPI_Shape.VERTEX, [60])
+model.testResultsVolumes(Loft_8, [151868.70541])
+
+
+
+
index 6fc8177bd946e0f6bdf8758681daf93320daf32c..ac4a0fd5b8fd11876b0c2e4f815e19cebcea055a 100644 (file)
@@ -25,6 +25,7 @@ Features plug-in provides a set of common topological operations. It implements
    geometryCalculationFeature.rst
    importResultFeature.rst
    linearCopyFeature.rst
+   loftFeature.rst
    measurementFeature.rst
    normalToFaceFeature.rst
    pipeFeature.rst
diff --git a/src/FeaturesPlugin/doc/TUI_loftFeature.rst b/src/FeaturesPlugin/doc/TUI_loftFeature.rst
new file mode 100644 (file)
index 0000000..c97cf3f
--- /dev/null
@@ -0,0 +1,11 @@
+
+  .. _tui_loft:
+
+loft
+====
+
+.. literalinclude:: examples/loft.py      
+    :linenos:
+    :language: python
+
+:download:`Download this script <examples/loft.py>`
diff --git a/src/FeaturesPlugin/doc/examples/loft.py b/src/FeaturesPlugin/doc/examples/loft.py
new file mode 100644 (file)
index 0000000..f3f9dfe
--- /dev/null
@@ -0,0 +1,45 @@
+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 Sketch
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+
+### Create SketchLine
+SketchLine_1 = Sketch_1.addLine(65.56914119359536, 34.84279475982533, -62.33478893740904, 34.84279475982533)
+
+### Create SketchLine
+SketchLine_2 = Sketch_1.addLine(-62.33478893740904, 34.84279475982533, -62.33478893740904, -28.08005822416302)
+
+### Create SketchLine
+SketchLine_3 = Sketch_1.addLine(-62.33478893740904, -28.08005822416302, 65.56914119359536, -28.08005822416302)
+
+### Create SketchLine
+SketchLine_4 = Sketch_1.addLine(65.56914119359536, -28.08005822416302, 65.56914119359536, 34.84279475982533)
+Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+Sketch_1.setHorizontal(SketchLine_1.result())
+Sketch_1.setVertical(SketchLine_2.result())
+Sketch_1.setHorizontal(SketchLine_3.result())
+Sketch_1.setVertical(SketchLine_4.result())
+model.do()
+
+### Create Plane
+Plane_1 = model.addPlane(Part_1_doc, model.selection("EDGE", "Sketch_1/SketchLine_4"), model.selection("VERTEX", "Sketch_1/SketchLine_3_StartVertex"), False)
+
+### Create Plane
+Plane_2 = model.addPlane(Part_1_doc, model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f"), 100, False)
+
+### Create Loft
+Loft_1 = model.addLoft(Part_1_doc, model.selection("FACE", "Plane_1"), model.selection("FACE", "Plane_2"))
+
+model.end()
diff --git a/src/FeaturesPlugin/doc/images/loft.png b/src/FeaturesPlugin/doc/images/loft.png
new file mode 100644 (file)
index 0000000..892ead9
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/loft.png differ
diff --git a/src/FeaturesPlugin/doc/images/loftPropertyPanel.png b/src/FeaturesPlugin/doc/images/loftPropertyPanel.png
new file mode 100644 (file)
index 0000000..7602443
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/loftPropertyPanel.png differ
diff --git a/src/FeaturesPlugin/doc/images/resultLoft.png b/src/FeaturesPlugin/doc/images/resultLoft.png
new file mode 100644 (file)
index 0000000..acf0013
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/resultLoft.png differ
diff --git a/src/FeaturesPlugin/doc/loftFeature.rst b/src/FeaturesPlugin/doc/loftFeature.rst
new file mode 100644 (file)
index 0000000..d053bba
--- /dev/null
@@ -0,0 +1,45 @@
+.. |loft.icon|    image:: images/loft.png
+
+Loft
+====
+
+**Loft** feature is used to create a face, shell or a solid shape from two or more objects.
+The two objects can be edges, wires or faces but must be of the same type
+
+To create a Loft in the active part:
+
+#. select in the Main Menu *Features - > Loft* item  or
+#. click |loft.icon| **Loft** button in the toolbar
+
+The following property panel appears.
+
+.. figure:: images/loftPropertyPanel.png
+   :align: center
+
+   Loft property panel
+
+Input fields:
+
+- **First object** defines the first shape (edge, wire, face) selected in 3D OCC viewer or object browser;
+- **Second object** defines the second shape (edge, wire, face) selected in 3D OCC viewer or object browser;
+
+**TUI Command**:
+
+.. py:function:: model.addLoft(Part_doc, [shape], [shape])
+
+    :param part: The current part object.
+    :param object: A shape in format *model.selection(TYPE, shape)*.
+    :param object: A shape in format *model.selection(TYPE, shape)*.
+    :return: Created object.
+
+Result
+""""""
+
+Result of loft between two faces.
+
+.. figure:: images/resultLoft.png
+   :align: center
+
+   Loft between two faces
+
+**See Also** a sample TUI Script of :ref:`tui_loft` operation.
diff --git a/src/FeaturesPlugin/icons/loft.png b/src/FeaturesPlugin/icons/loft.png
new file mode 100644 (file)
index 0000000..892ead9
Binary files /dev/null and b/src/FeaturesPlugin/icons/loft.png differ
diff --git a/src/FeaturesPlugin/loft_widget.xml b/src/FeaturesPlugin/loft_widget.xml
new file mode 100644 (file)
index 0000000..21dc390
--- /dev/null
@@ -0,0 +1,19 @@
+<source>
+  <shape_selector id="first_object"
+                  label="First object:"
+                  tooltip="Select a object"
+                  shape_types="edge face wire"
+                  concealment="true"
+                  default="">
+    <validator id="GeomValidators_ShapeType" parameters="line,edge,wire,face,shell"/>
+  </shape_selector>
+  <shape_selector id="second_object"
+                  label="Second object:"
+                  tooltip="Select a object"
+                  shape_types="edge face wire"
+                  concealment="true"
+                  default="">
+    <validator id="GeomValidators_ShapeType" parameters="line,edge,wire,face,shell"/>
+  </shape_selector>
+  <validator id="FeaturesPlugin_ValidatorLoftSameTypeShape"/>
+</source>
index 87e47c378a6753e27f3297a13ee4f79bbe2fb6a8..59ec705feb4555fab2e14237e06372a6684a682a 100644 (file)
                icon="icons/Features/pipe.png" helpfile="pipeFeature.html">
         <source path="pipe_widget.xml"/>
       </feature>
+      <feature id="Loft" title="Loft" tooltip="Generates a shape xwith two elements"
+               icon="icons/Features/loft.png" helpfile="loftFeature.html">
+        <source path="loft_widget.xml"/>
+      </feature>
     </group>
     <group id="Boolean" toolbar="yes">
       <feature id="Cut" title="Cut" tooltip="Perform boolean cut operation with objects"
index 393bc27e372859449568357273c7ea34f4f3fcc0..2b4e72796d1f72f5ca3edbe43f70cdcfe866aa19 100644 (file)
@@ -178,7 +178,7 @@ SET(TEST_NAMES
                TestMeasurementAngle3Points.py
                TestMeasurementPresentation.py
                TestFusionFaces.py
-               TestFusionFaces2697.py 
+               TestFusionFaces2697.py
                Test1379.py
                Test1922.py
                Test1942.py
@@ -526,4 +526,5 @@ SET(TEST_NAMES
                TestBoundingBox.py
                Test23885.py
                TestNormalToFace.py
+               TestLoft.py
 )
index 86ee8fe7ca671ceaa56f8d6231e5615e2efee1ee..02542a643c3c1894177857235264d17a331a699b 100644 (file)
@@ -60,6 +60,7 @@ SET(PROJECT_HEADERS
     GeomAlgoAPI_PaveFiller.h
     GeomAlgoAPI_Intersection.h
     GeomAlgoAPI_Pipe.h
+    GeomAlgoAPI_Loft.h
     GeomAlgoAPI_WireBuilder.h
     GeomAlgoAPI_Sewing.h
     GeomAlgoAPI_ShapeBuilder.h
@@ -134,6 +135,7 @@ SET(PROJECT_SOURCES
     GeomAlgoAPI_PaveFiller.cpp
     GeomAlgoAPI_Intersection.cpp
     GeomAlgoAPI_Pipe.cpp
+    GeomAlgoAPI_Loft.cpp
     GeomAlgoAPI_WireBuilder.cpp
     GeomAlgoAPI_Sewing.cpp
     GeomAlgoAPI_ShapeBuilder.cpp
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Loft.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Loft.cpp
new file mode 100644 (file)
index 0000000..3e07f52
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright (C) 2014-2022  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "GeomAlgoAPI_DFLoader.h"
+#include "GeomAlgoAPI_Loft.h"
+
+#include <BRepOffsetAPI_ThruSections.hxx>
+#include <Precision.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
+
+//==================================================================================================
+GeomAlgoAPI_Loft::GeomAlgoAPI_Loft(const GeomShapePtr theFirstShape,
+                                   const GeomShapePtr theSecondShape)
+{
+  build(theFirstShape, theSecondShape);
+}
+
+//==================================================================================================
+void GeomAlgoAPI_Loft::build(const GeomShapePtr theFirstShape,
+                             const GeomShapePtr theSecondShape)
+{
+  // Getting base shape.
+  if(!theFirstShape.get() || !theSecondShape.get()) {
+    return;
+  }
+  TopoDS_Shape aFirstShape = theFirstShape->impl<TopoDS_Shape>();
+  if(aFirstShape.IsNull()) {
+    return;
+  }
+  TopoDS_Shape aSecondShape= theSecondShape->impl<TopoDS_Shape>();
+  if(aSecondShape.IsNull()) {
+    return;
+  }
+
+  bool anIsSolid = true;
+
+  TopoDS_Shape aFirstShapeOut;
+  TopoDS_Shape aSecondShapeOut;
+  if (aFirstShape.ShapeType() == TopAbs_FACE) {
+    TopExp_Explorer anExp(aFirstShape, TopAbs_WIRE);
+    aFirstShapeOut = anExp.Current();
+    TopExp_Explorer anExp2(aSecondShape, TopAbs_WIRE);
+    aSecondShapeOut = anExp2.Current();
+  }
+
+  if (aFirstShape.ShapeType() == TopAbs_WIRE) {
+    aFirstShapeOut = aFirstShape;
+    aSecondShapeOut = aSecondShape;
+    anIsSolid = false;
+  }
+
+  // Initialize and build
+  BRepOffsetAPI_ThruSections * ThruSections =
+                              new BRepOffsetAPI_ThruSections(anIsSolid);
+  ThruSections->AddWire( TopoDS::Wire( aFirstShapeOut ) );
+  ThruSections->AddWire( TopoDS::Wire( aSecondShapeOut) );
+
+  try
+  {
+    ThruSections->Build();
+  }
+  catch (Standard_Failure& aFail)
+  {
+    delete ThruSections;
+    return;
+  }
+  // Checking result.
+  if(!ThruSections->IsDone() || ThruSections->Shape().IsNull()) {
+    delete ThruSections;
+    return;
+  }
+
+  this->initialize(ThruSections);
+
+  // Setting result.
+  TopoDS_Shape aResult = ThruSections->Shape();
+  aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
+  GeomShapePtr aGeomSh(new GeomAPI_Shape());
+  aGeomSh->setImpl(new TopoDS_Shape(aResult));
+  this->setShape(aGeomSh);
+  this->setDone(true);
+}
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Loft.h b/src/GeomAlgoAPI/GeomAlgoAPI_Loft.h
new file mode 100644 (file)
index 0000000..da5da2c
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright (C) 2014-2022  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef GeomAlgoAPI_Loft_H_
+#define GeomAlgoAPI_Loft_H_
+
+#include "GeomAlgoAPI.h"
+
+#include "GeomAlgoAPI_MakeShape.h"
+
+#include <GeomAPI_Shape.h>
+
+/// \class GeomAlgoAPI_Loft
+/// \ingroup DataAlgo
+/// \brief Allows to create loft of two objects with same type.
+/// It produces the following results from objects:
+/// 2 edges -> Face
+/// 2 Wire -> Shell
+/// 2 Face -> Solid
+class GeomAlgoAPI_Loft : public GeomAlgoAPI_MakeShape
+{
+  public:
+    /// \brief Creates loft for two given shape with same type.
+    /// \param[in] theFirstShape  the first shape.
+    /// \param[in] theSecondShape the second shape.
+    GEOMALGOAPI_EXPORT GeomAlgoAPI_Loft(const GeomShapePtr theFirstShape,
+                                        const GeomShapePtr theSecondShape);
+
+  private:
+    void build(const GeomShapePtr theFirstShape,
+              const GeomShapePtr theSecondShape);
+
+};
+
+#endif
index e316358829e21eb9c1d4283a7fe55d7da7a57941..d6825bf0612577a9a86992153902e8c9343194ec 100644 (file)
@@ -23,7 +23,7 @@ from FeaturesAPI import addPlacement, addRotation, addScale, addSymmetry, addTra
 from FeaturesAPI import addMultiTranslation, addMultiRotation
 from FeaturesAPI import addExtrusion, addExtrusionCut, addExtrusionFuse
 from FeaturesAPI import addRevolution, addRevolutionCut, addRevolutionFuse
-from FeaturesAPI import addPipe
+from FeaturesAPI import addPipe, addLoft
 from FeaturesAPI import addCut, addFuse, addCommon, addSmash, addSplit
 from FeaturesAPI import addIntersection, addPartition, addUnion, addRemoveSubShapes
 from FeaturesAPI import addRecover