]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Issue #3222: 1d fillet
authorArtem Zhidkov <Artem.Zhidkov@opencascade.com>
Wed, 22 Apr 2020 08:55:13 +0000 (11:55 +0300)
committerArtem Zhidkov <Artem.Zhidkov@opencascade.com>
Thu, 23 Apr 2020 16:17:43 +0000 (19:17 +0300)
* Implement the 1D-fillet feature
* Unit tests for 1D-fillet

42 files changed:
src/BuildPlugin/BuildPlugin_Wire.cpp
src/FeaturesAPI/FeaturesAPI.i
src/FeaturesAPI/FeaturesAPI_Fillet.cpp
src/FeaturesAPI/FeaturesAPI_Fillet.h
src/FeaturesPlugin/CMakeLists.txt
src/FeaturesPlugin/FeaturesPlugin_Fillet1D.cpp [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_Fillet1D.h [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.h
src/FeaturesPlugin/Test/TestFillet1D_ErrorMsg.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet1D_Vertices_1.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet1D_Vertices_2.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet1D_Vertices_3.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet1D_Vertices_4.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet1D_Vertices_5.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet1D_Vertices_6.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet1D_Vertices_7.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet1D_Vertices_8.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet1D_Wire_1.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet1D_Wire_2.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet1D_Wire_3.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet1D_Wire_4.py [new file with mode: 0644]
src/FeaturesPlugin/fillet1d_widget.xml [new file with mode: 0644]
src/FeaturesPlugin/icons/fillet1d.png [new file with mode: 0644]
src/FeaturesPlugin/icons/fillet1d_points.png [new file with mode: 0644]
src/FeaturesPlugin/icons/fillet1d_wire.png [new file with mode: 0644]
src/FeaturesPlugin/plugin-Features.xml
src/FiltersPlugin/FiltersPlugin_OppositeToEdge.cpp
src/GeomAPI/GeomAPI_Edge.cpp
src/GeomAPI/GeomAPI_Edge.h
src/GeomAPI/GeomAPI_WireExplorer.cpp
src/GeomAPI/GeomAPI_WireExplorer.h
src/GeomAlgoAPI/CMakeLists.txt
src/GeomAlgoAPI/GeomAlgoAPI_Fillet1D.cpp [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_Fillet1D.h [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h
src/GeomAlgoImpl/CMakeLists.txt
src/GeomAlgoImpl/GEOMImpl_Fillet1d.cxx [new file with mode: 0644]
src/GeomAlgoImpl/GEOMImpl_Fillet1d.hxx [new file with mode: 0644]
src/ModelHighAPI/ModelHighAPI_Macro.h

index c7caa85812a46170e654e5298e309f35a53b494e..04e6f6fe5d5641e90a1b40a9fe9d044712746235 100644 (file)
@@ -122,7 +122,10 @@ void BuildPlugin_Wire::execute()
       for (ListOfShape::const_iterator anIt = anEdges.cbegin(); anIt != anEdges.cend(); ++anIt) {
         std::shared_ptr<GeomAPI_Edge> anEdgeInList(new GeomAPI_Edge(*anIt));
         if (anEdgeInList->isEqual(anEdgeInResult)) {
-          aResultBody->modified(anEdgeInList, anEdgeInResult);
+          if (anEdgeInList->isSame(anEdgeInResult))
+            aResultBody->generated(anEdgeInResult, "Edge");
+          else
+            aResultBody->modified(anEdgeInList, anEdgeInResult);
           break;
         }
       }
index 010ddfa51867f5c1ab8392265d1dd105f148373b..2024975c6d908e2db1a341cd999b906b1c604ff1 100644 (file)
@@ -68,6 +68,8 @@
 %shared_ptr(FeaturesAPI_ExtrusionCut)
 %shared_ptr(FeaturesAPI_ExtrusionFuse)
 %shared_ptr(FeaturesAPI_Fillet)
+%shared_ptr(FeaturesAPI_Fillet1D)
+%shared_ptr(FeaturesAPI_Fillet2D)
 %shared_ptr(FeaturesAPI_Intersection)
 %shared_ptr(FeaturesAPI_MultiRotation)
 %shared_ptr(FeaturesAPI_MultiTranslation)
index d84e0017540195506e9f04f2f325d9817a6d0334..5cb598acbdbe0b2acbae261d8d5f53ce6c6160ba 100644 (file)
 
 #include <ModelHighAPI_Double.h>
 #include <ModelHighAPI_Dumper.h>
-////#include <ModelHighAPI_Reference.h>
+#include <ModelHighAPI_Selection.h>
 #include <ModelHighAPI_Tools.h>
 
+static GeomAPI_Shape::ShapeType typeOfSelection(
+    const std::list<ModelHighAPI_Selection>& theBaseObjects)
+{
+  std::string aType = theBaseObjects.empty() ? "SHAPE" : theBaseObjects.front().shapeType();
+  return GeomAPI_Shape::shapeTypeByStr(aType);
+}
+
+//==================================================================================================
+
 FeaturesAPI_Fillet::FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>& theFeature)
   : ModelHighAPI_Interface(theFeature)
+{
+}
+
+//==================================================================================================
+
+FeaturesAPI_Fillet1D::FeaturesAPI_Fillet1D(const std::shared_ptr<ModelAPI_Feature>& theFeature)
+  : FeaturesAPI_Fillet(theFeature)
 {
   initialize();
 }
 
-FeaturesAPI_Fillet::FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>& theFeature,
-                                       const std::list<ModelHighAPI_Selection>& theBaseObjects,
-                                       const ModelHighAPI_Double& theRadius)
-  : ModelHighAPI_Interface(theFeature)
+FeaturesAPI_Fillet1D::FeaturesAPI_Fillet1D(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                           const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                           const ModelHighAPI_Double& theRadius)
+  : FeaturesAPI_Fillet(theFeature)
+{
+  if (initialize()) {
+    setBase(theBaseObjects);
+    fillAttribute(theRadius, myradius);
+
+    execIfBaseNotEmpty();
+  }
+}
+
+FeaturesAPI_Fillet1D::~FeaturesAPI_Fillet1D()
+{
+}
+
+void FeaturesAPI_Fillet1D::setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects)
+{
+  mybaseWires->clear();
+  mybaseVertices->clear();
+
+  if (typeOfSelection(theBaseObjects) == GeomAPI_Shape::WIRE) {
+    fillAttribute(FeaturesPlugin_Fillet1D::CREATION_BY_WIRES(), mycreationMethod);
+    fillAttribute(theBaseObjects, mybaseWires);
+  }
+  else {
+    fillAttribute(FeaturesPlugin_Fillet1D::CREATION_BY_VERTICES(), mycreationMethod);
+    fillAttribute(theBaseObjects, mybaseVertices);
+  }
+
+  execIfBaseNotEmpty();
+}
+
+void FeaturesAPI_Fillet1D::setRadius(const ModelHighAPI_Double& theRadius)
+{
+  fillAttribute(theRadius, myradius);
+  execIfBaseNotEmpty();
+}
+
+void FeaturesAPI_Fillet1D::execIfBaseNotEmpty()
+{
+  if (mybaseWires->size() > 0 || mybaseVertices->size() > 0)
+    execute();
+}
+
+void FeaturesAPI_Fillet1D::dump(ModelHighAPI_Dumper& theDumper) const
+{
+  FeaturePtr aBase = feature();
+  const std::string& aDocName = theDumper.name(aBase->document());
+
+  AttributeSelectionListPtr anAttrObjects;
+  if (creationMethod()->value() == FeaturesPlugin_Fillet1D::CREATION_BY_WIRES())
+    anAttrObjects = aBase->selectionList(FeaturesPlugin_Fillet1D::WIRE_LIST_ID());
+  else if (creationMethod()->value() == FeaturesPlugin_Fillet1D::CREATION_BY_VERTICES())
+    anAttrObjects = aBase->selectionList(FeaturesPlugin_Fillet1D::VERTEX_LIST_ID());
+
+  AttributeDoublePtr anAttrRadius = aBase->real(FeaturesPlugin_Fillet1D::RADIUS_ID());
+
+  theDumper << aBase << " = model.addFillet(" << aDocName << ", " << anAttrObjects
+                                                          << ", " << anAttrRadius;
+
+  if (!aBase->data()->version().empty())
+    theDumper << ", keepSubResults = True";
+
+  theDumper << ")" << std::endl;
+}
+
+//==================================================================================================
+
+FeaturesAPI_Fillet2D::FeaturesAPI_Fillet2D(const std::shared_ptr<ModelAPI_Feature>& theFeature)
+  : FeaturesAPI_Fillet(theFeature)
+{
+  initialize();
+}
+
+FeaturesAPI_Fillet2D::FeaturesAPI_Fillet2D(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                           const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                           const ModelHighAPI_Double& theRadius)
+  : FeaturesAPI_Fillet(theFeature)
 {
   if (initialize()) {
     fillAttribute(FeaturesPlugin_Fillet::CREATION_METHOD_SINGLE_RADIUS(), mycreationMethod);
@@ -44,11 +136,11 @@ FeaturesAPI_Fillet::FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>&
   }
 }
 
-FeaturesAPI_Fillet::FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>& theFeature,
-                                       const std::list<ModelHighAPI_Selection>& theBaseObjects,
-                                       const ModelHighAPI_Double& theRadius1,
-                                       const ModelHighAPI_Double& theRadius2)
-  : ModelHighAPI_Interface(theFeature)
+FeaturesAPI_Fillet2D::FeaturesAPI_Fillet2D(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                           const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                           const ModelHighAPI_Double& theRadius1,
+                                           const ModelHighAPI_Double& theRadius2)
+  : FeaturesAPI_Fillet(theFeature)
 {
   if (initialize()) {
     fillAttribute(FeaturesPlugin_Fillet::CREATION_METHOD_VARYING_RADIUS(), mycreationMethod);
@@ -60,12 +152,11 @@ FeaturesAPI_Fillet::FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>&
   }
 }
 
-FeaturesAPI_Fillet::~FeaturesAPI_Fillet()
+FeaturesAPI_Fillet2D::~FeaturesAPI_Fillet2D()
 {
 }
 
-//==================================================================================================
-void FeaturesAPI_Fillet::setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects)
+void FeaturesAPI_Fillet2D::setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects)
 {
   mybaseObjects->clear();
   fillAttribute(theBaseObjects, mybaseObjects);
@@ -73,7 +164,7 @@ void FeaturesAPI_Fillet::setBase(const std::list<ModelHighAPI_Selection>& theBas
   execIfBaseNotEmpty();
 }
 
-void FeaturesAPI_Fillet::setRadius(const ModelHighAPI_Double& theRadius)
+void FeaturesAPI_Fillet2D::setRadius(const ModelHighAPI_Double& theRadius)
 {
   fillAttribute(FeaturesPlugin_Fillet::CREATION_METHOD_SINGLE_RADIUS(), mycreationMethod);
   fillAttribute(theRadius, myradius);
@@ -81,8 +172,8 @@ void FeaturesAPI_Fillet::setRadius(const ModelHighAPI_Double& theRadius)
   execIfBaseNotEmpty();
 }
 
-void FeaturesAPI_Fillet::setRadius(const ModelHighAPI_Double& theRadius1,
-                                   const ModelHighAPI_Double& theRadius2)
+void FeaturesAPI_Fillet2D::setRadius(const ModelHighAPI_Double& theRadius1,
+                                     const ModelHighAPI_Double& theRadius2)
 {
   fillAttribute(FeaturesPlugin_Fillet::CREATION_METHOD_VARYING_RADIUS(), mycreationMethod);
   fillAttribute(theRadius1, mystartRadius);
@@ -91,7 +182,7 @@ void FeaturesAPI_Fillet::setRadius(const ModelHighAPI_Double& theRadius1,
   execIfBaseNotEmpty();
 }
 
-void FeaturesAPI_Fillet::dump(ModelHighAPI_Dumper& theDumper) const
+void FeaturesAPI_Fillet2D::dump(ModelHighAPI_Dumper& theDumper) const
 {
   FeaturePtr aBase = feature();
   const std::string& aDocName = theDumper.name(aBase->document());
@@ -118,7 +209,7 @@ void FeaturesAPI_Fillet::dump(ModelHighAPI_Dumper& theDumper) const
   theDumper << ")" << std::endl;
 }
 
-void FeaturesAPI_Fillet::execIfBaseNotEmpty()
+void FeaturesAPI_Fillet2D::execIfBaseNotEmpty()
 {
   if (mybaseObjects->size() > 0)
     execute();
@@ -133,14 +224,20 @@ FilletPtr addFillet(const std::shared_ptr<ModelAPI_Document>& thePart,
                     const ModelHighAPI_Double& theRadius2,
                     const bool keepSubResults)
 {
-  std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_Fillet::ID());
+  GeomAPI_Shape::ShapeType aType = typeOfSelection(theBaseObjects);
+  bool is1D = aType == GeomAPI_Shape::WIRE || aType == GeomAPI_Shape::VERTEX;
+
+  FeaturePtr aFeature =
+      thePart->addFeature(is1D ? FeaturesAPI_Fillet1D::ID() : FeaturesAPI_Fillet2D::ID());
   if (!keepSubResults)
     aFeature->data()->setVersion("");
 
   FilletPtr aFillet;
-  if (theRadius2.value() < 0.0)
-    aFillet.reset(new FeaturesAPI_Fillet(aFeature, theBaseObjects, theRadius1));
+  if (is1D)
+    aFillet.reset(new FeaturesAPI_Fillet1D(aFeature, theBaseObjects, theRadius1));
+  else if (theRadius2.value() < 0.0)
+    aFillet.reset(new FeaturesAPI_Fillet2D(aFeature, theBaseObjects, theRadius1));
   else
-    aFillet.reset(new FeaturesAPI_Fillet(aFeature, theBaseObjects, theRadius1, theRadius2));
+    aFillet.reset(new FeaturesAPI_Fillet2D(aFeature, theBaseObjects, theRadius1, theRadius2));
   return aFillet;
 }
index b9adb3ff3a8f224e875fefac07489759f0f08492..dd15caef9f0646d3df5406330d8ee6675247970a 100644 (file)
@@ -23,6 +23,7 @@
 #include "FeaturesAPI.h"
 
 #include <FeaturesPlugin_Fillet.h>
+#include <FeaturesPlugin_Fillet1D.h>
 
 #include <ModelHighAPI_Double.h>
 #include <ModelHighAPI_Interface.h>
@@ -35,27 +36,103 @@ class ModelHighAPI_Selection;
 /// \brief Interface for Fillet feature.
 class FeaturesAPI_Fillet: public ModelHighAPI_Interface
 {
+public:
+  /// Destructor.
+  virtual ~FeaturesAPI_Fillet() {}
+
+  virtual std::shared_ptr<ModelAPI_AttributeDouble> radius() const = 0;
+
+  /// Modify base objects of the fillet.
+  virtual void setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects) = 0;
+
+  /// Modify fillet to have fixed radius
+  virtual void setRadius(const ModelHighAPI_Double& theRadius) = 0;
+
+protected:
+  FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+};
+
+/// Pointer on the fillet object.
+typedef std::shared_ptr<FeaturesAPI_Fillet> FilletPtr;
+
+
+/// \class FeaturesAPI_Fillet1D
+/// \ingroup CPPHighAPI
+/// \brief Interface for Fillet1D feature - fillet on vertices of a wire.
+class FeaturesAPI_Fillet1D : public FeaturesAPI_Fillet
+{
 public:
   /// Constructor without values.
   FEATURESAPI_EXPORT
-  explicit FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+  explicit FeaturesAPI_Fillet1D(const std::shared_ptr<ModelAPI_Feature>& theFeature);
 
   /// Constructor with values.
   FEATURESAPI_EXPORT
-  explicit FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>& theFeature,
-                              const std::list<ModelHighAPI_Selection>& theBaseObjects,
-                              const ModelHighAPI_Double& theRadius);
+  explicit FeaturesAPI_Fillet1D(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                const ModelHighAPI_Double& theRadius);
+
+  /// Destructor.
+  FEATURESAPI_EXPORT
+  virtual ~FeaturesAPI_Fillet1D();
+
+  INTERFACE_4(FeaturesPlugin_Fillet1D::ID(),
+              creationMethod, FeaturesPlugin_Fillet1D::CREATION_METHOD(),
+                              ModelAPI_AttributeString,
+                              /** Creation method */,
+              baseWires, FeaturesPlugin_Fillet1D::WIRE_LIST_ID(),
+                           ModelAPI_AttributeSelectionList,
+                           /** Base objects */,
+              baseVertices, FeaturesPlugin_Fillet1D::VERTEX_LIST_ID(),
+                            ModelAPI_AttributeSelectionList,
+                            /** Base objects */,
+              radius, FeaturesPlugin_Fillet1D::RADIUS_ID(),
+                      ModelAPI_AttributeDouble,
+                      /** Value of the fixed radius fillet */)
+
+  /// Modify base objects of the fillet.
+  FEATURESAPI_EXPORT
+  virtual void setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects);
+
+  /// Modify fillet to have fixed radius
+  FEATURESAPI_EXPORT
+  virtual void setRadius(const ModelHighAPI_Double& theRadius);
+
+  /// Dump wrapped feature
+  FEATURESAPI_EXPORT
+  virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+
+private:
+  void execIfBaseNotEmpty();
+};
+
+
+/// \class FeaturesAPI_Fillet2D
+/// \ingroup CPPHighAPI
+/// \brief Interface for Fillet feature - fillet edges on a solid.
+class FeaturesAPI_Fillet2D : public FeaturesAPI_Fillet
+{
+public:
+  /// Constructor without values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_Fillet2D(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+  /// Constructor with values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_Fillet2D(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                const ModelHighAPI_Double& theRadius);
 
   /// Constructor with values.
   FEATURESAPI_EXPORT
-  explicit FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>& theFeature,
-                              const std::list<ModelHighAPI_Selection>& theBaseObjects,
-                              const ModelHighAPI_Double& theRadius1,
-                              const ModelHighAPI_Double& theRadius2);
+  explicit FeaturesAPI_Fillet2D(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                const ModelHighAPI_Double& theRadius1,
+                                const ModelHighAPI_Double& theRadius2);
 
   /// Destructor.
   FEATURESAPI_EXPORT
-  virtual ~FeaturesAPI_Fillet();
+  virtual ~FeaturesAPI_Fillet2D();
 
   INTERFACE_5(FeaturesPlugin_Fillet::ID(),
               creationMethod, FeaturesPlugin_Fillet::CREATION_METHOD(),
@@ -76,11 +153,11 @@ public:
 
   /// Modify base objects of the fillet.
   FEATURESAPI_EXPORT
-  void setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects);
+  virtual void setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects);
 
   /// Modify fillet to have fixed radius
   FEATURESAPI_EXPORT
-  void setRadius(const ModelHighAPI_Double& theRadius);
+  virtual void setRadius(const ModelHighAPI_Double& theRadius);
 
   /// Modify fillet to have varying radius
   FEATURESAPI_EXPORT
@@ -94,8 +171,6 @@ private:
   void execIfBaseNotEmpty();
 };
 
-/// Pointer on Fillet object.
-typedef std::shared_ptr<FeaturesAPI_Fillet> FilletPtr;
 
 /// \ingroup CPPHighAPI
 /// \brief Create Fillet feature.
index 51d00ae402269646f30c9751e468aed7b5b731b3..b75a1a17e4dc554b7fee696580911803c13965f4 100644 (file)
@@ -57,6 +57,7 @@ SET(PROJECT_HEADERS
     FeaturesPlugin_MultiTranslation.h
     FeaturesPlugin_MultiRotation.h
     FeaturesPlugin_Fillet.h
+    FeaturesPlugin_Fillet1D.h
     FeaturesPlugin_Measurement.h
     FeaturesPlugin_FusionFaces.h
     FeaturesPlugin_RemoveResults.h
@@ -103,6 +104,7 @@ SET(PROJECT_SOURCES
     FeaturesPlugin_MultiTranslation.cpp
     FeaturesPlugin_MultiRotation.cpp
     FeaturesPlugin_Fillet.cpp
+    FeaturesPlugin_Fillet1D.cpp
     FeaturesPlugin_Measurement.cpp
     FeaturesPlugin_FusionFaces.cpp
     FeaturesPlugin_RemoveResults.cpp
@@ -140,6 +142,7 @@ SET(XML_RESOURCES
   multitranslation_widget.xml
   multirotation_widget.xml
   fillet_widget.xml
+  fillet1d_widget.xml
   measurement_widget.xml
   fusion_faces_widget.xml
   chamfer_widget.xml
@@ -658,4 +661,17 @@ ADD_UNIT_TESTS(TestExtrusion.py
                TestChamfer_MultiLevelCompound_v95_4.py
                Test18836.py
                Test2817.py
+               TestFillet1D_ErrorMsg.py
+               TestFillet1D_Vertices_1.py
+               TestFillet1D_Vertices_2.py
+               TestFillet1D_Vertices_3.py
+               TestFillet1D_Vertices_4.py
+               TestFillet1D_Vertices_5.py
+               TestFillet1D_Vertices_6.py
+               TestFillet1D_Vertices_7.py
+               TestFillet1D_Vertices_8.py
+               TestFillet1D_Wire_1.py
+               TestFillet1D_Wire_2.py
+               TestFillet1D_Wire_3.py
+               TestFillet1D_Wire_4.py
 )
diff --git a/src/FeaturesPlugin/FeaturesPlugin_Fillet1D.cpp b/src/FeaturesPlugin/FeaturesPlugin_Fillet1D.cpp
new file mode 100644 (file)
index 0000000..d62f6ac
--- /dev/null
@@ -0,0 +1,160 @@
+// Copyright (C) 2020  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include <FeaturesPlugin_Fillet1D.h>
+#include <FeaturesPlugin_Tools.h>
+
+#include <GeomAlgoAPI_Fillet1D.h>
+#include <GeomAlgoAPI_MapShapesAndAncestors.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+#include <GeomAlgoAPI_Tools.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Pln.h>
+#include <GeomAPI_WireExplorer.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_AttributeString.h>
+
+FeaturesPlugin_Fillet1D::FeaturesPlugin_Fillet1D()
+{
+}
+
+void FeaturesPlugin_Fillet1D::initAttributes()
+{
+  data()->addAttribute(CREATION_METHOD(), ModelAPI_AttributeString::typeId());
+  data()->addAttribute(WIRE_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
+  data()->addAttribute(VERTEX_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
+  data()->addAttribute(RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+}
+
+void FeaturesPlugin_Fillet1D::execute()
+{
+  MapShapeSubs aWireVertices;
+  if (!baseShapes(aWireVertices))
+    return;
+
+  int aResultIndex = 0;
+  for (MapShapeSubs::iterator anIt = aWireVertices.begin(); anIt != aWireVertices.end(); ++anIt)
+    if (!performFillet(anIt->first, anIt->second, aResultIndex++))
+      break;
+  removeResults(aResultIndex);
+}
+
+bool FeaturesPlugin_Fillet1D::baseShapes(MapShapeSubs& theWireVertices)
+{
+  std::string aMethod = string(CREATION_METHOD())->value();
+  if (aMethod == CREATION_BY_WIRES()) {
+    AttributeSelectionListPtr aSelList = selectionList(WIRE_LIST_ID());
+
+    std::set<GeomShapePtr> aProcessedWires;
+    int aNbSel = aSelList->size();
+    for (int ind = 0; ind < aNbSel; ++ind) {
+      AttributeSelectionPtr aCurSel = aSelList->value(ind);
+      GeomShapePtr aWire = aCurSel->context()->shape();
+      if (aProcessedWires.find(aWire) != aProcessedWires.end())
+        continue;
+
+      aProcessedWires.insert(aWire);
+      // get vertices applicable for fillet
+      GeomAlgoAPI_MapShapesAndAncestors aMapVE(aWire, GeomAPI_Shape::VERTEX, GeomAPI_Shape::EDGE);
+      const MapShapeToShapes& aSubshapes = aMapVE.map();
+      std::set<GeomShapePtr, GeomAPI_Shape::Comparator> aFilletVertices;
+      for (MapShapeToShapes::const_iterator anIt = aSubshapes.begin();
+           anIt != aSubshapes.end(); ++anIt) {
+        // vertex should have 2 adjacent edges
+        if (anIt->second.size() != 2)
+          continue;
+
+        // skip vertices, which adjacent edges are not on the same plane
+        ListOfShape anEdges;
+        anEdges.insert(anEdges.end(), anIt->second.begin(), anIt->second.end());
+        GeomPlanePtr aPlane = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
+        if (!aPlane)
+          continue;
+
+        // skip vertices, which smoothly connect adjacent edges
+        GeomEdgePtr anEdge1(new GeomAPI_Edge(anEdges.front()));
+        GeomEdgePtr anEdge2(new GeomAPI_Edge(anEdges.back()));
+        GeomVertexPtr aSharedVertex(new GeomAPI_Vertex(anIt->first));
+        if (GeomAlgoAPI_ShapeTools::isTangent(anEdge1, anEdge2, aSharedVertex))
+          continue;
+
+        aFilletVertices.insert(anIt->first);
+      }
+
+      if (aFilletVertices.empty()) {
+        setError("Wire has no vertices for fillet.");
+        return false;
+      }
+
+
+      // keep the sequence of fillet vertices stable
+      for (GeomAPI_WireExplorer anExp(aWire->wire()); anExp.more(); anExp.next()) {
+        GeomShapePtr aVertex = anExp.currentVertex();
+        if (aFilletVertices.find(aVertex) != aFilletVertices.end())
+          theWireVertices[aWire].push_back(aVertex);
+      }
+    }
+  }
+  else if (aMethod == CREATION_BY_VERTICES()) {
+    AttributeSelectionListPtr aSelList = selectionList(VERTEX_LIST_ID());
+    int aNbSel = aSelList->size();
+    for (int ind = 0; ind < aNbSel; ++ind) {
+      AttributeSelectionPtr aCurSel = aSelList->value(ind);
+      GeomShapePtr aWire = aCurSel->context()->shape();
+      GeomShapePtr aVertex = aCurSel->value();
+      theWireVertices[aWire].push_back(aVertex);
+    }
+  }
+  return true;
+}
+
+bool FeaturesPlugin_Fillet1D::performFillet(const GeomShapePtr& theWire,
+                                            const ListOfShape& theVertices,
+                                            const int theResultIndex)
+{
+  double aRadius = real(RADIUS_ID())->value();
+
+  // perform fillet operation
+  std::shared_ptr<GeomAlgoAPI_Fillet1D> aFilletBuilder(
+      new GeomAlgoAPI_Fillet1D(theWire, theVertices, aRadius));
+
+  std::string anError;
+  if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aFilletBuilder, getKind(), anError)) {
+    setError(anError);
+    return false;
+  }
+
+  static const std::string THE_PREFIX = "Fillet1D";
+
+  // store result
+  ResultBodyPtr aResult = document()->createBody(data(), theResultIndex);
+  ListOfShape anOriginal;
+  anOriginal.push_back(theWire);
+  FeaturesPlugin_Tools::loadModifiedShapes(aResult, anOriginal, ListOfShape(),
+                                           aFilletBuilder, aFilletBuilder->shape(), THE_PREFIX);
+  setResult(aResult, theResultIndex);
+  // store new edges generated from vertices
+  for (ListOfShape::const_iterator anIt = theVertices.begin(); anIt != theVertices.end(); ++anIt)
+    aResult->loadGeneratedShapes(aFilletBuilder, *anIt, GeomAPI_Shape::VERTEX, THE_PREFIX, true);
+
+  return true;
+}
diff --git a/src/FeaturesPlugin/FeaturesPlugin_Fillet1D.h b/src/FeaturesPlugin/FeaturesPlugin_Fillet1D.h
new file mode 100644 (file)
index 0000000..de2a380
--- /dev/null
@@ -0,0 +1,112 @@
+// Copyright (C) 2020  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef FeaturesPlugin_Fillet1D_H_
+#define FeaturesPlugin_Fillet1D_H_
+
+#include <FeaturesPlugin.h>
+
+#include <GeomAPI_Shape.h>
+#include <ModelAPI_Feature.h>
+
+#include <map>
+
+/// \class FeaturesPlugin_Fillet1D
+/// \ingroup Plugins
+/// \brief Feature for appling fillet on vertices of 3D wire.
+class FeaturesPlugin_Fillet1D : public ModelAPI_Feature
+{
+  typedef std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator> MapShapeSubs;
+
+public:
+  /// Feature kind.
+  inline static const std::string& ID()
+  {
+    static const std::string MY_ID("Fillet1D");
+    return MY_ID;
+  }
+
+  /// \return the kind of a feature.
+  FEATURESPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = FeaturesPlugin_Fillet1D::ID();
+    return MY_KIND;
+  }
+
+  inline static const std::string& CREATION_METHOD()
+  {
+    static std::string MY_CREATION_METHOD("creation_method");
+    return MY_CREATION_METHOD;
+  }
+
+  inline static const std::string CREATION_BY_WIRES()
+  {
+    static std::string MY_SINGLE_RADIUS("by_wires");
+    return MY_SINGLE_RADIUS;
+  }
+
+  inline static const std::string CREATION_BY_VERTICES()
+  {
+    static std::string MY_VARYING_RADIUS("by_vertices");
+    return MY_VARYING_RADIUS;
+  }
+
+  /// Attribute name of selected wires.
+  inline static const std::string& WIRE_LIST_ID()
+  {
+    static const std::string MY_OBJECT_LIST_ID("main_wires");
+    return MY_OBJECT_LIST_ID;
+  }
+
+  /// Attribute name of selected vertices.
+  inline static const std::string& VERTEX_LIST_ID()
+  {
+    static const std::string MY_OBJECT_LIST_ID("main_vertices");
+    return MY_OBJECT_LIST_ID;
+  }
+
+  /// Attribute name of radius.
+  inline static const std::string& RADIUS_ID()
+  {
+    static const std::string MY_RADIUS_ID("radius");
+    return MY_RADIUS_ID;
+  }
+
+  /// Request for initialization of data model of the feature: adding all attributes.
+  FEATURESPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Performs the fillet algorithm and stores it in the data structure.
+  FEATURESPLUGIN_EXPORT virtual void execute();
+
+  /// Use plugin manager for features creation.
+  FeaturesPlugin_Fillet1D();
+
+private:
+  /// Get the list of wires and fillet vertices
+  /// \retun \c false if errors occured
+  bool baseShapes(MapShapeSubs& theWireVertices);
+
+  /// Run fillet operation and store result.
+  /// \return \c false if fillet failed.
+  bool performFillet(const GeomShapePtr& theWire,
+                     const ListOfShape& theVertices,
+                     const int theResultIndex);
+};
+
+#endif
index 5f226c11b5d615d0fde56686f2628a7532dcf467..94daac07e74974f3077490e5a6007255f4529efb 100644 (file)
@@ -30,6 +30,7 @@
 #include <FeaturesPlugin_ExtrusionCut.h>
 #include <FeaturesPlugin_ExtrusionFuse.h>
 #include <FeaturesPlugin_Fillet.h>
+#include <FeaturesPlugin_Fillet1D.h>
 #include <FeaturesPlugin_Intersection.h>
 #include <FeaturesPlugin_Measurement.h>
 #include <FeaturesPlugin_MultiRotation.h>
@@ -101,6 +102,8 @@ FeaturesPlugin_Plugin::FeaturesPlugin_Plugin()
                               new FeaturesPlugin_ValidatorConcealedResult);
   aFactory->registerValidator("FeaturesPlugin_ValidatorFilletSelection",
                               new FeaturesPlugin_ValidatorFilletSelection);
+  aFactory->registerValidator("FeaturesPlugin_ValidatorFillet1DSelection",
+                              new FeaturesPlugin_ValidatorFillet1DSelection);
   aFactory->registerValidator("FeaturesPlugin_ValidatorCircular",
                               new FeaturesPlugin_ValidatorCircular);
   aFactory->registerValidator("FeaturesPlugin_ValidatorBooleanArguments",
@@ -180,6 +183,8 @@ FeaturePtr FeaturesPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new FeaturesPlugin_MultiRotation);
   } else if (theFeatureID == FeaturesPlugin_Fillet::ID()) {
     return FeaturePtr(new FeaturesPlugin_Fillet);
+  } else if (theFeatureID == FeaturesPlugin_Fillet1D::ID()) {
+    return FeaturePtr(new FeaturesPlugin_Fillet1D);
   } else if (theFeatureID == FeaturesPlugin_Measurement::ID()) {
     return FeaturePtr(new FeaturesPlugin_Measurement);
   } else if (theFeatureID == FeaturesPlugin_RemoveResults::ID()) {
index 1c7a4da1054ab4cf2a1e7ef05e816bfaef8244d9..538a5097fabcc853646fcfed7ebf099375a8dcaf 100644 (file)
@@ -54,6 +54,7 @@
 #include <GeomAPI_ShapeIterator.h>
 
 #include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_MapShapesAndAncestors.h>
 #include <GeomAlgoAPI_Prism.h>
 #include <GeomAlgoAPI_ShapeBuilder.h>
 #include <GeomAlgoAPI_ShapeTools.h>
@@ -938,6 +939,79 @@ bool FeaturesPlugin_ValidatorFilletSelection::isValid(const AttributePtr& theAtt
   return true;
 }
 
+
+//==================================================================================================
+bool FeaturesPlugin_ValidatorFillet1DSelection::isValid(const AttributePtr& theAttribute,
+                                                        const std::list<std::string>& theArguments,
+                                                        Events_InfoMessage& theError) const
+{
+  AttributeSelectionListPtr anAttrSelectionList =
+    std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
+  if (!anAttrSelectionList.get()) {
+    // LCOV_EXCL_START
+    theError =
+      "Error: This validator can only work with selection list attributes in \"Fillet\" feature.";
+    return false;
+    // LCOV_EXCL_STOP
+  }
+
+  // check each selected vertex is a sharp corner between adjacent edges,
+  // and these edges are in the same plane
+  std::map<GeomShapePtr, MapShapeToShapes> aWireSubshapes;
+  int aNbSel = anAttrSelectionList->size();
+  for (int ind = 0; ind < aNbSel; ++ind) {
+    AttributeSelectionPtr aCurSel = anAttrSelectionList->value(ind);
+    GeomShapePtr aContext = aCurSel->context()->shape();
+    GeomShapePtr aVertex = aCurSel->value();
+    // check wire already processed, if not, store all vertices and edges, sharing them
+    std::map<GeomShapePtr, MapShapeToShapes>::iterator aProcessed = aWireSubshapes.find(aContext);
+    if (aProcessed == aWireSubshapes.end()) {
+      if (aContext->shapeType() != GeomAPI_Shape::WIRE) {
+        theError = "Selected vertex is not a wire corner";
+        return false;
+      }
+      if (aVertex->shapeType() != GeomAPI_Shape::VERTEX) {
+        theError = "Selected shape it not a vertex";
+        return false;
+      }
+
+      GeomAlgoAPI_MapShapesAndAncestors aMapVE(aContext, GeomAPI_Shape::VERTEX,
+                                                         GeomAPI_Shape::EDGE);
+      aWireSubshapes[aContext] = aMapVE.map();
+      aProcessed = aWireSubshapes.find(aContext);
+    }
+
+    // check the vertex
+    MapShapeToShapes::iterator aFound = aProcessed->second.find(aVertex);
+    if (aFound == aProcessed->second.end()) {
+      theError = "Selected vertex does not exist in the wire";
+      return true;
+    }
+    else if (aFound->second.size() != 2) {
+      theError = "Vertex should be shared between 2 edges exactly";
+      return false;
+    }
+
+    ListOfShape anEdges;
+    anEdges.insert(anEdges.end(), aFound->second.begin(), aFound->second.end());
+    GeomPlanePtr aPlane = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
+    if (!aPlane) {
+      theError = "Error: Edges are not planar";
+      return false;
+    }
+
+    GeomEdgePtr anEdge1(new GeomAPI_Edge(anEdges.front()));
+    GeomEdgePtr anEdge2(new GeomAPI_Edge(anEdges.back()));
+    GeomVertexPtr aSharedVertex(new GeomAPI_Vertex(aVertex));
+    if (GeomAlgoAPI_ShapeTools::isTangent(anEdge1, anEdge2, aSharedVertex)) {
+      theError = "Error: Edges are tangent";
+      return false;
+    }
+  }
+
+  return true;
+}
+
 //==================================================================================================
 bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
                                                        const std::list<std::string>& theArguments,
index da3222d1ec7e0c4a71cbd58c73f91936ebb00de4..8d86d2a2eebee39351e72f805ededfd5431a45a3 100644 (file)
@@ -188,6 +188,22 @@ public:
                        Events_InfoMessage& theError) const;
 };
 
+/// \class FeaturesPlugin_ValidatorFillet1DSelection
+/// \ingroup Validators
+/// \brief Validates selection for 1d-fillet operation.
+class FeaturesPlugin_ValidatorFillet1DSelection : public ModelAPI_AttributeValidator
+{
+public:
+  /// \return True if the attribute is valid. It checks whether the selection
+  /// is acceptable for fillet on wire (vertex is a sharp corner).
+  /// \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.
diff --git a/src/FeaturesPlugin/Test/TestFillet1D_ErrorMsg.py b/src/FeaturesPlugin/Test/TestFillet1D_ErrorMsg.py
new file mode 100644 (file)
index 0000000..d491c37
--- /dev/null
@@ -0,0 +1,80 @@
+# Copyright (C) 2020  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+
+### 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(35.66344827586208, 18.52827586206897, -10.58758620689655, 18.52827586206897)
+Sketch_1.setHorizontal(SketchLine_1.result())
+
+### Create SketchProjection
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_2 = SketchProjection_1.createdFeature()
+
+### Create SketchArc
+SketchArc_1 = Sketch_1.addArc(-10.58758620689655, 34.59034482758621, -10.58758620689655, 18.52827586206897, 0, 46.66896551724138, True)
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchArc_1.startPoint())
+Sketch_1.setTangent(SketchLine_1.result(), SketchArc_1.results()[1])
+Sketch_1.setCoincident(SketchLine_2.result(), SketchArc_1.endPoint())
+model.do()
+
+### Create Sketch
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("YOZ"))
+
+### Create SketchLine
+SketchLine_3 = Sketch_2.addLine(46.66896551724138, 0, 49.59252615395944, 57.3324122669822)
+
+### Create SketchProjection
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "Sketch_1/SketchArc_1_2_StartVertex"), False)
+SketchPoint_1 = SketchProjection_2.createdFeature()
+Sketch_2.setCoincident(SketchLine_3.startPoint(), SketchPoint_1.result())
+model.do()
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchArc_1_2"), model.selection("EDGE", "Sketch_2/SketchLine_3")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+model.end()
+
+
+### Check errors on 1D-fillet
+vertices = ["Sketch_1/SketchLine_1_StartVertex",
+            "Sketch_2/SketchLine_3_EndVertex",
+            "[Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1]e[Wire_1_1/Modified_Edge&Sketch_1/SketchArc_1_2]e",
+            "[Wire_1_1/Modified_Edge&Sketch_1/SketchArc_1_2]e[Wire_1_1/Modified_Edge&Sketch_2/SketchLine_3]e"]
+for v in vertices:
+  model.begin()
+  Fillet1D = model.addFillet(Part_1_doc, [model.selection("VERTEX", v)], 1)
+  model.end()
+  assert(Fillet1D.feature().error() != "")
+
+### Wire has no vertices applicable for 1D-fillet
+model.begin()
+Fillet1D = model.addFillet(Part_1_doc, [model.selection("WIRE", "Wire_1_1")], 1)
+model.end()
+assert(Fillet1D.feature().error() != "")
diff --git a/src/FeaturesPlugin/Test/TestFillet1D_Vertices_1.py b/src/FeaturesPlugin/Test/TestFillet1D_Vertices_1.py
new file mode 100644 (file)
index 0000000..078f495
--- /dev/null
@@ -0,0 +1,63 @@
+# Copyright (C) 2020  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+from GeomAPI import *
+
+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, 10, 10, 10)
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_1]e[Wire_1_1/Edge_2]e")], 2)
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [6])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [12])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+### Create Fillet1D
+Fillet1D_2 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[(Wire_1_1/Edge_4)(Wire_1_1/Edge_5)2_Fillet1D_1_1]e[Wire_1_1/Edge_4]e")], 2)
+
+model.testHaveNamingByType(Fillet1D_2, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_2, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_2, 1)
+model.testNbSubResults(Fillet1D_2, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.EDGE, [7])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.VERTEX, [14])
+model.testResultsVolumes(Fillet1D_2, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
diff --git a/src/FeaturesPlugin/Test/TestFillet1D_Vertices_2.py b/src/FeaturesPlugin/Test/TestFillet1D_Vertices_2.py
new file mode 100644 (file)
index 0000000..8bd49a1
--- /dev/null
@@ -0,0 +1,74 @@
+# Copyright (C) 2020  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+from GeomAPI import *
+
+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, 10, 10, 10)
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"), model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Left]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_4]e[Wire_1_1/Edge_6]e")], 2)
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [9])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [18])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+### Create Fillet1D
+Fillet1D_2 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_1]e[Wire_1_1/Edge_3]e")], 1)
+
+model.testNbResults(Fillet1D_2, 1)
+model.testNbSubResults(Fillet1D_2, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.EDGE, [10])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.VERTEX, [20])
+model.testResultsVolumes(Fillet1D_2, [0])
+
+### Create Fillet1D
+Fillet1D_3 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[(Wire_1_1/Edge_8)4(Wire_1_1/Edge_5)4_Fillet1D_2_1]e[(Wire_1_1/Edge_8)3(Wire_1_1/Edge_7)4_Fillet1D_2_1]e")], 5)
+
+model.testHaveNamingByType(Fillet1D_3, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_3, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_3, 1)
+model.testNbSubResults(Fillet1D_3, [0])
+model.testNbSubShapes(Fillet1D_3, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_3, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_3, GeomAPI_Shape.EDGE, [11])
+model.testNbSubShapes(Fillet1D_3, GeomAPI_Shape.VERTEX, [22])
+model.testResultsVolumes(Fillet1D_3, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
diff --git a/src/FeaturesPlugin/Test/TestFillet1D_Vertices_3.py b/src/FeaturesPlugin/Test/TestFillet1D_Vertices_3.py
new file mode 100644 (file)
index 0000000..37e0ee2
--- /dev/null
@@ -0,0 +1,63 @@
+# Copyright (C) 2020  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+from GeomAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Cylinder
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10, 45)
+Wire_1_objects = [model.selection("EDGE", "[Cylinder_1_1/Face_1][Cylinder_1_1/Face_2]"), model.selection("EDGE", "[Cylinder_1_1/Face_2][Cylinder_1_1/Face_5]"), model.selection("EDGE", "[Cylinder_1_1/Face_4][Cylinder_1_1/Face_5]"), model.selection("EDGE", "[Cylinder_1_1/Face_3][Cylinder_1_1/Face_4]"), model.selection("EDGE", "[Cylinder_1_1/Face_1][Cylinder_1_1/Face_3]")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_1]e[Wire_1_1/Edge_2]e")], 1)
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [6])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [12])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+### Create Fillet1D
+Fillet1D_2 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_4]e[Wire_1_1/Edge_3]e")], 3)
+
+model.testHaveNamingByType(Fillet1D_2, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_2, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_2, 1)
+model.testNbSubResults(Fillet1D_2, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.EDGE, [7])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.VERTEX, [14])
+model.testResultsVolumes(Fillet1D_2, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
diff --git a/src/FeaturesPlugin/Test/TestFillet1D_Vertices_4.py b/src/FeaturesPlugin/Test/TestFillet1D_Vertices_4.py
new file mode 100644 (file)
index 0000000..9112fcd
--- /dev/null
@@ -0,0 +1,78 @@
+# Copyright (C) 2020  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+from GeomAPI import *
+
+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(-21.09850585253612, 7.838733928946021, 28.18352301808598, -36.47460859551143)
+
+### Create SketchLine
+SketchLine_2 = Sketch_1.addLine(28.18352301808598, -36.47460859551143, -24.86780397022334, -36.47460859551143)
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+Sketch_1.setHorizontal(SketchLine_2.result())
+
+### Create SketchArc
+SketchArc_1 = Sketch_1.addArc(-24.86780397022334, -14.15762886307242, -24.86780397022334, -36.47460859551143, -21.09850585253612, 7.838733928946021, True)
+Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchArc_1.startPoint())
+Sketch_1.setTangent(SketchLine_2.result(), SketchArc_1.results()[1])
+Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.startPoint())
+model.do()
+Wire_1_objects = [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2"), model.selection("EDGE", "Sketch_1/SketchArc_1_2")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1]e[Wire_1_1/Modified_Edge&Sketch_1/SketchLine_2]e")], 2)
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [4])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [8])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+### Create Fillet1D
+Fillet1D_2 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Fillet1D_1_1/ME:Fillet1D&Sketch_1/SketchLine_1]e[_weak_name_1_Fillet1D_1_1]e")], 20)
+
+model.testHaveNamingByType(Fillet1D_2, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_2, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_2, 1)
+model.testNbSubResults(Fillet1D_2, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.EDGE, [5])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.VERTEX, [10])
+model.testResultsVolumes(Fillet1D_2, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
diff --git a/src/FeaturesPlugin/Test/TestFillet1D_Vertices_5.py b/src/FeaturesPlugin/Test/TestFillet1D_Vertices_5.py
new file mode 100644 (file)
index 0000000..a240690
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (C) 2020  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+from GeomAPI import *
+
+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, 10, 10, 10)
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_2]e[Wire_1_1/Edge_3]e"), model.selection("VERTEX", "[Wire_1_1/Edge_3]e[Wire_1_1/Edge_4]e")], 2)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [7])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [14])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
diff --git a/src/FeaturesPlugin/Test/TestFillet1D_Vertices_6.py b/src/FeaturesPlugin/Test/TestFillet1D_Vertices_6.py
new file mode 100644 (file)
index 0000000..46ffa86
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (C) 2020  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+from GeomAPI import *
+
+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, 10, 10, 10)
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"), model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Left]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_4]e[Wire_1_1/Edge_6]e"), model.selection("VERTEX", "[Wire_1_1/Edge_2]e[Wire_1_1/Edge_4]e"), model.selection("VERTEX", "[Wire_1_1/Edge_1]e[Wire_1_1/Edge_3]e")], 2)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [11])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [22])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
diff --git a/src/FeaturesPlugin/Test/TestFillet1D_Vertices_7.py b/src/FeaturesPlugin/Test/TestFillet1D_Vertices_7.py
new file mode 100644 (file)
index 0000000..777ecc0
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (C) 2020  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+from GeomAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Cylinder
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10, 45)
+Wire_1_objects = [model.selection("EDGE", "[Cylinder_1_1/Face_1][Cylinder_1_1/Face_2]"), model.selection("EDGE", "[Cylinder_1_1/Face_2][Cylinder_1_1/Face_5]"), model.selection("EDGE", "[Cylinder_1_1/Face_4][Cylinder_1_1/Face_5]"), model.selection("EDGE", "[Cylinder_1_1/Face_3][Cylinder_1_1/Face_4]"), model.selection("EDGE", "[Cylinder_1_1/Face_1][Cylinder_1_1/Face_3]")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_1]e[Wire_1_1/Edge_2]e"), model.selection("VERTEX", "[Wire_1_1/Edge_3]e[Wire_1_1/Edge_4]e")], 2)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [7])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [14])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
diff --git a/src/FeaturesPlugin/Test/TestFillet1D_Vertices_8.py b/src/FeaturesPlugin/Test/TestFillet1D_Vertices_8.py
new file mode 100644 (file)
index 0000000..ac9bdcf
--- /dev/null
@@ -0,0 +1,67 @@
+# Copyright (C) 2020  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+from GeomAPI import *
+
+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(-21.09850585253612, 7.838733928946021, 28.18352301808598, -36.47460859551143)
+
+### Create SketchLine
+SketchLine_2 = Sketch_1.addLine(28.18352301808598, -36.47460859551143, -24.86780397022334, -36.47460859551143)
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+Sketch_1.setHorizontal(SketchLine_2.result())
+
+### Create SketchArc
+SketchArc_1 = Sketch_1.addArc(-24.86780397022334, -14.15762886307242, -24.86780397022334, -36.47460859551143, -21.09850585253612, 7.838733928946021, True)
+Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchArc_1.startPoint())
+Sketch_1.setTangent(SketchLine_2.result(), SketchArc_1.results()[1])
+Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.startPoint())
+model.do()
+Wire_1_objects = [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2"), model.selection("EDGE", "Sketch_1/SketchArc_1_2")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1]e[Wire_1_1/Modified_Edge&Sketch_1/SketchLine_2]e"), model.selection("VERTEX", "[Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1]e[Wire_1_1/Modified_Edge&Sketch_1/SketchArc_1_2]e")], 15)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [5])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [10])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
diff --git a/src/FeaturesPlugin/Test/TestFillet1D_Wire_1.py b/src/FeaturesPlugin/Test/TestFillet1D_Wire_1.py
new file mode 100644 (file)
index 0000000..aaad4ec
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (C) 2020  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+from GeomAPI import *
+
+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, 10, 10, 10)
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("WIRE", "Wire_1_1")], 2)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [9])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [18])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
diff --git a/src/FeaturesPlugin/Test/TestFillet1D_Wire_2.py b/src/FeaturesPlugin/Test/TestFillet1D_Wire_2.py
new file mode 100644 (file)
index 0000000..dea6667
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (C) 2020  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+from GeomAPI import *
+
+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, 10, 10, 10)
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"), model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Left]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("WIRE", "Wire_1_1")], 2)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [16])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [32])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
diff --git a/src/FeaturesPlugin/Test/TestFillet1D_Wire_3.py b/src/FeaturesPlugin/Test/TestFillet1D_Wire_3.py
new file mode 100644 (file)
index 0000000..834dd2b
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (C) 2020  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+from GeomAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Cylinder
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10, 45)
+Wire_1_objects = [model.selection("EDGE", "[Cylinder_1_1/Face_1][Cylinder_1_1/Face_2]"), model.selection("EDGE", "[Cylinder_1_1/Face_2][Cylinder_1_1/Face_5]"), model.selection("EDGE", "[Cylinder_1_1/Face_4][Cylinder_1_1/Face_5]"), model.selection("EDGE", "[Cylinder_1_1/Face_3][Cylinder_1_1/Face_4]"), model.selection("EDGE", "[Cylinder_1_1/Face_1][Cylinder_1_1/Face_3]")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("WIRE", "Wire_1_1")], 1)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [9])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [18])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
diff --git a/src/FeaturesPlugin/Test/TestFillet1D_Wire_4.py b/src/FeaturesPlugin/Test/TestFillet1D_Wire_4.py
new file mode 100644 (file)
index 0000000..5249526
--- /dev/null
@@ -0,0 +1,67 @@
+# Copyright (C) 2020  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+from GeomAPI import *
+
+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(-21.09850585253612, 7.838733928946021, 28.18352301808598, -36.47460859551143)
+
+### Create SketchLine
+SketchLine_2 = Sketch_1.addLine(28.18352301808598, -36.47460859551143, -24.86780397022334, -36.47460859551143)
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+Sketch_1.setHorizontal(SketchLine_2.result())
+
+### Create SketchArc
+SketchArc_1 = Sketch_1.addArc(-24.86780397022334, -14.15762886307242, -24.86780397022334, -36.47460859551143, -21.09850585253612, 7.838733928946021, True)
+Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchArc_1.startPoint())
+Sketch_1.setTangent(SketchLine_2.result(), SketchArc_1.results()[1])
+Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.startPoint())
+model.do()
+Wire_1_objects = [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2"), model.selection("EDGE", "Sketch_1/SketchArc_1_2")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("WIRE", "Wire_1_1")], 2)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [5])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [10])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
diff --git a/src/FeaturesPlugin/fillet1d_widget.xml b/src/FeaturesPlugin/fillet1d_widget.xml
new file mode 100644 (file)
index 0000000..d967063
--- /dev/null
@@ -0,0 +1,40 @@
+<source>
+  <toolbox id="creation_method">
+    <box id="by_wires"
+         title="Wires"
+         tooltip="Fillet each sharp corner of the wire"
+         icon="icons/Features/fillet1d_wire.png">
+      <multi_selector id="main_wires"
+                      label="Wires"
+                      icon=""
+                      tooltip="Select wires"
+                      shape_types="wires"
+                      use_choice="false"
+                      concealment="true">
+        <validator id="PartSet_DifferentObjects"/>
+      </multi_selector>
+    </box>
+    <box id="by_vertices"
+         title="Vertices"
+         tooltip="Fillet the specified corners of the wire"
+         icon="icons/Features/fillet1d_points.png">
+      <multi_selector id="main_vertices"
+                      label="Vertices"
+                      icon=""
+                      tooltip="Select vertices"
+                      shape_types="vertices"
+                      use_choice="false"
+                      concealment="true">
+        <validator id="PartSet_DifferentObjects"/>
+        <validator id="FeaturesPlugin_ValidatorFillet1DSelection"/>
+      </multi_selector>
+    </box>
+  </toolbox>
+  <doublevalue id="radius"
+               label="Radius"
+               tooltip="Fillet radius."
+               min="0"
+               default="0">
+    <validator id="GeomValidators_Positive"/>
+  </doublevalue>
+</source>
diff --git a/src/FeaturesPlugin/icons/fillet1d.png b/src/FeaturesPlugin/icons/fillet1d.png
new file mode 100644 (file)
index 0000000..a94aba3
Binary files /dev/null and b/src/FeaturesPlugin/icons/fillet1d.png differ
diff --git a/src/FeaturesPlugin/icons/fillet1d_points.png b/src/FeaturesPlugin/icons/fillet1d_points.png
new file mode 100644 (file)
index 0000000..c0f751a
Binary files /dev/null and b/src/FeaturesPlugin/icons/fillet1d_points.png differ
diff --git a/src/FeaturesPlugin/icons/fillet1d_wire.png b/src/FeaturesPlugin/icons/fillet1d_wire.png
new file mode 100644 (file)
index 0000000..62eed22
Binary files /dev/null and b/src/FeaturesPlugin/icons/fillet1d_wire.png differ
index 5fbe8a1f42adb127c95d4a8831b6b691944d747d..10bd904de42bff3ec00085ed4642420a1ea9fb88 100644 (file)
       </feature>
     </group>
     <group id="Features">
+      <feature id="Fillet1D"
+               title="1D-fillet"
+               tooltip="Perform fillet on vertices of a wire"
+               icon="icons/Features/fillet1d.png"
+               auto_preview="true"
+               apply_continue="true"
+               helpfile="fillet1dFeature.html">
+        <source path="fillet1d_widget.xml"/>
+      </feature>
       <feature id="Fillet" title="Fillet" tooltip="Perform fillet on face or edge"
                icon="icons/Features/fillet.png" auto_preview="true" helpfile="filletFeature.html">
         <source path="fillet_widget.xml"/>
index bf5805e1527403e644e1d68aa091501c78c1a200..3bb282186731277d75ac6eb9c9725dfc606eb9cc 100644 (file)
@@ -23,6 +23,7 @@
 #include <ModelAPI_ResultBody.h>
 #include <ModelAPI_Tools.h>
 
+#include <GeomAPI_Edge.h>
 #include <GeomAPI_Shape.h>
 #include <GeomAPI_ShapeExplorer.h>
 #include <GeomAPI_Wire.h>
index 9364605b9b1b95c6cc6862e8145285e6024ff76b..03e44e8084844cc8f90ff5c4f605805d1f581d6a 100644 (file)
@@ -461,6 +461,22 @@ void GeomAPI_Edge::setLastPointTolerance(const double theTolerance)
   BRep_Builder().UpdateVertex(aVLast, theTolerance);
 }
 
+double GeomAPI_Edge::firstPointTolerance() const
+{
+  TopoDS_Edge anEdge = impl<TopoDS_Edge>();
+  TopoDS_Vertex aVFirst, aVLast;
+  TopExp::Vertices(anEdge, aVFirst, aVLast);
+  return BRep_Tool::Tolerance(aVFirst);
+}
+
+double GeomAPI_Edge::lastPointTolerance() const
+{
+  TopoDS_Edge anEdge = impl<TopoDS_Edge>();
+  TopoDS_Vertex aVFirst, aVLast;
+  TopExp::Vertices(anEdge, aVFirst, aVLast);
+  return BRep_Tool::Tolerance(aVLast);
+}
+
 GeomPointPtr GeomAPI_Edge::middlePoint() const
 {
   GeomPointPtr aMiddlePoint;
index 3e926d8d04e5d109cb512957bc4eeed805425c10..7823f97b37805b1fdd3ac0f29abfad0deba19c8c 100644 (file)
@@ -135,6 +135,10 @@ public:
   GEOMAPI_EXPORT
   void setLastPointTolerance(const double theTolerance);
 
+  GEOMAPI_EXPORT double firstPointTolerance() const;
+
+  GEOMAPI_EXPORT double lastPointTolerance() const;
+
   /// Return middle point on the edge
   GEOMAPI_EXPORT
   virtual std::shared_ptr<GeomAPI_Pnt> middlePoint() const;
index efd37a0ae5b70db027a07debd24623ad33b46089..edae958658d5c3e13b142abb40c9ae9be09bc0df 100644 (file)
@@ -18,6 +18,9 @@
 //
 
 #include <GeomAPI_WireExplorer.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Vertex.h>
 #include <GeomAPI_Wire.h>
 
 #include <BRepTools_WireExplorer.hxx>
@@ -49,11 +52,19 @@ void GeomAPI_WireExplorer::next()
   MY_EXPLORER->Next();
 }
 
-std::shared_ptr<GeomAPI_Shape> GeomAPI_WireExplorer::current()
+std::shared_ptr<GeomAPI_Edge> GeomAPI_WireExplorer::current()
+{
+  const TopoDS_Edge& aShape = MY_EXPLORER->Current();
+  std::shared_ptr<GeomAPI_Edge> aGeomShape(new GeomAPI_Edge());
+  aGeomShape->setImpl(new TopoDS_Edge(aShape));
+  return aGeomShape;
+}
+
+std::shared_ptr<GeomAPI_Vertex> GeomAPI_WireExplorer::currentVertex()
 {
-  const TopoDS_Shape& aShape = MY_EXPLORER->Current();
-  std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape());
-  aGeomShape->setImpl(new TopoDS_Shape(aShape));
+  const TopoDS_Vertex& aShape = MY_EXPLORER->CurrentVertex();
+  std::shared_ptr<GeomAPI_Vertex> aGeomShape(new GeomAPI_Vertex());
+  aGeomShape->setImpl(new TopoDS_Vertex(aShape));
   return aGeomShape;
 }
 
index 4328582996ec4e4f96cc550cb74aa6a344389bd6..b68cee6dec9da6564420d21114beffc0984af715 100644 (file)
@@ -23,7 +23,9 @@
 #include <GeomAPI.h>
 #include <GeomAPI_Interface.h>
 
+class GeomAPI_Edge;
 class GeomAPI_Shape;
+class GeomAPI_Vertex;
 class GeomAPI_Wire;
 
 /** \class GeomAPI_WireExplorer
@@ -53,9 +55,13 @@ public:
   /// if there are no more shapes to explore.
   GEOMAPI_EXPORT void next();
 
-  /// \return the current shape in the exploration or empty pointer
+  /// \return the current edge in the exploration or empty pointer
   /// if this explorer has no more shapes to explore.
-  GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Shape> current();
+  GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Edge> current();
+
+  /// \return the current vertex in the exploration or empty pointer
+  /// if this explorer has no more shapes to explore.
+  GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Vertex> currentVertex();
 
   /// Clears the content of the explorer. It will return False on more().
   GEOMAPI_EXPORT void clear();
index 391acc8f641b11991f567fbccd7aa4a64b7ecf3b..50546b4f2b3b0cec6850afff72f114ca4b97bcd8 100644 (file)
@@ -75,6 +75,7 @@ SET(PROJECT_HEADERS
     GeomAlgoAPI_Circ2dBuilder.h
     GeomAlgoAPI_UnifySameDomain.h
     GeomAlgoAPI_Fillet.h
+    GeomAlgoAPI_Fillet1D.h
     GeomAlgoAPI_SortListOfShapes.h
     GeomAlgoAPI_Filling.h
     GeomAlgoAPI_CurveBuilder.h
@@ -139,6 +140,7 @@ SET(PROJECT_SOURCES
     GeomAlgoAPI_Circ2dBuilder.cpp
     GeomAlgoAPI_UnifySameDomain.cpp
     GeomAlgoAPI_Fillet.cpp
+    GeomAlgoAPI_Fillet1D.cpp
     GeomAlgoAPI_SortListOfShapes.cpp
     GeomAlgoAPI_Filling.cpp
     GeomAlgoAPI_CurveBuilder.cpp
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Fillet1D.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Fillet1D.cpp
new file mode 100644 (file)
index 0000000..5eca5b8
--- /dev/null
@@ -0,0 +1,201 @@
+// Copyright (C) 2020  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include <GeomAlgoAPI_Fillet1D.h>
+#include <GeomAlgoAPI_MapShapesAndAncestors.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Pln.h>
+#include <GeomAPI_Pnt.h>
+#include <GeomAPI_Wire.h>
+#include <GeomAPI_WireExplorer.h>
+
+#include <GEOMImpl_Fillet1d.hxx>
+
+#include <BRep_Builder.hxx>
+#include <BRepTools_WireExplorer.hxx>
+#include <ShapeFix_Wire.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Wire.hxx>
+
+static GeomShapePtr convert(const TopoDS_Shape& theShape)
+{
+  GeomShapePtr aNewShape(new GeomAPI_Shape);
+  aNewShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(theShape));
+  return aNewShape;
+}
+
+static void substituteNewEdge(GeomEdgePtr theEdge,
+    std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator>& theMap)
+{
+  std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator>::iterator anIt = theMap.begin();
+  for (; anIt != theMap.end(); ++anIt) {
+    for (ListOfShape::iterator aEIt = anIt->second.begin(); aEIt != anIt->second.end(); ++aEIt)
+      if (theEdge->isEqual(*aEIt)) {
+        // substitute edge and stop iteration
+        *aEIt = theEdge;
+        return;
+      }
+  }
+}
+
+
+GeomAlgoAPI_Fillet1D::GeomAlgoAPI_Fillet1D(const GeomShapePtr& theBaseWire,
+                                           const ListOfShape&  theFilletVertices,
+                                           const double        theFilletRadius)
+{
+  build(theBaseWire, theFilletVertices, theFilletRadius);
+}
+
+void GeomAlgoAPI_Fillet1D::build(const GeomShapePtr& theBaseWire,
+                                 const ListOfShape&  theFilletVertices,
+                                 const double        theRadius)
+{
+  if (!theBaseWire || theFilletVertices.empty() || theRadius < 0.)
+    return;
+
+  GeomAlgoAPI_MapShapesAndAncestors aMapVE(theBaseWire, GeomAPI_Shape::VERTEX,
+                                                        GeomAPI_Shape::EDGE);
+
+  for (ListOfShape::const_iterator aVIt = theFilletVertices.begin();
+       aVIt != theFilletVertices.end(); ++aVIt) {
+    // get edges to perform fillet
+    MapShapeToShapes::const_iterator aVE = aMapVE.map().find(*aVIt);
+    if (aVE == aMapVE.map().end())
+      continue;
+    ListOfShape anEdges;
+    for (SetOfShapes::const_iterator aEIt = aVE->second.begin();
+         aEIt != aVE->second.end(); ++aEIt) {
+      ListOfShape aNewEdges;
+      modified(*aEIt, aNewEdges);
+      if (aNewEdges.empty())
+        anEdges.push_back(*aEIt);
+      else
+        anEdges.insert(anEdges.end(), aNewEdges.begin(), aNewEdges.end());
+    }
+
+    GeomPlanePtr aPlane = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
+    if (!aPlane)
+      return; // non-planar edges
+
+    TopoDS_Edge anEdge1 = TopoDS::Edge(anEdges.front()->impl<TopoDS_Shape>());
+    TopoDS_Edge anEdge2 = TopoDS::Edge(anEdges.back()->impl<TopoDS_Shape>());
+
+    // create fillet builder
+    GEOMImpl_Fillet1d aFilletBuilder(anEdge1, anEdge2, aPlane->impl<gp_Pln>());
+    if (!aFilletBuilder.Perform(theRadius))
+      return; // fillet is failed, no way to continue
+
+    GeomPointPtr aPoint = aVE->first->vertex()->point();
+    TopoDS_Edge aFilletEdge = aFilletBuilder.Result(aPoint->impl<gp_Pnt>(), anEdge1, anEdge2);
+
+    // store modified shapes
+    myGenerated[aVE->first].push_back(convert(aFilletEdge));
+    SetOfShapes::const_iterator aEIt = aVE->second.begin();
+    myModified[*aEIt].clear();
+    myModified[*aEIt].push_back(convert(anEdge1));
+    myModified[*(++aEIt)].clear();
+    myModified[*aEIt].push_back(convert(anEdge2));
+  }
+
+  // compose a new wire
+  TopoDS_Wire aNewWire;
+  BRep_Builder aBuilder;
+  aBuilder.MakeWire(aNewWire);
+  GeomWirePtr aBaseWire = theBaseWire->wire();
+  GeomAPI_WireExplorer aWExp(aBaseWire);
+  GeomShapePtr aBaseFirstEdge = aWExp.current();
+  for (; aWExp.more(); aWExp.next()) {
+    ListOfShape aNewEdges;
+    modified(aWExp.current(), aNewEdges);
+    if (aNewEdges.empty())
+      aNewEdges.push_back(aWExp.current());
+    for (ListOfShape::iterator anIt = aNewEdges.begin(); anIt != aNewEdges.end(); ++anIt)
+      aBuilder.Add(aNewWire, TopoDS::Edge((*anIt)->impl<TopoDS_Shape>()));
+  }
+  for (MapModified::iterator aGenIt = myGenerated.begin(); aGenIt != myGenerated.end(); ++aGenIt) {
+    for (ListOfShape::iterator anIt = aGenIt->second.begin(); anIt != aGenIt->second.end(); ++anIt)
+      aBuilder.Add(aNewWire, TopoDS::Edge((*anIt)->impl<TopoDS_Shape>()));
+  }
+  // fix the wire connectivity
+  ShapeFix_Wire aFixWire;
+  aFixWire.Load(aNewWire);
+  aFixWire.ClosedWireMode() = aBaseWire->isClosed();
+  aFixWire.FixReorder();
+  aNewWire = aFixWire.WireAPIMake();
+  if (aNewWire.IsNull())
+    return;
+
+  // update the map of modified shapes, because the edges are changed by ShapeFix
+  for (BRepTools_WireExplorer anExp(aNewWire); anExp.More(); anExp.Next()) {
+    GeomEdgePtr aCurrent(new GeomAPI_Edge);
+    aCurrent->setImpl(new TopoDS_Edge(anExp.Current()));
+    substituteNewEdge(aCurrent, myGenerated);
+    substituteNewEdge(aCurrent, myModified);
+  }
+
+  // rebuild the wire once again to get the first edge of fillet wire correspond
+  // to the first edge of original wire
+  TopoDS_Edge aFirstEdge = TopoDS::Edge(aBaseFirstEdge->impl<TopoDS_Shape>());
+  ListOfShape aNewEdges;
+  modified(aBaseFirstEdge, aNewEdges);
+  if (!aNewEdges.empty())
+    aFirstEdge = TopoDS::Edge(aNewEdges.front()->impl<TopoDS_Shape>());
+  TopTools_ListOfShape aKeptForEnd;
+  BRepTools_WireExplorer aNewExp(aNewWire);
+  for (; aNewExp.More(); aNewExp.Next())
+    if (aNewExp.Current().IsEqual(aFirstEdge))
+      break;
+  if (aNewExp.More()) {
+    TopoDS_Wire aReorderedWire;
+    aBuilder.MakeWire(aReorderedWire);
+    for (; aNewExp.More(); aNewExp.Next())
+      aBuilder.Add(aReorderedWire, aNewExp.Current());
+    for (aNewExp.Init(aNewWire); aNewExp.More(); aNewExp.Next()) {
+      if (aNewExp.Current().IsEqual(aFirstEdge))
+        break;
+      aBuilder.Add(aReorderedWire, aNewExp.Current());
+    }
+    aNewWire = aReorderedWire;
+  }
+
+  std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
+  aShape->setImpl(new TopoDS_Shape(aNewWire));
+  myModified[theBaseWire].push_back(aShape);
+
+  setShape(aShape);
+  setDone(true);
+}
+
+void GeomAlgoAPI_Fillet1D::generated(const GeomShapePtr theOldShape,
+                                     ListOfShape& theNewShapes)
+{
+  MapModified::iterator aFound = myGenerated.find(theOldShape);
+  if (aFound != myGenerated.end())
+    theNewShapes = aFound->second;
+}
+
+void GeomAlgoAPI_Fillet1D::modified(const GeomShapePtr theOldShape,
+                                     ListOfShape& theNewShapes)
+{
+  MapModified::iterator aFound = myModified.find(theOldShape);
+  if (aFound != myModified.end())
+    theNewShapes = aFound->second;
+}
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Fillet1D.h b/src/GeomAlgoAPI/GeomAlgoAPI_Fillet1D.h
new file mode 100644 (file)
index 0000000..b386bc4
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright (C) 2020  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef GeomAlgoAPI_Fillet1D_H_
+#define GeomAlgoAPI_Fillet1D_H_
+
+#include <GeomAlgoAPI.h>
+#include <GeomAlgoAPI_MakeShape.h>
+
+#include <GeomAPI_Shape.h>
+
+/// \class GeomAlgoAPI_Fillet1D
+/// \ingroup DataAlgo
+/// \brief Perform fillet on vertices of a wire
+class GeomAlgoAPI_Fillet1D : public GeomAlgoAPI_MakeShape
+{
+  typedef std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator> MapModified;
+
+public:
+  /// Run fillet operation on a set of vertices with fixed radius.
+  /// \param theBaseWire        a changing Wire
+  /// \param theFilletVertices  list of edges the fillet is performed on
+  /// \param theFilletRadius    radius of the fillet
+  GEOMALGOAPI_EXPORT GeomAlgoAPI_Fillet1D(const GeomShapePtr& theBaseWire,
+                                          const ListOfShape&  theFilletVertices,
+                                          const double        theFilletRadius);
+
+  /// \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);
+
+  /// \return the list of shapes modified from the shape \a theShape.
+  /// \param[in] theOldShape base shape.
+  /// \param[out] theNewShapes shapes modified from \a theShape. Does not cleared!
+  GEOMALGOAPI_EXPORT virtual void modified(const GeomShapePtr theOldShape,
+                                           ListOfShape& theNewShapes);
+
+private:
+  /// Perform 1d-fillet on wire
+  /// \param theBaseWire        a changing wire
+  /// \param theFilletVertices  list of vertices of filler
+  /// \param theRadius          fillet radius
+  void build(const GeomShapePtr& theBaseWire,
+             const ListOfShape&  theFilletVertices,
+             const double        theRadius);
+
+private:
+  MapModified myGenerated;
+  MapModified myModified;
+};
+
+#endif
index 77aeaad15ea46a7d73a3b2580c5785babdd27aaa..0a7037184e5e75364ffaef84fbdbf65f8bd6e1ab 100644 (file)
@@ -50,6 +50,7 @@
 #include <BRepTopAdaptor_FClass2d.hxx>
 #include <BRepClass_FaceClassifier.hxx>
 #include <BRepLib_CheckCurveOnSurface.hxx>
+#include <BRepLProp.hxx>
 
 #include <BOPAlgo_Builder.hxx>
 
@@ -857,6 +858,44 @@ std::shared_ptr<GeomAPI_Shape>
   return anOuterWire;
 }
 
+//==================================================================================================
+static bool boundaryOfEdge(const std::shared_ptr<GeomAPI_Edge> theEdge,
+                          const std::shared_ptr<GeomAPI_Vertex> theVertex,
+                          double& theParam)
+{
+  GeomPointPtr aPoint = theVertex->point();
+  GeomPointPtr aFirstPnt = theEdge->firstPoint();
+  double aFirstPntTol = theEdge->firstPointTolerance();
+  GeomPointPtr aLastPnt = theEdge->lastPoint();
+  double aLastPntTol = theEdge->lastPointTolerance();
+
+  double aFirst, aLast;
+  theEdge->getRange(aFirst, aLast);
+
+  bool isFirst = aPoint->distance(aFirstPnt) <= aFirstPntTol;
+  bool isLast = aPoint->distance(aLastPnt) <= aLastPntTol;
+  if (isFirst)
+    theParam = aFirst;
+  else if (isLast)
+    theParam = aLast;
+
+  return isFirst != isLast;
+}
+
+bool GeomAlgoAPI_ShapeTools::isTangent(const std::shared_ptr<GeomAPI_Edge> theEdge1,
+                                       const std::shared_ptr<GeomAPI_Edge> theEdge2,
+                                       const std::shared_ptr<GeomAPI_Vertex> theTgPoint)
+{
+  double aParE1 = 0, aParE2 = 0;
+  if (!boundaryOfEdge(theEdge1, theTgPoint, aParE1) ||
+      !boundaryOfEdge(theEdge2, theTgPoint, aParE2))
+    return false;
+
+  BRepAdaptor_Curve aC1(theEdge1->impl<TopoDS_Edge>());
+  BRepAdaptor_Curve aC2(theEdge2->impl<TopoDS_Edge>());
+  return BRepLProp::Continuity(aC1, aC2, aParE1, aParE2) >= GeomAbs_G1;
+}
+
 //==================================================================================================
 bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr<GeomAPI_Edge> theEdge,
                                         const std::shared_ptr<GeomAPI_Face> theFace)
index 49b3432445b394744ae06d5faa901f6dde0dc01f..90a065b0b5f282e15e67f853820cbf269ccd1cb7 100644 (file)
@@ -141,6 +141,11 @@ public:
   GEOMALGOAPI_EXPORT static
     std::shared_ptr<GeomAPI_Shape> getFaceOuterWire(const std::shared_ptr<GeomAPI_Shape> theFace);
 
+  /// \return \c true if edges are tangent in the specified point
+  GEOMALGOAPI_EXPORT static bool isTangent(const std::shared_ptr<GeomAPI_Edge> theEdge1,
+                                           const std::shared_ptr<GeomAPI_Edge> theEdge2,
+                                           const std::shared_ptr<GeomAPI_Vertex> theTgPoint);
+
   /// \return true if edge is parallel to face.
   GEOMALGOAPI_EXPORT static bool isParallel(const std::shared_ptr<GeomAPI_Edge> theEdge,
                                             const std::shared_ptr<GeomAPI_Face> theFace);
index 7a7da432be01843ba4f29216300a6563f42527ec..e28bf968e424ae1e2e3301f48531794fe2984bd8 100644 (file)
@@ -22,10 +22,12 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
 SET(PROJECT_HEADERS
     GeomAlgoImpl.h
     GEOMAlgo_Splitter.hxx
+    GEOMImpl_Fillet1d.hxx
 )
 
 SET(PROJECT_SOURCES
     GEOMAlgo_Splitter.cxx
+    GEOMImpl_Fillet1d.cxx
 )
 
 SET(PROJECT_LIBRARIES
diff --git a/src/GeomAlgoImpl/GEOMImpl_Fillet1d.cxx b/src/GeomAlgoImpl/GEOMImpl_Fillet1d.cxx
new file mode 100644 (file)
index 0000000..b9aef21
--- /dev/null
@@ -0,0 +1,909 @@
+// Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// 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
+//
+
+//  File   : GEOMImpl_Fillet1d.cxx
+//  Module : GEOMImpl
+
+#include "GEOMImpl_Fillet1d.hxx"
+
+#include <BRep_Tool.hxx>
+#include <BRepAdaptor_Curve.hxx>
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <ElCLib.hxx>
+#include <ElSLib.hxx>
+#include <gp_Circ.hxx>
+#include <Geom2d_Line.hxx>
+#include <Geom2dAPI_ProjectPointOnCurve.hxx>
+#include <Geom2dAPI_InterCurveCurve.hxx>
+#include <GeomAPI_ProjectPointOnCurve.hxx>
+#include <GeomProjLib.hxx>
+#include <Geom_Circle.hxx>
+#include <Precision.hxx>
+#include <TColStd_ListIteratorOfListOfReal.hxx>
+#include <IntRes2d_IntersectionSegment.hxx>
+#include <TopExp.hxx>
+
+#include <Standard_NotImplemented.hxx>
+
+
+/**
+ * This function returns Standard_True if it is possible to divide edge, i.e.
+ * if one parameter either start or end one is inside the edge. This function
+ * is used in the method GEOMImpl_Fillet1d::Result.
+ *
+ * \param theEdge the edge
+ * \param theStart the start parameter
+ * \param theEnd the end parameter
+ * \return Standard_True if it is possible to split edge;
+ *         Standard_False otherwise.
+ */
+static Standard_Boolean IsDivideEdge(const TopoDS_Edge   &theEdge,
+                                     const Standard_Real  theStart,
+                                     const Standard_Real  theEnd)
+{
+  Standard_Real      aFirst;
+  Standard_Real      aLast;
+  Handle(Geom_Curve) aCurve    = BRep_Tool::Curve(theEdge, aFirst, aLast);
+  gp_Pnt             aPStart   = aCurve->Value(theStart);
+  gp_Pnt             aPEnd     = aCurve->Value(theEnd);
+  TopoDS_Vertex      aVFirst   = TopExp::FirstVertex(theEdge);
+  TopoDS_Vertex      aVLast    = TopExp::LastVertex(theEdge);
+  Standard_Real      aTolFirst = BRep_Tool::Tolerance(aVFirst);
+  Standard_Real      aTolLast  = BRep_Tool::Tolerance(aVLast);
+  Standard_Real      aTolConf  = Precision::Confusion();
+  gp_Pnt             aPFirst   = BRep_Tool::Pnt(aVFirst);
+  gp_Pnt             aPLast    = BRep_Tool::Pnt(aVLast);
+  Standard_Real      aDistSF   = aPStart.Distance(aPFirst);
+  Standard_Real      aDistSL   = aPStart.Distance(aPLast);
+  Standard_Real      aDistEF   = aPEnd.Distance(aPFirst);
+  Standard_Real      aDistEL   = aPEnd.Distance(aPLast);
+  Standard_Boolean   isSplit   = Standard_True;
+
+  if (aDistSF <= aTolFirst + aTolConf ||
+      aDistSL <= aTolLast  + aTolConf) {
+    if (aDistEF <= aTolFirst + aTolConf ||
+        aDistEL <= aTolLast  + aTolConf) {
+
+      isSplit = Standard_False;
+      // in this case the original edge is thrown, and distance (gap) from new arc end
+      // to a vertex of original wire can reach (aVertexTolerance + Precision::Confusion()).
+      // Resulting wire is fixed (Mantis issue 0023411) in GEOMImpl_Fillet1dDriver::MakeFillet()
+    }
+  }
+
+  return isSplit;
+}
+
+/**
+ * class GEOMImpl_Fillet1d
+ */
+
+//=======================================================================
+//function : Constructor
+//purpose  :
+//=======================================================================
+GEOMImpl_Fillet1d::GEOMImpl_Fillet1d(const TopoDS_Edge& theEdge1,
+                                     const TopoDS_Edge& theEdge2,
+                                     const gp_Pln& thePlane)
+: myEdgesExchnged( Standard_False )
+{
+  myPlane = new Geom_Plane(thePlane);
+
+  BRepAdaptor_Curve aBAC1(theEdge1);
+  BRepAdaptor_Curve aBAC2(theEdge2);
+  if (aBAC1.GetType() < aBAC2.GetType())
+  { // first curve must be more complicated
+    myEdge1 = theEdge2;
+    myEdge2 = theEdge1;
+    myEdgesExchnged = Standard_True;
+  }
+  else
+  {
+    myEdge1 = theEdge1;
+    myEdge2 = theEdge2;
+  }
+
+  Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(myEdge1, myStart1, myEnd1);
+  Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(myEdge2, myStart2, myEnd2);
+
+  myCurve1 = GeomProjLib::Curve2d(aCurve1, myStart1, myEnd1, myPlane);
+  myCurve2 = GeomProjLib::Curve2d(aCurve2, myStart2, myEnd2, myPlane);
+
+  while (myCurve1->IsPeriodic() && myStart1 >= myEnd1)
+    myEnd1 += myCurve1->Period();
+  while (myCurve2->IsPeriodic() && myStart2 >= myEnd2)
+    myEnd2 += myCurve2->Period();
+
+  if (aBAC1.GetType() == aBAC2.GetType())
+  {
+    if (myEnd2 - myStart2 < myEnd1 - myStart1)
+    { // first curve must be parametrically shorter
+      TopoDS_Edge anEdge = myEdge1;
+      myEdge1 = myEdge2;
+      myEdge2 = anEdge;
+      Handle(Geom2d_Curve) aCurve = myCurve1;
+      myCurve1 = myCurve2;
+      myCurve2 = aCurve;
+      Standard_Real a = myStart1;
+      myStart1 = myStart2;
+      myStart2 = a;
+      a = myEnd1;
+      myEnd1 = myEnd2;
+      myEnd2 = a;
+      myEdgesExchnged = Standard_True;
+    }
+  }
+}
+
+//=======================================================================
+//function : isRadiusIntersected
+//purpose  : local function
+//=======================================================================
+static Standard_Boolean isRadiusIntersected(const Handle(Geom2d_Curve)& theCurve,
+                                            const gp_Pnt2d theStart,
+                                            const gp_Pnt2d theEnd,
+                                            const Standard_Boolean theStartConnected)
+{
+  const Standard_Real aTol = Precision::Confusion();
+  const Standard_Real anAngTol = Precision::Angular();
+  Handle(Geom2d_Line) aRadiusLine = new Geom2d_Line (theStart, gp_Dir2d(gp_Vec2d(theStart, theEnd)));
+  Geom2dAPI_InterCurveCurve anInter (theCurve, aRadiusLine, aTol);
+  Standard_Integer a;
+  gp_Pnt2d aPoint;
+  for(a = anInter.NbPoints(); a > 0; a--)
+  {
+    aPoint = anInter.Point(a);
+    if ( aPoint.Distance(theStart) < aTol && !theStartConnected )
+      return Standard_True;
+    if (aPoint.Distance(theEnd) < aTol * 200)
+      return Standard_True;
+    if (gp_Vec2d(aPoint, theStart).IsOpposite(gp_Vec2d(aPoint, theEnd), anAngTol))
+      return Standard_True;
+  }
+  Handle(Geom2d_Curve) aCurve;
+  for(a = anInter.NbSegments(); a > 0; a--)
+  {
+    // Porting to DEV version of OCCT 10.02.2017 BEGIN
+    Standard_NotImplemented::Raise("The treatment of tangential intersection is not implemented");
+    // Porting to DEV version of OCCT 10.02.2017 END
+  }
+  return Standard_False;
+}
+
+
+//=======================================================================
+//function : fillPoint
+//purpose  :
+//=======================================================================
+void GEOMImpl_Fillet1d::fillPoint(GEOMImpl_Fillet1dPoint* thePoint)
+{
+  gp_Pnt2d aPoint;
+  gp_Vec2d aVec;
+  const Standard_Real aTol = Precision::Confusion();
+  myCurve1->D1(thePoint->GetParam(), aPoint, aVec);
+  if (aVec.SquareMagnitude() < aTol)
+    return;
+
+  gp_Vec2d aPerp(((myStartSide)?-1:1) * aVec.Y(), ((myStartSide)?1:-1) * aVec.X());
+  aPerp.Normalize();
+  aPerp.Multiply(myRadius);
+  gp_Pnt2d aCenter = aPoint.Translated(aPerp);
+  thePoint->SetCenter(aCenter);
+
+  // on the intersection point
+  Standard_Boolean aValid = Standard_True;
+  Geom2dAPI_ProjectPointOnCurve aProjInt(aPoint, myCurve2);
+  if (aProjInt.NbPoints() && aPoint.Distance(aProjInt.NearestPoint()) < aTol)
+    aValid = Standard_False;
+  else
+    aValid = !isRadiusIntersected(myCurve2, aPoint, aCenter, Standard_True);
+
+  Geom2dAPI_ProjectPointOnCurve aProj(aCenter, myCurve2);
+  Standard_Integer a, aNB = aProj.NbPoints();
+  for(a = aNB; a > 0; a--)
+  {
+    if (aPoint.Distance(aProj.Point(a)) < aTol)
+      continue;
+
+    Standard_Boolean aValid2 = aValid;
+    if (aValid2)
+      aValid2 = !isRadiusIntersected(myCurve1, aCenter, aProj.Point(a), Standard_False);
+
+    // checking the right parameter
+    Standard_Real aParam = aProj.Parameter(a);
+    while(myCurve2->IsPeriodic() && aParam < myStart2)
+      aParam += myCurve2->Period();
+
+    thePoint->AddValue(aProj.Distance(a) * aProj.Distance(a) - myRadius * myRadius,
+                       (aParam >= myStart2 && aParam <= myEnd2 && aValid2));
+    if (fabs(fabs(aProj.Distance(a)) - myRadius) < aTol)
+      thePoint->SetParam2(aParam);
+  }
+}
+
+//=======================================================================
+//function : fillDiff
+//purpose  :
+//=======================================================================
+void GEOMImpl_Fillet1d::fillDiff(GEOMImpl_Fillet1dPoint* thePoint, Standard_Real theDiffStep, Standard_Boolean theFront)
+{
+  GEOMImpl_Fillet1dPoint* aDiff =
+    new GEOMImpl_Fillet1dPoint(thePoint->GetParam() + (theFront?(theDiffStep):(-theDiffStep)));
+  fillPoint(aDiff);
+  if (!thePoint->ComputeDifference(aDiff))
+  {
+    aDiff->SetParam(thePoint->GetParam() + (theFront?(-theDiffStep):(theDiffStep)));
+    fillPoint(aDiff);
+    thePoint->ComputeDifference(aDiff);
+  }
+  delete aDiff;
+}
+
+//=======================================================================
+//function : Perform
+//purpose  :
+//=======================================================================
+Standard_Boolean GEOMImpl_Fillet1d::Perform(const Standard_Real theRadius)
+{
+  myDegreeOfRecursion = 0;
+  myResultParams.Clear();
+  myResultOrientation.Clear();
+
+  Standard_Integer aNBSteps = 100;
+  Geom2dAdaptor_Curve aGAC(myCurve1);
+  switch (aGAC.GetType())
+  {
+    case GeomAbs_Line:
+      aNBSteps = 2;
+      break;
+    case GeomAbs_Circle:
+      aNBSteps = 4;
+      break;
+    case GeomAbs_Ellipse:
+      aNBSteps = 5;
+      break;
+    case GeomAbs_BezierCurve:
+    case GeomAbs_BSplineCurve:
+      aNBSteps = 2 + aGAC.Degree() * aGAC.NbPoles();
+      break;
+    default: // unknown: maximum
+      aNBSteps = 100;
+  }
+
+  myRadius = theRadius;
+
+  // Compute the intervals.
+  const Standard_Real aTol = Precision::Confusion();
+  Geom2dAPI_InterCurveCurve anAPIInter(myCurve1, myCurve2, aTol);
+  const Geom2dInt_GInter &anInter = anAPIInter.Intersector();
+  Standard_Integer aNb = anInter.NbPoints();
+  Standard_Integer i;
+  TColStd_ListOfReal aParams;
+  TColStd_ListIteratorOfListOfReal anIter;
+
+  // Treat intersection points.
+  for(i = 1; i <= aNb; i++) {
+    const IntRes2d_IntersectionPoint &aPoint = anInter.Point(i);
+    Standard_Real                     aParam = aPoint.ParamOnFirst();
+
+    // Adjust parameter on periodic curve.
+    if (myCurve1->IsPeriodic()) {
+      aParam = ElCLib::InPeriod
+        (aParam, myStart1, myStart1 + myCurve1->Period());
+    }
+
+    if (aParam > myStart1 + aTol && aParam < myEnd1 - aTol) {
+      // Add the point in the list in increasing order.
+      for(anIter.Initialize(aParams); anIter.More(); anIter.Next()) {
+        if (anIter.Value() > aParam) {
+          aParams.InsertBefore(aParam, anIter);
+          break;
+        }
+      }
+
+      if (!anIter.More()) {
+        aParams.Append(aParam);
+      }
+    }
+  }
+
+  // Treat intersection segments.
+  aNb = anInter.NbSegments();
+
+  for(i = 1; i <= aNb; i++) {
+    const IntRes2d_IntersectionSegment &aSegment = anInter.Segment(i);
+
+    if (aSegment.HasFirstPoint() && aSegment.HasLastPoint()) {
+      Standard_Real aParam1 = aSegment.FirstPoint().ParamOnFirst();
+      Standard_Real aParam2 = aSegment.LastPoint().ParamOnFirst();
+
+      // Adjust parameters on periodic curve.
+      if (myCurve1->IsPeriodic()) {
+        ElCLib::AdjustPeriodic(myStart1, myStart1 + myCurve1->Period(),
+                               aTol, aParam1, aParam2);
+      }
+
+      if (aParam1 > myStart1 + aTol && aParam1 < myEnd1 - aTol &&
+          aParam2 > myStart1 + aTol && aParam2 < myEnd1 - aTol) {
+        // Add the point in the list in increasing order.
+        const Standard_Real aParam = 0.5*(aParam1 + aParam2);
+
+        for(anIter.Initialize(aParams); anIter.More(); anIter.Next()) {
+          if (anIter.Value() > aParam) {
+            aParams.InsertBefore(aParam, anIter);
+            break;
+          }
+        }
+
+        if (!anIter.More()) {
+          aParams.Append(aParam);
+        }
+      }
+    }
+  }
+
+  // Add start and end parameters to the list.
+  aParams.Prepend(myStart1);
+  aParams.Append(myEnd1);
+  anIter.Initialize(aParams);
+
+  // Perform each interval.
+  Standard_Real aStart = anIter.Value();
+
+  for (anIter.Next(); anIter.More(); anIter.Next()) {
+    const Standard_Real anEnd = anIter.Value();
+
+    // Perform the interval.
+    performInterval(aStart, anEnd, aNBSteps);
+    aStart = anEnd;
+  }
+
+  if (myResultParams.Extent())
+    return Standard_True;
+
+  return Standard_False;
+}
+
+//=======================================================================
+//function : performInterval
+//purpose  :
+//=======================================================================
+void GEOMImpl_Fillet1d::performInterval(const Standard_Real theStart,
+                                        const Standard_Real theEnd,
+                                        const Standard_Integer theNBSteps)
+{
+  Standard_Real aParam, aStep, aDStep;
+  aStep = (theEnd - theStart) / theNBSteps;
+  aDStep = aStep/1000.;
+
+  Standard_Integer aCycle;
+  for(aCycle = 2, myStartSide = Standard_False; aCycle; myStartSide = !myStartSide, aCycle--)
+  {
+    GEOMImpl_Fillet1dPoint *aLeft = NULL, *aRight = NULL;
+
+    for(aParam = theStart + aStep; aParam < theEnd || fabs(theEnd - aParam) < Precision::Confusion(); aParam += aStep)
+    {
+      if (!aLeft)
+      {
+        aLeft = new GEOMImpl_Fillet1dPoint(aParam - aStep);
+        fillPoint(aLeft);
+        fillDiff(aLeft, aDStep, Standard_True);
+      }
+
+      aRight = new GEOMImpl_Fillet1dPoint(aParam);
+      fillPoint(aRight);
+      fillDiff(aRight, aDStep, Standard_False);
+
+      aLeft->FilterPoints(aRight);
+      performNewton(aLeft, aRight);
+
+      delete aLeft;
+      aLeft = aRight;
+    }
+    delete aLeft;
+  }
+}
+
+//=======================================================================
+//function : processPoint
+//purpose  :
+//=======================================================================
+Standard_Boolean GEOMImpl_Fillet1d::processPoint(GEOMImpl_Fillet1dPoint* theLeft,
+                                                 GEOMImpl_Fillet1dPoint* theRight,
+                                                 Standard_Real           theParameter)
+{
+  if (theParameter >= theLeft->GetParam() && theParameter < theRight->GetParam())
+  {
+    Standard_Real aDX = theRight->GetParam() - theLeft->GetParam();
+    if (theParameter - theLeft->GetParam() < aDX / 100.)
+    {
+      theParameter = theLeft->GetParam() + aDX / 100.;
+    }
+    if (theRight->GetParam() - theParameter < aDX / 100.)
+    {
+      theParameter = theRight->GetParam() - aDX / 100.;
+    }
+
+    // Protection on infinite loop.
+    myDegreeOfRecursion++;
+    Standard_Real diffx = 0.001 * aDX;
+    if (myDegreeOfRecursion > 1000)
+    {
+        diffx *= 10.0;
+        if (myDegreeOfRecursion > 10000)
+        {
+            diffx *= 10.0;
+            if (myDegreeOfRecursion > 100000)
+            {
+                return Standard_True;
+            }
+        }
+    }
+
+    GEOMImpl_Fillet1dPoint* aPoint1 = theLeft->Copy();
+    GEOMImpl_Fillet1dPoint* aPoint2 = new GEOMImpl_Fillet1dPoint(theParameter);
+    fillPoint(aPoint2);
+    fillDiff(aPoint2, diffx, Standard_True);
+
+    aPoint1->FilterPoints(aPoint2);
+    performNewton(aPoint1, aPoint2);
+    aPoint2->FilterPoints(theRight);
+    performNewton(aPoint2, theRight);
+
+    delete aPoint1;
+    delete aPoint2;
+    return Standard_True;
+  }
+
+  return Standard_False;
+}
+
+//=======================================================================
+//function : performNewton
+//purpose  :
+//=======================================================================
+void GEOMImpl_Fillet1d::performNewton(GEOMImpl_Fillet1dPoint* theLeft,
+                                      GEOMImpl_Fillet1dPoint* theRight)
+{
+  Standard_Integer a;
+  // check the left: if this is solution store it and remove it from the list of researching points of theLeft
+  a = theLeft->HasSolution(myRadius);
+  if (a)
+  {
+    if (theLeft->IsValid(a))
+    {
+      myResultParams.Append(theLeft->GetParam());
+      myResultOrientation.Append(myStartSide);
+    }
+    return;
+  }
+
+  Standard_Real aDX = theRight->GetParam() - theLeft->GetParam();
+  if ( aDX < Precision::Confusion() / 1000000.)
+  {
+    a = theRight->HasSolution(myRadius);
+    if (a)
+      if (theRight->IsValid(a))
+      {
+        myResultParams.Append(theRight->GetParam());
+        myResultOrientation.Append(myStartSide);
+      }
+    return;
+  }
+
+  for(a = 1; a <= theLeft->GetNBValues(); a++)
+  {
+    Standard_Integer aNear = theLeft->GetNear(a);
+
+    Standard_Real aA = (theRight->GetDiff(aNear) - theLeft->GetDiff(a)) / aDX;
+    Standard_Real aB = theLeft->GetDiff(a) - aA * theLeft->GetParam();
+    Standard_Real aC = theLeft->GetValue(a) - theLeft->GetDiff(a) * theLeft->GetParam() +
+                       aA * theLeft->GetParam() * theLeft->GetParam() / 2.0;
+    Standard_Real aDet = aB * aB - 2.0 * aA * aC;
+
+    if ( fabs(aDet) < gp::Resolution() )
+      continue;
+
+    if (fabs(aA) < Precision::Confusion())
+    { // linear case
+      if (fabs(aB) > 10e-20)
+      {
+        Standard_Real aX0 = - aC / aB; // use extremum
+        if (aX0 > theLeft->GetParam() && aX0 < theRight->GetParam())
+          processPoint(theLeft, theRight, aX0);
+      }
+      else
+      {
+        processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
+      }
+    }
+    else
+    {
+      if (fabs(aB) > fabs(aDet * 1000000.))
+      {  // possible floating point operations accuracy errors
+        processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
+      }
+      else
+      {
+        if (aDet > 0)
+        { // two solutions
+          aDet = sqrt(aDet);
+          Standard_Boolean aRes = processPoint(theLeft, theRight, (- aB + aDet) / aA);
+          if (!aRes)
+            aRes = processPoint(theLeft, theRight, (- aB - aDet) / aA);
+          if (!aRes)
+            processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
+        }
+        else
+        {
+          Standard_Real aX0 = - aB / aA; // use extremum
+          if (aX0 > theLeft->GetParam() && aX0 < theRight->GetParam())
+            processPoint(theLeft, theRight, aX0);
+          else
+            processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
+        }
+      }
+    }
+  }
+}
+
+//=======================================================================
+//function : Result
+//purpose  :
+//=======================================================================
+TopoDS_Edge GEOMImpl_Fillet1d::Result(const gp_Pnt& thePoint,
+                                      TopoDS_Edge& theEdge1,
+                                      TopoDS_Edge& theEdge2)
+{
+  TopoDS_Edge aResult;
+  gp_Pnt2d aTargetPoint2d;
+  Standard_Real aX, aY;
+  ElSLib::PlaneParameters(myPlane->Pln().Position(), thePoint, aX, aY);
+  aTargetPoint2d.SetCoord(aX, aY);
+
+  // choose the nearest circle
+  Standard_Real aDistance, aP;
+  GEOMImpl_Fillet1dPoint *aNearest;
+  Standard_Integer a;
+  TColStd_ListIteratorOfListOfReal anIter(myResultParams);
+  for(aNearest = NULL, a = 1; anIter.More(); anIter.Next(), a++)
+  {
+    myStartSide = (myResultOrientation.Value(a)) ? Standard_True : Standard_False;
+    GEOMImpl_Fillet1dPoint *aPoint = new GEOMImpl_Fillet1dPoint(anIter.Value());
+    fillPoint(aPoint);
+    if (!aPoint->HasSolution(myRadius))
+      continue;
+    aP = fabs(aPoint->GetCenter().Distance(aTargetPoint2d) - myRadius);
+    if (!aNearest || aP < aDistance)
+    {
+      aNearest = aPoint;
+      aDistance = aP;
+    }
+    else
+    {
+      delete aPoint;
+    }
+   }
+
+  if (!aNearest)
+     return aResult;
+
+  // create circle edge
+  gp_Pnt aCenter = ElSLib::PlaneValue(aNearest->GetCenter().X(),
+                                      aNearest->GetCenter().Y(),
+                                      myPlane->Pln().Position());
+  Handle(Geom_Circle) aCircle =
+    new Geom_Circle(gp_Ax2(aCenter, myPlane->Pln().Axis().Direction()), myRadius);
+  gp_Pnt2d aPoint2d1, aPoint2d2;
+  myCurve1->D0(aNearest->GetParam(), aPoint2d1);
+  myCurve2->D0(aNearest->GetParam2(), aPoint2d2);
+  gp_Pnt aPoint1 = ElSLib::PlaneValue(aPoint2d1.X(), aPoint2d1.Y(), myPlane->Pln().Position());
+  gp_Pnt aPoint2 = ElSLib::PlaneValue(aPoint2d2.X(), aPoint2d2.Y(), myPlane->Pln().Position());
+
+  GeomAPI_ProjectPointOnCurve aProj(thePoint, aCircle);
+  Standard_Real aTarGetParam = aProj.LowerDistanceParameter();
+  gp_Pnt aPointOnCircle = aProj.NearestPoint();
+
+  // Check extrema point manually, because there is a bug in Open CASCADE
+  //  in calculation of nearest point to a circle near the parameter 0.0
+  gp_Pnt p0 = ElCLib::Value(0.0, aCircle->Circ());
+  if (p0.Distance(thePoint) < aPointOnCircle.Distance(thePoint))
+  {
+     aTarGetParam = 0.0;
+     aPointOnCircle = p0;
+  }
+
+  aProj.Perform(aPoint1);
+  Standard_Real aParam1 = aProj.LowerDistanceParameter();
+    aProj.Perform(aPoint2);
+  Standard_Real aParam2 = aProj.LowerDistanceParameter();
+  Standard_Boolean aIsOut = ((aParam1 < aTarGetParam && aParam2 < aTarGetParam) ||
+                             (aParam1 > aTarGetParam && aParam2 > aTarGetParam));
+  if (aParam1 > aParam2)
+    aIsOut = !aIsOut;
+  BRepBuilderAPI_MakeEdge aBuilder(aCircle->Circ(),
+                                   aIsOut ? aParam2 : aParam1,
+                                   aIsOut? aParam1 : aParam2);
+  aResult = aBuilder.Edge();
+
+  // divide edges
+  Standard_Real aStart, anEnd;
+  Handle(Geom_Curve) aCurve = BRep_Tool::Curve(myEdge1, aStart, anEnd);
+  gp_Vec aDir;
+  aCurve->D1(aNearest->GetParam(), aPoint1, aDir);
+
+  gp_Vec aCircleDir;
+  aCircle->D1(aParam1, aPoint1, aCircleDir);
+  if ((aCircleDir.Angle(aDir) > M_PI / 2.0) ^ aIsOut)
+    aStart = aNearest->GetParam();
+  else
+    anEnd = aNearest->GetParam();
+
+  if (IsDivideEdge(myEdge1, aStart, anEnd))
+  {
+      //Divide edge
+      BRepBuilderAPI_MakeEdge aDivider1(aCurve, aStart, anEnd);
+      if (myEdgesExchnged)
+        theEdge2 = aDivider1.Edge();
+      else
+        theEdge1 = aDivider1.Edge();
+  }
+
+  aCurve = BRep_Tool::Curve(myEdge2, aStart, anEnd);
+  aCurve->D1(aNearest->GetParam2(), aPoint2, aDir);
+
+  aCircle->D1(aParam2, aPoint2, aCircleDir);
+  if ((aCircleDir.Angle(aDir) > M_PI / 2.0) ^ (!aIsOut))
+    aStart = aNearest->GetParam2();
+  else
+    anEnd = aNearest->GetParam2();
+
+  if (IsDivideEdge(myEdge2, aStart, anEnd))
+  {
+      BRepBuilderAPI_MakeEdge aDivider2(aCurve, aStart, anEnd);
+      if (myEdgesExchnged)
+        theEdge1 = aDivider2.Edge();
+      else
+        theEdge2 = aDivider2.Edge();
+  }
+
+  delete aNearest;
+  return aResult;
+}
+
+//=======================================================================
+//function : AddValue
+//purpose  :
+//=======================================================================
+void GEOMImpl_Fillet1dPoint::AddValue(Standard_Real theValue, Standard_Boolean theValid)
+{
+  Standard_Integer a;
+  for(a = 1; a <= myV.Length(); a++)
+  {
+    if (theValue < myV.Value(a))
+    {
+      myV.InsertBefore(a, theValue);
+      myValid.InsertBefore(a, (Standard_Integer)theValid);
+      return;
+    }
+  }
+  myV.Append(theValue);
+  myValid.Append((Standard_Integer)theValid);
+}
+
+//=======================================================================
+//function : ComputeDifference
+//purpose  :
+//=======================================================================
+Standard_Boolean GEOMImpl_Fillet1dPoint::ComputeDifference(GEOMImpl_Fillet1dPoint* thePoint)
+{
+  Standard_Integer a;
+  Standard_Boolean aDiffsSet = (myD.Length() != 0);
+  Standard_Real aDX = thePoint->GetParam() - myParam, aDY;
+  if (thePoint->myV.Length() == myV.Length())
+  { // absolutely the same points
+    for(a = 1; a <= myV.Length(); a++)
+    {
+      aDY = thePoint->myV.Value(a) - myV.Value(a);
+      if ( aDiffsSet )
+        myD.SetValue(a, fabs(aDX) > gp::Resolution() ? (aDY/aDX) : 0);
+      else
+        myD.Append( fabs(aDX) > gp::Resolution() ? (aDY/aDX) : 0);
+    }
+    return Standard_True;
+  }
+  // between the diffeerent points searching for nearest analogs
+  Standard_Integer b;
+  for(a = 1; a <= myV.Length(); a++)
+  {
+    for(b = 1; b <= thePoint->myV.Length(); b++)
+    {
+      if (b == 1 || fabs(thePoint->myV.Value(b) - myV.Value(a)) < fabs(aDY))
+        aDY = thePoint->myV.Value(b) - myV.Value(a);
+    }
+    if (aDiffsSet)
+    {
+      if ( fabs(aDX) > gp::Resolution() && fabs(aDY / aDX) < fabs(myD.Value(a)))
+        myD.SetValue(a, aDY / aDX);
+      else
+        myD.SetValue(a, 0);
+    }
+    else
+    {
+      myD.Append( fabs(aDX) > gp::Resolution() ? aDY/aDX : 0);
+    }
+  }
+
+  return Standard_False;
+}
+
+//=======================================================================
+//function : FilterPoints
+//purpose  :
+//=======================================================================
+void GEOMImpl_Fillet1dPoint::FilterPoints(GEOMImpl_Fillet1dPoint* thePoint)
+{
+  Standard_Integer a, b;
+  TColStd_SequenceOfReal aDiffs;
+  Standard_Real aY, aY2, aDX = thePoint->GetParam() - myParam;
+  for(a = 1; a <= myV.Length(); a++)
+  {
+    // searching for near point from thePoint
+    Standard_Integer aNear = 0;
+    Standard_Real aDiff = aDX * 10000.;
+    aY = myV.Value(a) + myD.Value(a) * aDX;
+    for(b = 1; b <= thePoint->myV.Length(); b++)
+    {
+      // calculate hypothesis value of the Y2 with the constant first and second derivative
+      aY2 = aY + aDX * (thePoint->myD.Value(b) - myD.Value(a)) / 2.0;
+      if (aNear == 0 || fabs(aY2 - thePoint->myV.Value(b)) < fabs(aDiff))
+      {
+        aNear = b;
+        aDiff = aY2 - thePoint->myV.Value(b);
+      }
+    }//for b...
+
+    if (aNear)
+    {
+      if (myV.Value(a) * thePoint->myV.Value(aNear) > 0)
+      {// the same sign at the same sides of the interval
+        if (myV.Value(a) * myD.Value(a) > 0)
+        {
+          if (fabs(myD.Value(a)) > Precision::Confusion())
+            aNear = 0;
+        }
+        else
+        {
+          if (fabs(myV.Value(a)) > fabs(thePoint->myV.Value(aNear)))
+            if (thePoint->myV.Value(aNear) * thePoint->myD.Value(aNear) < 0 &&
+                fabs(thePoint->myD.Value(aNear)) > Precision::Confusion())
+            {
+              aNear = 0;
+            }
+        }
+      }
+    }
+
+    if (aNear)
+    {
+      if (myV.Value(a) * thePoint->myV.Value(aNear) > 0)
+      {
+        if ((myV.Value(a) + myD.Value(a) * aDX) * myV.Value(a) > Precision::Confusion() &&
+        (thePoint->myV.Value(aNear) + thePoint->myD.Value(aNear) * aDX) * thePoint->myV.Value(aNear) > Precision::Confusion())
+        {
+          aNear = 0;
+        }
+      }
+    }
+
+    if (aNear)
+    {
+      if (  fabs(aDX) < gp::Resolution() || fabs(aDiff / aDX) > 1.e+7)
+      {
+        aNear = 0;
+      }
+    }
+
+    if (aNear == 0)
+    {  // there is no near: remove it from the list
+      myV.Remove(a);
+      myD.Remove(a);
+      myValid.Remove(a);
+      a--;
+    }
+    else
+    {
+      Standard_Boolean aFound = Standard_False;
+      for(b = 1; b <= myNear.Length(); b++)
+      {
+        if (myNear.Value(b) == aNear)
+        {
+          if (fabs(aDiffs.Value(b)) < fabs(aDiff))
+          { // return this 'near'
+            aFound = Standard_True;
+            myV.Remove(a);
+            myD.Remove(a);
+            myValid.Remove(a);
+            a--;
+            break;
+          }
+          else
+          { // remove the old 'near'
+            myV.Remove(b);
+            myD.Remove(b);
+            myValid.Remove(b);
+            myNear.Remove(b);
+            aDiffs.Remove(b);
+            a--;
+            break;
+          }
+        }
+      }//for b...
+      if (!aFound)
+      {
+        myNear.Append(aNear);
+        aDiffs.Append(aDiff);
+      }
+    }
+  }//for a...
+}
+
+//=======================================================================
+//function : Copy
+//purpose  :
+//=======================================================================
+GEOMImpl_Fillet1dPoint* GEOMImpl_Fillet1dPoint::Copy()
+{
+  GEOMImpl_Fillet1dPoint* aCopy = new GEOMImpl_Fillet1dPoint(myParam);
+  Standard_Integer a;
+  for(a = 1; a <= myV.Length(); a++)
+  {
+    aCopy->myV.Append(myV.Value(a));
+    aCopy->myD.Append(myD.Value(a));
+    aCopy->myValid.Append(myValid.Value(a));
+  }
+  return aCopy;
+}
+
+//=======================================================================
+//function : HasSolution
+//purpose  :
+//=======================================================================
+Standard_Integer GEOMImpl_Fillet1dPoint::HasSolution(const Standard_Real theRadius)
+{
+  Standard_Integer a;
+  for(a = 1; a <= myV.Length(); a++)
+  {
+    if (fabs(sqrt(fabs(fabs(myV.Value(a)) + theRadius * theRadius)) - theRadius) < Precision::Confusion() / 10.)
+      return a;
+  }
+  return 0;
+}
+
+//=======================================================================
+//function : RemoveSolution
+//purpose  :
+//=======================================================================
+void GEOMImpl_Fillet1dPoint::RemoveSolution(Standard_Integer theIndex)
+{
+  myV.Remove(theIndex);
+  myD.Remove(theIndex);
+  myValid.Remove(theIndex);
+  myNear.Remove(theIndex);
+}
diff --git a/src/GeomAlgoImpl/GEOMImpl_Fillet1d.hxx b/src/GeomAlgoImpl/GEOMImpl_Fillet1d.hxx
new file mode 100644 (file)
index 0000000..f49294f
--- /dev/null
@@ -0,0 +1,147 @@
+// Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// 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
+//
+
+//  File   : GEOMImpl_Fillet1d.hxx
+//  Module : GEOMImpl
+
+#ifndef _GEOMImpl_Fillet1d_HeaderFile
+#define _GEOMImpl_Fillet1d_HeaderFile
+
+#include <TopoDS_Edge.hxx>
+
+#include <Geom_Plane.hxx>
+#include <Geom2d_Curve.hxx>
+
+#include <gp_Pnt.hxx>
+
+#include <TColStd_ListOfReal.hxx>
+#include <TColStd_SequenceOfReal.hxx>
+#include <TColStd_SequenceOfInteger.hxx>
+
+class GEOMImpl_Fillet1dPoint;
+
+/**
+* GEOMImpl_Fillet1d is 1D fillet algorithm on two planar edges with given radius
+*/
+
+class GEOMImpl_Fillet1d
+{
+public:
+  //! Constructor
+  //! The fillet 1D algorithm is initialised by two edges and plane
+  Standard_EXPORT GEOMImpl_Fillet1d(const TopoDS_Edge& theEdge1,
+                                    const TopoDS_Edge& theEdge2,
+                                    const gp_Pln&      thePlane);
+  //! Makes fillet with given radius
+  //! @returns Standard_True, if at least one result computed
+  Standard_EXPORT Standard_Boolean Perform(const Standard_Real theRadius);
+
+  //! Returns result fillet edge and modified edges as out parameters
+  Standard_EXPORT TopoDS_Edge Result(const gp_Pnt& thePoint, TopoDS_Edge& theEdge1, TopoDS_Edge& theEdge2);
+
+private:
+  //! private methods
+  void performInterval(const Standard_Real theStart,
+                       const Standard_Real theEnd,
+                       const Standard_Integer theNBSteps);
+  void fillPoint(GEOMImpl_Fillet1dPoint*);
+  void fillDiff(GEOMImpl_Fillet1dPoint*, Standard_Real, Standard_Boolean);
+  void performNewton(GEOMImpl_Fillet1dPoint*, GEOMImpl_Fillet1dPoint*);
+  Standard_Boolean processPoint(GEOMImpl_Fillet1dPoint*, GEOMImpl_Fillet1dPoint*, Standard_Real);
+
+private:
+  //! private fields
+  TopoDS_Edge myEdge1, myEdge2;
+  Handle(Geom_Plane) myPlane;
+  Handle(Geom2d_Curve) myCurve1, myCurve2;
+  Standard_Real myStart1, myEnd1, myStart2, myEnd2, myRadius;
+  TColStd_ListOfReal myResultParams;
+  TColStd_SequenceOfInteger myResultOrientation;
+  Standard_Boolean myStartSide, myEdgesExchnged;
+  Standard_Integer myDegreeOfRecursion;
+};
+
+
+/**
+* GEOMImpl_Fillet1dPoint is an internal class for 1D fillet algorithm
+*   to store and compare computed solutions on edges
+*/
+
+class GEOMImpl_Fillet1dPoint
+{
+public:
+  //! Puiblic methods
+
+  //! Constructor
+  Standard_EXPORT GEOMImpl_Fillet1dPoint(Standard_Real theParam)
+  {myParam = theParam;}
+
+  //! Make copy of point
+  //!WARNING: Copies only field values: myParam, myV, myD, myValid
+  Standard_EXPORT GEOMImpl_Fillet1dPoint* Copy(); // warning: this is not the full copy!
+
+  //! Set/Get parameter
+  Standard_EXPORT inline void SetParam(Standard_Real theParam)
+    {myParam = theParam;}
+  Standard_EXPORT inline Standard_Real GetParam() const
+    {return myParam;}
+  Standard_EXPORT inline void SetParam2(const Standard_Real theParam2)
+    {myParam2 = theParam2;}
+  Standard_EXPORT inline Standard_Real GetParam2()
+    { return myParam2 ; }
+
+  //! Returns validity
+  Standard_EXPORT inline Standard_Boolean IsValid(int theIndex)
+    {return (Standard_Boolean)myValid.Value(theIndex);}
+
+  //! Get values
+  Standard_EXPORT inline Standard_Integer GetNBValues() {return myV.Length();}
+  Standard_EXPORT inline Standard_Real GetValue(Standard_Integer theIndex)
+    {return myV.Value(theIndex);}
+  Standard_EXPORT inline Standard_Real GetDiff(Standard_Integer theIndex)
+    {return myD.Value(theIndex);}
+  Standard_EXPORT inline Standard_Integer GetNear(Standard_Integer theIndex)
+    {return myNear.Value(theIndex);}
+
+  //! Set/Get center point
+  Standard_EXPORT inline void SetCenter(const gp_Pnt2d thePoint)
+    {myCenter = thePoint;}
+  Standard_EXPORT inline const gp_Pnt2d GetCenter()
+    {return myCenter;}
+
+  Standard_EXPORT void AddValue(Standard_Real theValue, Standard_Boolean theIsValid);
+
+  //! compute difference between this and given point
+  Standard_EXPORT Standard_Boolean ComputeDifference(GEOMImpl_Fillet1dPoint*);
+  Standard_EXPORT void FilterPoints(GEOMImpl_Fillet1dPoint*);
+
+  //! Checks if point contains solution and returns the index of it if any
+  Standard_EXPORT Standard_Integer HasSolution(Standard_Real theRadius);
+  //! Remove solution by index
+  void RemoveSolution(Standard_Integer theIndex);
+
+private:
+  //! Private fields
+  gp_Pnt2d myCenter;
+  Standard_Real myParam, myParam2;
+  TColStd_SequenceOfReal myV, myD;
+  TColStd_SequenceOfInteger myValid, myNear;
+};
+
+#endif
index 7fd21232ced3b794e80740b2a59e30d85c3f8ba3..01da052aada0ec2acaa6dcc4af33a88912fd18c0 100644 (file)
@@ -50,7 +50,7 @@
 // Used in INTERFACE_N for create variable and getter
 #define DEFINE_ATTRIBUTE(NAME, TYPE, COMMENT) \
     COMMENT \
-    std::shared_ptr<TYPE> NAME() const { return VAR_NAME(NAME); } \
+    virtual std::shared_ptr<TYPE> NAME() const { return VAR_NAME(NAME); } \
   protected: \
     std::shared_ptr<TYPE> VAR_NAME(NAME); \
   public: