]> 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, 2 Jul 2020 11:26:39 +0000 (14:26 +0300)
* Implement the 1D-fillet feature
* Unit tests for 1D-fillet
* Documentation update.
* Translations to French.
* Additional test cases for filleting several wires at once.
* Stabilize the sequence of fillet results.
* Process failed vertices and send the message to highlight them in 3D viewer.

62 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/FeaturesPlugin_msg_en.ts
src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts
src/FeaturesPlugin/FeaturesPlugin_msg_ru.ts
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_Vertices_9.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/Test/TestFillet1D_Wire_5.py [new file with mode: 0644]
src/FeaturesPlugin/doc/FeaturesPlugin.rst
src/FeaturesPlugin/doc/TUI_fillet1DVertices.rst [new file with mode: 0644]
src/FeaturesPlugin/doc/TUI_fillet1DWire.rst [new file with mode: 0644]
src/FeaturesPlugin/doc/examples/fillet1d_vertices.py [new file with mode: 0644]
src/FeaturesPlugin/doc/examples/fillet1d_wire.py [new file with mode: 0644]
src/FeaturesPlugin/doc/fillet1dFeature.rst [new file with mode: 0644]
src/FeaturesPlugin/doc/images/Fillet1DPanel_Vertices.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/Fillet1DPanel_Wire.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/Fillet1DResult_Vertices.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/Fillet1DResult_Wire.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/fillet1d.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/fillet1d_points.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/fillet1d_wire.png [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/ModelAPI/ModelAPI_Events.cpp
src/ModelAPI/ModelAPI_Events.h
src/ModelHighAPI/ModelHighAPI_Macro.h

index 124a03abb68051ccad3c3d8ee105f8d2609af01e..f3d48bd8b4daeaf12131ee702fa40b4256bf9a92 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 3e10651756804744b07c9acdac17220c1ba866ea..d98babe2e23f57ebf8989fc337c79dda176f4879 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 c9b446b6b1121f14310ddb4cb4e0a696aeb0de5f..332b5820878c9eb63c6d4ae8dddb8db63edaf8e2 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 37eeef6884d1cc10d9a8833eb33cd3eea5641a6b..7eac5d6c882c3bfd2f71a69bea4e4e62f8a6b48c 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 3dd2b67f837ea53ffb1ca8336efa60fa8b1f6526..fcd93d08cbbb61afc50b3856db4bb6e85cdcb281 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
@@ -662,4 +665,19 @@ ADD_UNIT_TESTS(TestExtrusion.py
                Test2817.py
                Test19065.py
                Test19066.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_Vertices_9.py
+               TestFillet1D_Wire_1.py
+               TestFillet1D_Wire_2.py
+               TestFillet1D_Wire_3.py
+               TestFillet1D_Wire_4.py
+               TestFillet1D_Wire_5.py
 )
diff --git a/src/FeaturesPlugin/FeaturesPlugin_Fillet1D.cpp b/src/FeaturesPlugin/FeaturesPlugin_Fillet1D.cpp
new file mode 100644 (file)
index 0000000..d62fdee
--- /dev/null
@@ -0,0 +1,187 @@
+// 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>
+#include <ModelAPI_Events.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()
+{
+  ListOfShape aWires;
+  MapShapeSubs aVertices;
+  if (!baseShapes(aWires, aVertices))
+    return;
+
+  int aResultIndex = 0;
+  for (ListOfShape::iterator anIt = aWires.begin(); anIt != aWires.end(); ++anIt)
+    if (!performFillet(*anIt, aVertices[*anIt], aResultIndex++))
+      break;
+  removeResults(aResultIndex);
+}
+
+bool FeaturesPlugin_Fillet1D::baseShapes(ListOfShape& theWires, MapShapeSubs& theWireVertices)
+{
+  std::set<GeomShapePtr, GeomAPI_Shape::Comparator> aProcessedWires;
+  std::string aMethod = string(CREATION_METHOD())->value();
+  if (aMethod == CREATION_BY_WIRES()) {
+    AttributeSelectionListPtr aSelList = selectionList(WIRE_LIST_ID());
+
+    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 wires and fillet vertices stable
+      theWires.push_back(aWire);
+      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();
+
+      // keep the sequence of wires stable
+      if (aProcessedWires.find(aWire) == aProcessedWires.end()) {
+        theWires.push_back(aWire);
+        aProcessedWires.insert(aWire);
+      }
+
+      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));
+
+  bool isOk = true;
+  bool isSendMessage = !myFailedVertices.empty();
+  myFailedVertices = aFilletBuilder->failedVertices();
+
+  std::string anError;
+  if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aFilletBuilder, getKind(), anError)) {
+    isOk = false;
+    // in case of vertices, the fillet completed, send message to highlight them in the viewer
+    isSendMessage = true;
+    bool isAllFailed = myFailedVertices.size() == theVertices.size();
+    setError(anError, isAllFailed);
+    if (isAllFailed)
+      return isOk;
+  }
+
+  if (isSendMessage) {
+    // send message to highlight the failed vertices
+    std::shared_ptr<ModelAPI_Fillet1DFailedMessage> aMessage(
+        new ModelAPI_Fillet1DFailedMessage(Events_Loop::eventByName(EVENT_1DFILLET_FAILED)));
+    aMessage->setVertices(myFailedVertices);
+    Events_Loop::loop()->send(aMessage);
+  }
+
+  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 isOk;
+}
diff --git a/src/FeaturesPlugin/FeaturesPlugin_Fillet1D.h b/src/FeaturesPlugin/FeaturesPlugin_Fillet1D.h
new file mode 100644 (file)
index 0000000..7cf37cc
--- /dev/null
@@ -0,0 +1,115 @@
+// Copyright (C) 2020  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#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(ListOfShape& theWires, 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);
+
+private:
+  ListOfShape myFailedVertices;
+};
+
+#endif
index 9cf7af9d90e56c02fbca6edfaf8821442fbe0c5f..0d49dfe08d1da9ca019628b9784e630e8b5331f9 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 e92148495868ded97bada247c73ca484abfb356b..e84cae4189a61710a5ec8d30776ba8474f5a03f7 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>
@@ -941,6 +942,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 is 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 59eb5fd43929dc7124c0ee744a016ff77f3ff177..951d4c52f969eb17ce2924d31fe0b5732e43c242 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.
index 0ff1004eeb8a3f1aba72d2007d64ce5fc19aac3f..c65a3e3ed60afab7f8f86b2885a7ba793b0c344f 100644 (file)
       <translation>Base shape is not selected.</translation>
     </message>
   </context>
+
+  <!-- 1D-fillet -->
+  <context>
+    <name>Fillet1D</name>
+    <message>
+      <source>1D-fillet</source>
+      <translation>1D-fillet</translation>
+    </message>
+    <message>
+      <source>Perform fillet on vertices of a wire</source>
+      <translation>Perform fillet on vertices of a wire</translation>
+    </message>
+    <message>
+      <source>Wire has no vertices for fillet.</source>
+      <translation>Wire has no vertices for fillet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:main_wires</name>
+    <message>
+      <source>Wires</source>
+      <translation>Wires</translation>
+    </message>
+    <message>
+      <source>Select wires</source>
+      <translation>Select wires</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select wires.</translation>
+    </message>
+    <message>
+      <source>Fillet each sharp corner of the wire</source>
+      <translation>Fillet each sharp corner of the wire</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:main_vertices</name>
+    <message>
+      <source>Vertices</source>
+      <translation>Vertices</translation>
+    </message>
+    <message>
+      <source>Select vertices</source>
+      <translation>Select vertices</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select vertices on wires.</translation>
+    </message>
+    <message>
+      <source>Fillet the specified corners of the wire</source>
+      <translation>Fillet the specified corners of the wire</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:main_vertices:FeaturesPlugin_ValidatorFillet1DSelection</name>
+    <message>
+      <source>Selected vertex is not a wire corner</source>
+      <translation>Selected vertex is not a wire corner</translation>
+    </message>
+    <message>
+      <source>Selected shape is not a vertex</source>
+      <translation>Selected shape is not a vertex</translation>
+    </message>
+    <message>
+      <source>Selected vertex does not exist in the wire</source>
+      <translation>Selected vertex does not exist in the wire</translation>
+    </message>
+    <message>
+      <source>Vertex should be shared between 2 edges exactly</source>
+      <translation>Vertex should be shared between 2 edges exactly</translation>
+    </message>
+    <message>
+      <source>Error: Edges are not planar</source>
+      <translation>Error: Edges are not planar</translation>
+    </message>
+    <message>
+      <source>Error: Edges are tangent</source>
+      <translation>Error: Edges are tangent</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:creation_method</name>
+    <message>
+      <source>Wires</source>
+      <translation>Wires</translation>
+    </message>
+    <message>
+      <source>Vertices</source>
+      <translation>Vertices</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:radius</name>
+    <message>
+      <source>Radius</source>
+      <translation>Radius</translation>
+    </message>
+    <message>
+      <source>Fillet radius</source>
+      <translation>Fillet radius</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Specify fillet radius.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:radius:GeomValidators_Positive</name>
+    <message>
+      <source>Value is too small.</source>
+      <translation>Value is too small.</translation>
+    </message>
+  </context>
+
 </TS>
index 0dfcdfacfc2121fad06c2cb84f1583b09f5feeb1..6f821a2e2fa1c59eadfbf68ab80c4f2e9fbd427a 100644 (file)
       <source>Fillet</source>
       <translation>Congé</translation>
     </message>
+    <message>
+      <source>1D-fillet</source>
+      <translation>1D-congé</translation>
+    </message>
     <message>
       <source>Fuse</source>
       <translation>Fusionner</translation>
     </message>
   </context>
 
+  <!-- 1D-fillet -->
+  <context>
+    <name>Fillet1D</name>
+    <message>
+      <source>1D-fillet</source>
+      <translation>1D-congé</translation>
+    </message>
+    <message>
+      <source>Perform fillet on vertices of a wire</source>
+      <translation>Effectuer un congé sur les sommets d&apos;un contour</translation>
+    </message>
+    <message>
+      <source>Wire has no vertices for fillet.</source>
+      <translation>Le contour n&apos;a pas de sommet pour le congé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:main_wires</name>
+    <message>
+      <source>Wires</source>
+      <translation>Contours</translation>
+    </message>
+    <message>
+      <source>Select wires</source>
+      <translation>Sélectionnez les contours</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez les contours.</translation>
+    </message>
+    <message>
+      <source>Fillet each sharp corner of the wire</source>
+      <translation>Raccordez chaque coin pointu du contour</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:main_vertices</name>
+    <message>
+      <source>Vertices</source>
+      <translation>Sommets</translation>
+    </message>
+    <message>
+      <source>Select vertices</source>
+      <translation>Sélectionnez les sommets</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez des sommets sur les contours.</translation>
+    </message>
+    <message>
+      <source>Fillet the specified corners of the wire</source>
+      <translation>Raccorder les coins spécifiés du contour</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:main_vertices:FeaturesPlugin_ValidatorFillet1DSelection</name>
+    <message>
+      <source>Selected vertex is not a wire corner</source>
+      <translation>Le sommet sélectionné n&apos;est pas un coin de contour</translation>
+    </message>
+    <message>
+      <source>Selected shape is not a vertex</source>
+      <translation>La forme sélectionnée n&apos;est pas un sommet</translation>
+    </message>
+    <message>
+      <source>Selected vertex does not exist in the wire</source>
+      <translation>Le sommet sélectionné n&apos;existe pas dans le contour</translation>
+    </message>
+    <message>
+      <source>Vertex should be shared between 2 edges exactly</source>
+      <translation>Le sommet doit être partagé entre 2 bords exactement</translation>
+    </message>
+    <message>
+      <source>Error: Edges are not planar</source>
+      <translation>Erreur: les arêtes ne sont pas planes</translation>
+    </message>
+    <message>
+      <source>Error: Edges are tangent</source>
+      <translation>Erreur: les bords sont tangents</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:creation_method</name>
+    <message>
+      <source>Wires</source>
+      <translation>Contours</translation>
+    </message>
+    <message>
+      <source>Vertices</source>
+      <translation>Sommets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:radius</name>
+    <message>
+      <source>Radius</source>
+      <translation>Rayon</translation>
+    </message>
+    <message>
+      <source>Fillet radius</source>
+      <translation>Rayon de congé</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Spécifiez le rayon du congé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:radius:GeomValidators_Positive</name>
+    <message>
+      <source>Value is too small.</source>
+      <translation>La valeur est trop petite.</translation>
+    </message>
+  </context>
+
   <!-- Fuse -->
   <context>
     <name>Fuse</name>
index 4e52f45275f6f58f31e0b04506eea85d44d97148..e2777069916eb3f9224efa0e75d3462a1a4b892b 100644 (file)
       <translation>Ошибка: не все выбранные объекты являются подэлементами твердых тел.</translation>
     </message>
   </context>
+
+  <!-- 1D-fillet -->
+  <context>
+    <name>Fillet1D</name>
+    <message>
+      <source>1D-fillet</source>
+      <translation>1D-сглаживание</translation>
+    </message>
+    <message>
+      <source>Perform fillet on vertices of a wire</source>
+      <translation>Выполнить сглаживание в узлах контура</translation>
+    </message>
+    <message>
+      <source>Wire has no vertices for fillet.</source>
+      <translation>Контур не имеет узлов, подходящих для сглаживания.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:main_wires</name>
+    <message>
+      <source>Wires</source>
+      <translation>Контуры</translation>
+    </message>
+    <message>
+      <source>Select wires</source>
+      <translation>Выберите контуры</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Выберите контуры.</translation>
+    </message>
+    <message>
+      <source>Fillet each sharp corner of the wire</source>
+      <translation>Сгладить все острые углы контура</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:main_vertices</name>
+    <message>
+      <source>Vertices</source>
+      <translation>Узлы</translation>
+    </message>
+    <message>
+      <source>Select vertices</source>
+      <translation>Выберите узлы</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Выберите острые углы на контуре.</translation>
+    </message>
+    <message>
+      <source>Fillet the specified corners of the wire</source>
+      <translation>Сгладить выбранные узлы контура</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:main_vertices:FeaturesPlugin_ValidatorFillet1DSelection</name>
+    <message>
+      <source>Selected vertex is not a wire corner</source>
+      <translation>Выбранный узел не принадлежит контуру</translation>
+    </message>
+    <message>
+      <source>Selected shape is not a vertex</source>
+      <translation>Выбранный объект не является узлом</translation>
+    </message>
+    <message>
+      <source>Selected vertex does not exist in the wire</source>
+      <translation>Выбранный узел не принадлежит контуру</translation>
+    </message>
+    <message>
+      <source>Vertex should be shared between 2 edges exactly</source>
+      <translation>Узел должен примыкать ровно к двум рёбрам</translation>
+    </message>
+    <message>
+      <source>Error: Edges are not planar</source>
+      <translation>Ошибка: рёбра не лежат на одной плоскости</translation>
+    </message>
+    <message>
+      <source>Error: Edges are tangent</source>
+      <translation>Ошибка: рёбра касаются друг друга</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:creation_method</name>
+    <message>
+      <source>Wires</source>
+      <translation>Контуры</translation>
+    </message>
+    <message>
+      <source>Vertices</source>
+      <translation>Узлы</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:radius</name>
+    <message>
+      <source>Radius</source>
+      <translation>Радиус</translation>
+    </message>
+    <message>
+      <source>Fillet radius</source>
+      <translation>Радиус сглаживания</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Задайте радиус сглаживания.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet1D:radius:GeomValidators_Positive</name>
+    <message>
+      <source>Value is too small.</source>
+      <translation>Значение радиуса слишком мало.</translation>
+    </message>
+  </context>
+
 </TS>
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..295f226
--- /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", "[Fillet1D_1_1/ME:Fillet1D&Wire_1_1/Edge_1]e[Fillet1D_1_1/ME:Fillet1D&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", "[Fillet1D_2_1/ME:Fillet1D&Wire_1_1/Edge_2]e[Fillet1D_2_1/ME:Fillet1D&Wire_1_1/Edge_4]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..2d1a78b
--- /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", "[Fillet1D_1_1/ME:Fillet1D&Wire_1_1/Edge_4]e[Fillet1D_1_1/ME:Fillet1D&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_Vertices_9.py b/src/FeaturesPlugin/Test/TestFillet1D_Vertices_9.py
new file mode 100644 (file)
index 0000000..2305d0c
--- /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
+#
+
+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)
+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]")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Recover
+Recover_1 = model.addRecover(Part_1_doc, Wire_1, [Box_1.result()])
+
+### Create Wire
+Wire_2_objects = [model.selection("EDGE", "[Recover_1_1/Modified_Face&Box_1_1/Right][Recover_1_1/Modified_Face&Box_1_1/Bottom]"), model.selection("EDGE", "[Recover_1_1/Modified_Face&Box_1_1/Back][Recover_1_1/Modified_Face&Box_1_1/Right]"), model.selection("EDGE", "[Recover_1_1/Modified_Face&Box_1_1/Back][Recover_1_1/Modified_Face&Box_1_1/Top]")]
+Wire_2 = model.addWire(Part_1_doc, Wire_2_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_2_1/Edge_2]e[Wire_2_1/Edge_3]e")], 2)
+
+model.testNbResults(Fillet1D_1, 2)
+model.testNbSubResults(Fillet1D_1, [0, 0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0, 0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0, 0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [4, 4])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [8, 8])
+model.testResultsVolumes(Fillet1D_1, [0, 0])
+
+### Create Fillet1D
+Fillet1D_2 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Fillet1D_1_2/ME:Fillet1D&Wire_2_1/Edge_1]e[Fillet1D_1_2/ME:Fillet1D&Wire_2_1/Edge_2]e"), model.selection("VERTEX", "[Fillet1D_1_1/ME:Fillet1D&Wire_1_1/Edge_2]e[Fillet1D_1_1/ME:Fillet1D&Wire_1_1/Edge_3]e")], 5)
+
+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, 2)
+model.testNbSubResults(Fillet1D_2, [0, 0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.SOLID, [0, 0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.FACE, [0, 0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.EDGE, [5, 5])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.VERTEX, [10, 10])
+model.testResultsVolumes(Fillet1D_2, [0, 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/Test/TestFillet1D_Wire_5.py b/src/FeaturesPlugin/Test/TestFillet1D_Wire_5.py
new file mode 100644 (file)
index 0000000..b05c0c6
--- /dev/null
@@ -0,0 +1,59 @@
+# 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)
+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]")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Recover
+Recover_1 = model.addRecover(Part_1_doc, Wire_1, [Box_1.result()])
+
+### Create Wire
+Wire_2_objects = [model.selection("EDGE", "[Recover_1_1/Modified_Face&Box_1_1/Right][Recover_1_1/Modified_Face&Box_1_1/Bottom]"), model.selection("EDGE", "[Recover_1_1/Modified_Face&Box_1_1/Back][Recover_1_1/Modified_Face&Box_1_1/Right]"), model.selection("EDGE", "[Recover_1_1/Modified_Face&Box_1_1/Back][Recover_1_1/Modified_Face&Box_1_1/Top]")]
+Wire_2 = model.addWire(Part_1_doc, Wire_2_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("WIRE", "Wire_1_1"), model.selection("WIRE", "Wire_2_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, 2)
+model.testNbSubResults(Fillet1D_1, [0, 0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0, 0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0, 0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [5, 5])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [10, 10])
+model.testResultsVolumes(Fillet1D_1, [0, 0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
index 9b06e64e5b4d0156206e1e0b1560eed7e034ed57..421292b0bf65833b3227b8bab4ca254c28e3766f 100644 (file)
@@ -19,6 +19,7 @@ Features plug-in provides a set of common topological operations. It implements
    extrusionCutFeature.rst
    extrusionFeature.rst
    extrusionFuseFeature.rst
+   fillet1dFeature.rst
    filletFeature.rst
    fuseFeature.rst
    fuseFeatureFaces.rst
diff --git a/src/FeaturesPlugin/doc/TUI_fillet1DVertices.rst b/src/FeaturesPlugin/doc/TUI_fillet1DVertices.rst
new file mode 100644 (file)
index 0000000..6a7f037
--- /dev/null
@@ -0,0 +1,12 @@
+
+  .. _tui_create_fillet1d_vertices:
+
+Create 1D-fillet for special vertices on a wire
+===============================================
+
+.. literalinclude:: examples/fillet1d_vertices.py 
+    :linenos:
+    :language: python
+
+:download:`Download this script <examples/fillet1d_vertices.py >` 
+   
diff --git a/src/FeaturesPlugin/doc/TUI_fillet1DWire.rst b/src/FeaturesPlugin/doc/TUI_fillet1DWire.rst
new file mode 100644 (file)
index 0000000..c222306
--- /dev/null
@@ -0,0 +1,12 @@
+
+  .. _tui_create_fillet1d_wire:
+
+Create 1D-fillet on a wire
+==========================
+
+.. literalinclude:: examples/fillet1d_wire.py 
+    :linenos:
+    :language: python
+
+:download:`Download this script <examples/fillet1d_wire.py >` 
+   
diff --git a/src/FeaturesPlugin/doc/examples/fillet1d_vertices.py b/src/FeaturesPlugin/doc/examples/fillet1d_vertices.py
new file mode 100644 (file)
index 0000000..d2a0cbe
--- /dev/null
@@ -0,0 +1,25 @@
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Box
+Box_1 = model.addBox(Part_1_doc, 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]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1_objects = [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")]
+Fillet1D_1 = model.addFillet(Part_1_doc, Fillet1D_1_objects, 3)
+
+model.end()
diff --git a/src/FeaturesPlugin/doc/examples/fillet1d_wire.py b/src/FeaturesPlugin/doc/examples/fillet1d_wire.py
new file mode 100644 (file)
index 0000000..36ccfc9
--- /dev/null
@@ -0,0 +1,23 @@
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Box
+Box_1 = model.addBox(Part_1_doc, 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]")]
+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")], 3)
+
+model.end()
diff --git a/src/FeaturesPlugin/doc/fillet1dFeature.rst b/src/FeaturesPlugin/doc/fillet1dFeature.rst
new file mode 100644 (file)
index 0000000..e3a30a4
--- /dev/null
@@ -0,0 +1,100 @@
+.. |fillet1d.icon|    image:: images/fillet1d.png
+
+.. _featureFillet1D:
+
+1D-fillet
+=========
+
+**1D-fillet** feature creates fillets on the vertices of a wire. 
+The fillet may be performed on sharp corners of a wire, which are shared exactly between 2 edges, and which are placed ona single plane. 
+
+To create a 1D-fillet in the active part:
+
+#. select in the Main Menu *Feature - > 1D-fillet* item  or
+#. click |fillet1d.icon| **1D-fillet** button in the toolbar
+
+There are 2 types of fillet:
+
+  .. image:: images/fillet1d_wire.png   
+    :align: left
+  fillet all sharp corners on a wire
+
+  .. image:: images/fillet1d_points.png   
+    :align: left
+  fillet only the specified corners
+
+Fillet a wire
+-------------
+
+The property panel for this mode is shown below.
+
+.. image:: images/Fillet1DPanel_Wire.png
+  :align: center
+
+.. centered::
+  Property panel of an operation to fillet all sharp corners on a wire
+
+Input fields:
+
+- **Wires** panel contains the list of wires for the operation. The fillet will be performed to the applicable corners. If the wire has no such corner, the error message will be shown;
+- **Radius** defines the fillet radius.
+
+**TUI Command**:
+
+.. py:function:: model.addFillet(Part_doc, [wires], radius)
+
+    :param part: The current part object.
+    :param list: A list of wires subject to fillet operation in format *model.selection(TYPE, shape)*.
+    :param number: Radius value.
+    :return: Created object.
+
+Result
+""""""
+
+Result of **Fillet a wire** is shown below. In this case all vertices were sharp, thus, filleted.
+
+.. image:: images/Fillet1DResult_Wire.png
+   :align: center
+
+.. centered::
+   Result of filleting a wire
+
+**See Also** a sample TUI Script of :ref:`tui_create_fillet1d_wire` operation.
+
+Fillet the specified vertices on a wire
+---------------------------------------
+
+Alternatively, there is a possibility to create a fillet on a special sharp corners of a wire.
+
+.. image:: images/Fillet1DPanel_Vertices.png
+  :align: center
+
+.. centered::
+  Property panel to fillet the specified vertices of a wire
+
+Input fields:
+
+- **Vertices** panel contains list of vertices on a wires applicable for fillet operation;
+- **Radius** defines the fillet radius.
+
+**TUI Command**:
+
+.. py:function:: model.addFillet(Part_doc, [vertices], radius)
+
+    :param part: The current part object.
+    :param list: A list of vertices subject to fillet operation in format *model.selection(TYPE, shape)*.
+    :param number: Radius value.
+    :return: Created object.
+
+Result
+""""""
+
+Result of **Fillet by vertices** is shown below. The only 2 corners of the wire become smooth.
+
+.. image:: images/Fillet1DResult_Vertices.png
+   :align: center
+
+.. centered::
+   Result of filleting the specified vertices of a wire
+
+**See Also** a sample TUI Script of :ref:`tui_create_fillet1d_vertices` operation.
diff --git a/src/FeaturesPlugin/doc/images/Fillet1DPanel_Vertices.png b/src/FeaturesPlugin/doc/images/Fillet1DPanel_Vertices.png
new file mode 100644 (file)
index 0000000..883c5e0
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/Fillet1DPanel_Vertices.png differ
diff --git a/src/FeaturesPlugin/doc/images/Fillet1DPanel_Wire.png b/src/FeaturesPlugin/doc/images/Fillet1DPanel_Wire.png
new file mode 100644 (file)
index 0000000..668627e
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/Fillet1DPanel_Wire.png differ
diff --git a/src/FeaturesPlugin/doc/images/Fillet1DResult_Vertices.png b/src/FeaturesPlugin/doc/images/Fillet1DResult_Vertices.png
new file mode 100644 (file)
index 0000000..4ec0fa9
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/Fillet1DResult_Vertices.png differ
diff --git a/src/FeaturesPlugin/doc/images/Fillet1DResult_Wire.png b/src/FeaturesPlugin/doc/images/Fillet1DResult_Wire.png
new file mode 100644 (file)
index 0000000..a465525
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/Fillet1DResult_Wire.png differ
diff --git a/src/FeaturesPlugin/doc/images/fillet1d.png b/src/FeaturesPlugin/doc/images/fillet1d.png
new file mode 100644 (file)
index 0000000..a94aba3
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/fillet1d.png differ
diff --git a/src/FeaturesPlugin/doc/images/fillet1d_points.png b/src/FeaturesPlugin/doc/images/fillet1d_points.png
new file mode 100644 (file)
index 0000000..c0f751a
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/fillet1d_points.png differ
diff --git a/src/FeaturesPlugin/doc/images/fillet1d_wire.png b/src/FeaturesPlugin/doc/images/fillet1d_wire.png
new file mode 100644 (file)
index 0000000..62eed22
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/fillet1d_wire.png differ
diff --git a/src/FeaturesPlugin/fillet1d_widget.xml b/src/FeaturesPlugin/fillet1d_widget.xml
new file mode 100644 (file)
index 0000000..e7f3caf
--- /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 29f4053331058cf788f3f2191912b119eab7db12..0a336c3981da3570c8c9751cfba679a75f9161a8 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 9d462d7082a52333389ecf381d0548cdd1f9c431..e7d65648a5739c5b709ac583482ff436527fee35 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 6233a08c974b1dd86121295f110f9e9e09c652f2..41cfa84a8b88710c496bf8656834ba84b93bf865 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 89eecc8e9a95e0d52aec96ea674d698dac2f4bdf..6accbf978b1c7d5c3bf4ca8c4e29affe2d63a817 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 318819f9996385b4873676f505ace738cb535da9..635c9b6fbbdf79332f27588338444e5276deb35c 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 292128e902efaab229d184501f54a4953ea878d2..97e6eb180361b24b17566997f185a2b3cf13afff 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 78fba30bc9e9780e2ca854377e9555c9756d2446..95e749c10d2d5263ee845b513f73b2659f70365e 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..4408220
--- /dev/null
@@ -0,0 +1,216 @@
+// 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_Copy.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;
+
+  myFailedVertices.clear();
+  // store all edges of a base wire as modified, because they will be rebuild by ShapeFix
+  for (GeomAPI_WireExplorer aWExp(theBaseWire->wire()); aWExp.more(); aWExp.next()) {
+    GeomShapePtr aCurrent = aWExp.current();
+    GeomAlgoAPI_Copy aCopy(aCurrent);
+    myModified[aCurrent].push_back(aCopy.shape());
+  }
+
+  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)) {
+      // store the failed vertex and continue
+      myFailedVertices.push_back(*aVIt);
+      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()) {
+    myFailedVertices = theFilletVertices;
+    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(myFailedVertices.empty());
+}
+
+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..578f91c
--- /dev/null
@@ -0,0 +1,75 @@
+// 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);
+
+  /// \return List of failed vertices
+  const ListOfShape& failedVertices() const { return myFailedVertices; }
+
+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;
+
+  ListOfShape myFailedVertices;
+};
+
+#endif
index d35f58bade2cd907ef1e4bdb7642665b0b996e3c..5b04d9f066dbc3a0ebde05a8a57c39915c32caab 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>
 
@@ -855,6 +856,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 e321dd3e365c82e2fd54f4cdb5f1324071c185a8..4e1e6523a0d95ce80cc6223af87da34f8c672c2e 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 a855e00cadc21fec357fa22a806d55e3c9abe113..83c67995933d1a415c08a6c4a3ef2d865b074a99 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 f616eb290d86f27d058078c334b19b2c5c25fb98..19e664f81296e14bdac9e85ec43c5032deea7809 100644 (file)
@@ -21,6 +21,7 @@
 #include <ModelAPI_Events.h>
 
 #include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_Shape.h>
 
 //#define DEBUG_OBJECT_MOVED_MESSAGE
 #ifdef DEBUG_OBJECT_MOVED_MESSAGE
@@ -384,3 +385,23 @@ void ModelAPI_ObjectMovedMessage::setCurrentPosition(
             << myCurrentPosition->y() - myOriginalPosition->y() << std::endl;
 #endif
 }
+
+
+// =====   ModelAPI_Fillet1DFailedMessage   =====
+ModelAPI_Fillet1DFailedMessage::ModelAPI_Fillet1DFailedMessage(const Events_ID theID,
+                                                               const void* theSender)
+  : Events_Message(theID, theSender)
+{}
+
+ModelAPI_Fillet1DFailedMessage::~ModelAPI_Fillet1DFailedMessage()
+{}
+
+void ModelAPI_Fillet1DFailedMessage::setVertices(const ListOfShape& theVertices)
+{
+  myVertices = theVertices;
+}
+
+const ListOfShape& ModelAPI_Fillet1DFailedMessage::vertices() const
+{
+  return myVertices;
+}
index c79ec94d007f30f3a42b8845a332cc5a5cec28b5..2a63ab671d8643e617d9c9aac415298f1367883f 100644 (file)
@@ -36,6 +36,7 @@
 class ModelAPI_Document;
 class ModelAPI_ResultParameter;
 class GeomAPI_Pnt2d;
+class GeomAPI_Shape;
 
 #if defined __GNUC__ || defined __clang__
 #define MAYBE_UNUSED __attribute__((unused))
@@ -119,6 +120,9 @@ MAYBE_UNUSED static const char * EVENT_DOF_OBJECTS = "DoFObjects";
 MAYBE_UNUSED static const char * EVENT_VISUAL_ATTRIBUTES = "UpdateVisualAttributes";
 
 
+/// Event ID that 1D-fillet failed (comes with ModelAPI_Fillet1DFailedMessage)
+static const char * EVENT_1DFILLET_FAILED = "1DFilletFailed";
+
 /// Message that feature was changed (used for Object Browser update): moved, updated and deleted
 class MODELAPI_EXPORT ModelAPI_ObjectUpdatedMessage : public Events_MessageGroup
 {
@@ -540,4 +544,27 @@ public:
   { return myCurrentPosition; }
 };
 
+/// Message that sends the failed vertices of 1D-fillet to highlight them in 3D viewer
+class ModelAPI_Fillet1DFailedMessage : public Events_Message
+{
+public:
+  /// Creates an message
+  MODELAPI_EXPORT ModelAPI_Fillet1DFailedMessage(const Events_ID theID, const void* theSender = 0);
+  /// Default destructor
+  MODELAPI_EXPORT virtual ~ModelAPI_Fillet1DFailedMessage();
+  /// Static. Returns EventID of the message.
+  MODELAPI_EXPORT static Events_ID eventId()
+  {
+    return Events_Loop::eventByName(EVENT_1DFILLET_FAILED);
+  }
+
+  /// Sets list of failed vertices
+  MODELAPI_EXPORT void setVertices(const std::list< std::shared_ptr<GeomAPI_Shape> >& theVertices);
+  /// Returns list of failed vertices
+  MODELAPI_EXPORT const std::list< std::shared_ptr<GeomAPI_Shape> >& vertices() const;
+
+private:
+  std::list< std::shared_ptr<GeomAPI_Shape> > myVertices;
+};
+
 #endif
index accf0c79fc93fe10a88f1107454691ccae2685c7..333de514e0347ea08358160a39ab93727b500db7 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: