]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Integration :
authorJérôme <jerome.lucas@cesgenslab.fr>
Mon, 2 Nov 2020 14:01:08 +0000 (15:01 +0100)
committerNicolas RECHATIN <nicolas.rechatin@cea.fr>
Thu, 10 Jun 2021 13:11:33 +0000 (15:11 +0200)
{ Integrated by : Nicolas RECHATIN <nicolas.rechatin@cea.fr>}
{ Code from : Jerome LUCAS <jerome.lucas@cesgenslabs.fr>}
+ Implementation of Filters "Edge size", "Face size" and "Volume Size"
+ Add Filter Feature Edge and Continuous Faces
+ Documentation error
+ Units tests for filter Edge Size and Face Size
+ Add test for "feature Edges"
+ Add test "Continuous face" filters, traduction
+ Add precision in geom_validator for zero value.
+ Add test for filter VolumeSize
+ Copyright update

38 files changed:
src/FiltersAPI/FiltersAPI.i
src/FiltersAPI/FiltersAPI_Argument.cpp
src/FiltersAPI/FiltersAPI_Argument.h
src/FiltersAPI/FiltersAPI_Feature.cpp
src/FiltersAPI/FiltersAPI_Filter.cpp
src/FiltersPlugin/CMakeLists.txt
src/FiltersPlugin/FiltersPlugin_ContinuousFaces.cpp [new file with mode: 0644]
src/FiltersPlugin/FiltersPlugin_ContinuousFaces.h [new file with mode: 0644]
src/FiltersPlugin/FiltersPlugin_EdgeSize.cpp [new file with mode: 0644]
src/FiltersPlugin/FiltersPlugin_EdgeSize.h [new file with mode: 0644]
src/FiltersPlugin/FiltersPlugin_FaceSize.cpp [new file with mode: 0644]
src/FiltersPlugin/FiltersPlugin_FaceSize.h [new file with mode: 0644]
src/FiltersPlugin/FiltersPlugin_FeatureEdges.cpp [new file with mode: 0644]
src/FiltersPlugin/FiltersPlugin_FeatureEdges.h [new file with mode: 0644]
src/FiltersPlugin/FiltersPlugin_Plugin.cpp
src/FiltersPlugin/FiltersPlugin_VolumeSize.cpp [new file with mode: 0644]
src/FiltersPlugin/FiltersPlugin_VolumeSize.h [new file with mode: 0644]
src/FiltersPlugin/FiltersPlugin_msg_fr.ts
src/FiltersPlugin/Test/TestFilter_ContinuousFaces.py [new file with mode: 0644]
src/FiltersPlugin/Test/TestFilter_EdgeSize.py [new file with mode: 0644]
src/FiltersPlugin/Test/TestFilter_FaceSize.py [new file with mode: 0644]
src/FiltersPlugin/Test/TestFilter_FeatureEdges.py [new file with mode: 0644]
src/FiltersPlugin/Test/TestFilter_VolumeSize.py [new file with mode: 0644]
src/FiltersPlugin/Test/TestFilters_Supported.py
src/FiltersPlugin/doc/FiltersPlugin.rst
src/FiltersPlugin/filter-ContinuousFaces.xml [new file with mode: 0644]
src/FiltersPlugin/filter-EdgeSize.xml [new file with mode: 0644]
src/FiltersPlugin/filter-FaceSize.xml [new file with mode: 0644]
src/FiltersPlugin/filter-FeatureEdges.xml [new file with mode: 0644]
src/FiltersPlugin/filter-VolumeSize.xml [new file with mode: 0644]
src/FiltersPlugin/tests.set
src/GeomAlgoAPI/CMakeLists.txt
src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.cpp [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.h [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.cpp [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.h [new file with mode: 0644]
src/GeomValidators/GeomValidators_Positive.cpp
src/ModuleBase/ModuleBase_WidgetSelectionFilter.cpp

index 76bcad128228344ffa198d5d9eaf616564d873ae..99e68051500c5d8f87a2ee8a9c3c3a7fe0784f4a 100644 (file)
@@ -45,6 +45,8 @@
 %shared_ptr(FiltersAPI_Feature)
 %shared_ptr(FiltersAPI_Filter)
 
+%shared_ptr(ModelHighAPI_Interface)
+
 // function with named parameters
 %feature("kwargs") addFilter;
 
         if (!temp_string) {
           $1 = 0;
         }
-      } else
+      }else
+      if (!PyFloat_Check(item) && PyLong_Check(item))
+        $1 = 0;
+      else
       if (!PyUnicode_Check(item) && !PyBool_Check(item))
         $1 = 0;
     }
 %typemap(in) const std::list<FiltersAPI_Argument> & (std::list<FiltersAPI_Argument> temp) {
   ModelHighAPI_Selection* temp_selection;
   std::string* temp_string;
+  ModelHighAPI_Double* temp_double;
   int newmem = 0;
   if (PySequence_Check($input)) {
     for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
       PyObject * item = PySequence_GetItem($input, i);
       if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_selection, $descriptor(ModelHighAPI_Selection*), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
         if (!temp_selection) {
-          PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_Selection, string or boolean.");
+          PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_Selection, string, double or boolean.1");
           return NULL;
         }
         temp.push_back(FiltersAPI_Argument(*temp_selection));
       } else
       if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_string, $descriptor(std::string*), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
         if (!temp_string) {
-          PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_Selection, string or boolean.");
+          PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_Selection, string, double or boolean.2");
           return NULL;
         }
         temp.push_back(FiltersAPI_Argument(*temp_string));
       } else
       if (PyBool_Check(item)) {
         temp.push_back(FiltersAPI_Argument(item == Py_True));
+      } else 
+      if(PyFloat_Check(item) || PyLong_Check(item)) { 
+        temp.push_back(FiltersAPI_Argument(ModelHighAPI_Double(PyFloat_AsDouble(item))));
       } else {
-        PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_Selection, string or boolean.");
+        PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_Selection, string, double or boolean.4");
         return NULL;
       }
       Py_DECREF(item);
     }
     $1 = &temp;
   } else {
-    PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_Selection, string or boolean.");
+    PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_Selection, string, double or boolean.5");
     return NULL;
   }
 }
index 30d5e36cd8d372e3e33f44c14f9415d2bf0691ee..8cc6880bd256dc732a688820996fde426e4bf045 100644 (file)
@@ -28,6 +28,16 @@ FiltersAPI_Argument::FiltersAPI_Argument(const bool theValue)
 {
 }
 
+FiltersAPI_Argument::FiltersAPI_Argument(const ModelHighAPI_Double theValue)
+  : myDouble(theValue)
+{
+}
+
+FiltersAPI_Argument::FiltersAPI_Argument(const double& theValue)
+{
+  myDouble = theValue;
+}
+
 FiltersAPI_Argument::FiltersAPI_Argument(const std::string& theValue)
   : myValue(theValue)
 {
@@ -54,9 +64,14 @@ void FiltersAPI_Argument::dump(ModelHighAPI_Dumper& theDumper) const
     theDumper << "model.selection()"; // mySelectionAttr;
   }
   else if (mySelection.variantType() == ModelHighAPI_Selection::VT_Empty) {
-    if (myValue.empty())
+    if (myDouble.value() > -100000000000 ){
+      theDumper << myDouble.value();
+    }
+    else if (myValue.empty()){
       theDumper << myBoolean;
-    else
+    }
+    else{
       theDumper << "\"" << myValue << "\"";
+    }
   }
 }
index 7b7cd30ff49f2f92383db5a285a70b72c87d84f1..050bacd146dc66f24acf127b20b1d20472f00b97 100644 (file)
@@ -23,6 +23,7 @@
 #include "FiltersAPI.h"
 
 #include <ModelAPI_AttributeSelection.h>
+#include <ModelHighAPI_Double.h>
 
 #include <ModelHighAPI_Dumper.h>
 #include <ModelHighAPI_Selection.h>
@@ -39,6 +40,12 @@ public:
   FILTERSAPI_EXPORT
   FiltersAPI_Argument(const bool theValue);
 
+  FILTERSAPI_EXPORT
+  FiltersAPI_Argument(const ModelHighAPI_Double theValue);
+
+  FILTERSAPI_EXPORT
+  FiltersAPI_Argument(const double& theValue);
+
   FILTERSAPI_EXPORT
   FiltersAPI_Argument(const std::string& theValue);
 
@@ -55,13 +62,14 @@ public:
   const bool boolean() const { return myBoolean; }
   const std::string& string() const { return myValue; }
   const ModelHighAPI_Selection& selection() const { return mySelection; }
-
+  const ModelHighAPI_Double& dble() const { return myDouble; }
   /// Dump wrapped feature
   FILTERSAPI_EXPORT
   void dump(ModelHighAPI_Dumper& theDumper) const;
 
 private:
   bool myBoolean;
+  ModelHighAPI_Double myDouble  = -100000000000;
   std::string myValue;
   ModelHighAPI_Selection mySelection;
   AttributeSelectionPtr mySelectionAttr;
index 215b2ef12892dc0dd5d915b978a8c9954ccdf3b9..9a24140f4c81aabbe126ea80edb7f19e2af971f7 100644 (file)
@@ -41,14 +41,19 @@ FiltersAPI_Feature::~FiltersAPI_Feature()
 static void separateArguments(const std::list<FiltersAPI_Argument>& theArguments,
                               std::list<ModelHighAPI_Selection>& theSelections,
                               std::list<std::string>& theTextArgs,
-                              std::list<bool>& theBoolArgs)
+                              std::list<bool>& theBoolArgs,
+                              std::list<ModelHighAPI_Double>& theDoubleArgs)
 {
   std::list<FiltersAPI_Argument>::const_iterator anIt = theArguments.begin();
   for (; anIt != theArguments.end(); ++anIt) {
     if (anIt->selection().variantType() != ModelHighAPI_Selection::VT_Empty)
       theSelections.push_back(anIt->selection());
-    else if (anIt->string().empty())
+    else if (anIt->dble().value() > -100000000000) {
+      theDoubleArgs.push_back(anIt->dble());
+    }
+    else if (anIt->string().empty()){
       theBoolArgs.push_back(anIt->boolean());
+    }
     else
       theTextArgs.push_back(anIt->string());
   }
@@ -68,7 +73,8 @@ void FiltersAPI_Feature::setFilters(const std::list<FilterAPIPtr>& theFilters)
       std::list<ModelHighAPI_Selection> aSelections;
       std::list<std::string> aTexts;
       std::list<bool> aBools;
-      separateArguments(anArgs, aSelections, aTexts, aBools);
+      std::list<ModelHighAPI_Double> aDoubles;
+      separateArguments(anArgs, aSelections, aTexts, aBools, aDoubles);
 
       std::list<AttributePtr> aFilterArgs = aBase->filterArgs(aFilterID);
       std::list<AttributePtr>::iterator aFIt = aFilterArgs.begin();
@@ -78,6 +84,7 @@ void FiltersAPI_Feature::setFilters(const std::list<FilterAPIPtr>& theFilters)
       if (aReversedFlag)
         ++aFIt;
       // fill arguments of the filter
+      std::list<ModelHighAPI_Double>::const_iterator anItDle = aDoubles.begin();
       for (; aFIt != aFilterArgs.end(); ++aFIt) {
         AttributeSelectionListPtr aSelList =
             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*aFIt);
@@ -98,8 +105,17 @@ void FiltersAPI_Feature::setFilters(const std::list<FilterAPIPtr>& theFilters)
             else {
               AttributeBooleanPtr aBoolean =
                   std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(*aFIt);
-              if (aBoolean && aBools.size() == 1)
-                fillAttribute(aBools.front(), aBoolean);
+              if (aBoolean) {
+                if (aBools.size() == 1)
+                  fillAttribute(aBools.front(), aBoolean);
+              }else {
+                AttributeDoublePtr aDouble =
+                    std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(*aFIt);
+                if (aDouble) {
+                  fillAttribute((*anItDle).value(), aDouble);
+                  anItDle++;
+                }
+              }
             }
           }
         }
index 5ae1afb029fc2c381190e0c56d254ccb5f155dc6..37d7881e68d142634c985f887f348389cffabc07 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <ModelAPI_Attribute.h>
 #include <ModelAPI_AttributeBoolean.h>
+#include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_AttributeString.h>
 
@@ -72,11 +73,18 @@ FiltersAPI_Filter::FiltersAPI_Filter(const std::string& theName,
       continue;
     }
 
+    AttributeDoublePtr aDouble = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(*anArgIt);
+    if (aDouble) {
+      myFilterArguments.push_back(FiltersAPI_Argument(aDouble->value()));
+      continue;
+    }
+
     AttributeBooleanPtr aBoolean = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(*anArgIt);
     if (aBoolean) {
       myFilterArguments.push_back(FiltersAPI_Argument(aBoolean->value()));
       continue;
     }
+
   }
 }
 
index 7b77d8466164e28dec8627ef0838a5b68496580d..f32f2047d719e48398460f46daee298d43007f96 100644 (file)
@@ -35,6 +35,11 @@ SET(PROJECT_HEADERS
     FiltersPlugin_RelativeToSolid.h
     FiltersPlugin_ExternalFaces.h
     FiltersPlugin_Validators.h
+    FiltersPlugin_EdgeSize.h
+    FiltersPlugin_FaceSize.h
+    FiltersPlugin_VolumeSize.h
+    FiltersPlugin_FeatureEdges.h
+    FiltersPlugin_ContinuousFaces.h
 )
 
 SET(PROJECT_SOURCES
@@ -51,6 +56,11 @@ SET(PROJECT_SOURCES
     FiltersPlugin_RelativeToSolid.cpp
     FiltersPlugin_ExternalFaces.cpp
     FiltersPlugin_Validators.cpp
+    FiltersPlugin_EdgeSize.cpp
+    FiltersPlugin_FaceSize.cpp
+    FiltersPlugin_VolumeSize.cpp
+    FiltersPlugin_FeatureEdges.cpp
+    FiltersPlugin_ContinuousFaces.cpp
 )
 
 SET(PROJECT_LIBRARIES
@@ -76,6 +86,11 @@ SET(XML_RESOURCES
   filter-OppositeToEdge.xml
   filter-RelativeToSolid.xml
   filter-TopoConnectedFaces.xml
+  filter-EdgeSize.xml
+  filter-FaceSize.xml
+  filter-VolumeSize.xml
+  filter-FeatureEdges.xml
+  filter-ContinuousFaces.xml
 )
 
 SET(TEXT_RESOURCES
@@ -114,17 +129,16 @@ ADD_UNIT_TESTS(${TEST_NAMES})
 if(${HAVE_SALOME})
   enable_testing()
   set(TEST_INSTALL_DIRECTORY "${SALOME_SHAPER_INSTALL_TESTS}/FiltersPlugin")
-  
+
   install(FILES CTestTestfileInstall.cmake
   DESTINATION ${TEST_INSTALL_DIRECTORY}
   RENAME CTestTestfile.cmake)
   install(FILES tests.set DESTINATION ${TEST_INSTALL_DIRECTORY})
-  
+
   set(TMP_TESTS_NAMES)
   foreach(tfile ${TEST_NAMES})
     list(APPEND TMP_TESTS_NAMES "Test/${tfile}")
   endforeach(tfile ${TEST_NAMES})
-  
+
   install(FILES ${TMP_TESTS_NAMES} DESTINATION ${TEST_INSTALL_DIRECTORY})
 endif(${HAVE_SALOME})
-
diff --git a/src/FiltersPlugin/FiltersPlugin_ContinuousFaces.cpp b/src/FiltersPlugin/FiltersPlugin_ContinuousFaces.cpp
new file mode 100644 (file)
index 0000000..0ab82ea
--- /dev/null
@@ -0,0 +1,195 @@
+// Copyright (C) 2014-2021  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 "FiltersPlugin_ContinuousFaces.h"
+
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_AttributeSelection.h>
+#include <ModelAPI_AttributeDouble.h>
+
+#include <ModelAPI_Tools.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Shape.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+#include <GeomAPI_Wire.h>
+
+#include <GeomAPI_ShapeExplorer.h>
+#include <GeomAlgoAPI_ContinuousFaces.h>
+
+#include <map>
+#include <math.h>
+#include <iostream>
+
+typedef std::map<GeomShapePtr, SetOfShapes, GeomAPI_Shape::Comparator> MapShapeAndAncestors;
+
+//=================================================================================================
+static void mapEdgesAndFaces(const GeomShapePtr theShape, MapShapeAndAncestors& theMap)
+{
+  GeomAPI_ShapeExplorer aFExp(theShape, GeomAPI_Shape::FACE);
+  for (; aFExp.more(); aFExp.next()) {
+    GeomShapePtr aFace = aFExp.current();
+    GeomAPI_ShapeExplorer aEExp(aFace, GeomAPI_Shape::EDGE);
+    for (; aEExp.more(); aEExp.next())
+      theMap[aEExp.current()].insert(aFace);
+  }
+}
+
+//=================================================================================================
+// Find all continuous faces for the given.
+static void cacheContinuousFace(const GeomShapePtr theFace,
+                                const MapShapeAndAncestors& theEdgeToFaces,
+                                SetOfShapes& theCache,
+                                const double & theAngle)
+{
+
+  MapShapeAndAncestors::const_iterator aFound;
+  GeomAPI_ShapeExplorer aEExp(theFace, GeomAPI_Shape::EDGE);
+  for (; aEExp.more(); aEExp.next()){
+    aFound = theEdgeToFaces.find(aEExp.current());
+    if (aFound == theEdgeToFaces.end())
+      continue;
+
+    GeomEdgePtr anEdge;
+    anEdge = GeomEdgePtr(new GeomAPI_Edge(aEExp.current()));
+
+    for (SetOfShapes::const_iterator aFIt = aFound->second.begin();
+       aFIt != aFound->second.end(); ++aFIt) {
+      std::string anError = "";
+      if (theCache.find(*aFIt) == theCache.end()) {
+       GeomPointPtr aPoint = anEdge->middlePoint();
+       if (isContinuousFaces(theFace,
+                              *aFIt,
+                              aPoint,
+                              theAngle,
+                              anError)) {
+          theCache.insert(*aFIt);
+          cacheContinuousFace(*aFIt, theEdgeToFaces, theCache, theAngle);
+        }
+      }
+    }
+  }
+}
+
+//=================================================================================================
+static void cacheContinuousFaces(const GeomShapePtr theTopLevelShape,
+                                 const SetOfShapes& theFaces,
+                                 SetOfShapes& theCache,
+                                 const double & theAngle)
+{
+  if (!theTopLevelShape || theFaces.empty())
+    return;
+
+  MapShapeAndAncestors anEdgesToFaces;
+  mapEdgesAndFaces(theTopLevelShape, anEdgesToFaces);
+
+  for (SetOfShapes::const_iterator aFIt = theFaces.begin();
+       aFIt != theFaces.end(); ++aFIt) {
+    // keep the original face
+    theCache.insert(*aFIt);
+    // cache continuous face
+    cacheContinuousFace(*aFIt, anEdgesToFaces, theCache,theAngle);
+  }
+}
+
+//=================================================================================================
+static bool updateFaces(const AttributeSelectionListPtr& theList,
+                        SetOfShapes& theFaces)
+{
+  bool aNewCache = false;
+  if (theFaces.size() != theList->size()) {
+    aNewCache = true;
+  } else {
+    for (int i = 0; i < theList->size(); i++) {
+      AttributeSelectionPtr aCurAttr = theList->value(i);
+      GeomShapePtr aFace = aCurAttr->value();
+      if (theFaces.empty() || theFaces.find(aFace) == theFaces.end()) {
+        aNewCache = true;
+        break;
+      }
+    }
+  }
+  if (aNewCache) {
+    theFaces.clear();
+    for (int i = 0; i < theList->size(); i++) {
+      AttributeSelectionPtr aCurAttr = theList->value(i);
+      GeomShapePtr aFace = aCurAttr->value();
+      theFaces.insert(aFace);
+    }
+  }
+  return aNewCache;
+}
+
+//=================================================================================================
+bool FiltersPlugin_ContinuousFaces::isSupported(GeomAPI_Shape::ShapeType theType) const
+{
+  return theType == GeomAPI_Shape::FACE;
+}
+
+//=================================================================================================
+bool FiltersPlugin_ContinuousFaces::isOk(const GeomShapePtr& theShape, const ResultPtr&,
+                                         const ModelAPI_FiltersArgs& theArgs) const
+{
+  AttributePtr aAttr = theArgs.argument("faces");
+  AttributeSelectionListPtr aList =
+    std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aAttr);
+  if (!aList.get())
+    return false;
+
+  AttributePtr anAttr = theArgs.argument("value");
+  AttributeDoublePtr aValue = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttr);
+  if (!aValue.get()|| !anAttr->isInitialized())
+    return false;
+  double anAngle= aValue->value();
+
+  bool aNewCache = updateFaces(aList,
+                               const_cast<FiltersPlugin_ContinuousFaces*>(this)->myFaces);
+
+  if (aNewCache || fabs(myAngle - anAngle) > 1e-10 ) {
+    const_cast<FiltersPlugin_ContinuousFaces*>(this)->myAngle = anAngle;
+    const_cast<FiltersPlugin_ContinuousFaces*>(this)->myCachedShapes.clear();
+  }
+
+  if (myCachedShapes.empty()) {
+    ResultBodyPtr aBaseResult = ModelAPI_Tools::bodyOwner(aList->value(0)->context(), true);
+    if (!aBaseResult.get()) {
+      aBaseResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aList->value(0)->context());
+      if (!aBaseResult.get())
+        return false;
+    }
+    cacheContinuousFaces(aBaseResult->shape(),
+                         const_cast<FiltersPlugin_ContinuousFaces*>(this)->myFaces,
+                         const_cast<FiltersPlugin_ContinuousFaces*>(this)->myCachedShapes,anAngle);
+  }
+  return myCachedShapes.find(theShape) != myCachedShapes.end();
+}
+
+//=================================================================================================
+std::string FiltersPlugin_ContinuousFaces::xmlRepresentation() const
+{
+  return xmlFromFile("filter-ContinuousFaces.xml");
+}
+
+//=================================================================================================
+void FiltersPlugin_ContinuousFaces::initAttributes(ModelAPI_FiltersArgs& theArguments)
+{
+  theArguments.initAttribute("value", ModelAPI_AttributeDouble::typeId());
+  theArguments.initAttribute("faces", ModelAPI_AttributeSelectionList::typeId());
+}
+
diff --git a/src/FiltersPlugin/FiltersPlugin_ContinuousFaces.h b/src/FiltersPlugin/FiltersPlugin_ContinuousFaces.h
new file mode 100644 (file)
index 0000000..386b2de
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright (C) 2014-2021  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 FILTERSPLUGIN_CONTINUOUSFACES_H_
+#define FILTERSPLUGIN_CONTINUOUSFACES_H_
+
+#include "FiltersPlugin.h"
+
+#include <GeomAPI_Shape.h>
+#include <ModelAPI_Filter.h>
+
+#include <set>
+
+typedef std::set<GeomShapePtr, GeomAPI_Shape::Comparator> SetOfShapes;
+
+/**\class FiltersPlugin_ContinuousFaces
+* \ingroup DataModel
+* \brief Filter for face with specific area
+*/
+class FiltersPlugin_ContinuousFaces : public ModelAPI_Filter
+{
+public:
+  FiltersPlugin_ContinuousFaces() : ModelAPI_Filter() {
+    myAngle = 0.0;
+  }
+
+  virtual const std::string& name() const {
+    static const std::string kName("Continuous faces");
+    return kName;
+  }
+
+  /// Returns true for face type
+  virtual bool isSupported(GeomAPI_Shape::ShapeType theType) const override;
+
+  /// This method should contain the filter logic. It returns true if the given shape
+  /// is accepted by the filter.
+  /// \param theShape the given shape
+  /// \param theArgs arguments of the filter
+  virtual bool isOk(const GeomShapePtr& theShape, const ResultPtr&,
+                    const ModelAPI_FiltersArgs& theArgs) const override;
+
+  /// Returns XML string which represents GUI of the filter
+  virtual std::string xmlRepresentation() const override;
+
+  /// Initializes arguments of a filter.
+  virtual void initAttributes(ModelAPI_FiltersArgs& theArguments) override;
+
+  private:
+    /// Original faces selected for filtering
+    SetOfShapes myFaces;
+    /// Shapes applicable for the filter
+    SetOfShapes myCachedShapes;
+    /// Angle tolerance
+    double myAngle;
+};
+
+#endif
diff --git a/src/FiltersPlugin/FiltersPlugin_EdgeSize.cpp b/src/FiltersPlugin/FiltersPlugin_EdgeSize.cpp
new file mode 100644 (file)
index 0000000..a5b6ff8
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright (C) 2014-2021  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 "FiltersPlugin_EdgeSize.h"
+
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_AttributeDouble.h>
+
+#include <ModelAPI_ResultBody.h>
+#include <ModelAPI_Tools.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Shape.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+#include <GeomAPI_Wire.h>
+
+#include <Precision.hxx>
+
+#include <map>
+#include <iostream>
+
+
+bool FiltersPlugin_EdgeSize::isSupported(GeomAPI_Shape::ShapeType theType) const
+{
+  return theType == GeomAPI_Shape::EDGE;
+}
+
+bool FiltersPlugin_EdgeSize::isOk(const GeomShapePtr& theShape, const ResultPtr&,
+                                  const ModelAPI_FiltersArgs& theArgs) const
+{
+  AttributePtr anAttr = theArgs.argument("value");
+  AttributeDoublePtr aValue = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttr);
+  if (!aValue.get()|| !anAttr->isInitialized() )
+    return false;
+  double aVal = aValue->value();
+
+  anAttr = theArgs.argument("valueMax");
+  aValue = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttr);
+  if (!aValue.get()|| !anAttr->isInitialized() )
+    return false;
+  double aValMax = aValue->value();
+
+  if (aVal < 0.0)
+    return false;
+
+  GeomEdgePtr anEdge;
+  switch (theShape->shapeType()) {
+  case GeomAPI_Shape::EDGE:
+    anEdge = GeomEdgePtr(new GeomAPI_Edge(theShape));
+    break;
+  case GeomAPI_Shape::WIRE:
+    anEdge = GeomAlgoAPI_ShapeTools::wireToEdge(
+        GeomWirePtr(new GeomAPI_Wire(theShape)));
+    break;
+  default:
+    return false;
+  }
+  double aLength = anEdge->length();
+
+  anAttr = theArgs.argument("comparatorType");
+  AttributeStringPtr aCompAttr = std::dynamic_pointer_cast<ModelAPI_AttributeString>(anAttr);
+  if (!aCompAttr)
+    return false;
+  std::string aCompString = aCompAttr->value();
+
+  bool isOK = false;
+  if (aCompString == "inf")
+    isOK = aLength < aVal && fabs(aLength - aVal) > Precision::Confusion();
+  else if (aCompString == "infEq")
+    isOK = aLength < aVal || fabs(aLength - aVal) < Precision::Confusion();
+  else if (aCompString == "sup")
+    isOK = aLength > aVal && fabs(aLength - aVal) > Precision::Confusion();
+  else if (aCompString == "supEq")
+    isOK = aLength > aVal || fabs(aLength - aVal) < Precision::Confusion();
+  else if (aCompString == "isBetween")
+    isOK = (aLength > aVal || fabs(aLength - aVal) < Precision::Confusion())
+          && (aLength < aValMax || fabs(aLength - aVal) < Precision::Confusion());
+  else if (aCompString == "isStrictlyBetween")
+    isOK = (aLength > aVal && fabs(aLength - aVal) > Precision::Confusion())
+           && (aLength < aValMax && fabs(aLength - aValMax) > Precision::Confusion());
+  return isOK;
+}
+
+std::string FiltersPlugin_EdgeSize::xmlRepresentation() const
+{
+  return xmlFromFile("filter-EdgeSize.xml");
+}
+
+void FiltersPlugin_EdgeSize::initAttributes(ModelAPI_FiltersArgs& theArguments)
+{
+  theArguments.initAttribute("comparatorType", ModelAPI_AttributeString::typeId());
+  theArguments.initAttribute("value", ModelAPI_AttributeDouble::typeId());
+  theArguments.initAttribute("valueMax", ModelAPI_AttributeDouble::typeId());
+}
+
diff --git a/src/FiltersPlugin/FiltersPlugin_EdgeSize.h b/src/FiltersPlugin/FiltersPlugin_EdgeSize.h
new file mode 100644 (file)
index 0000000..fc53fec
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright (C) 2014-2021  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 FILTERSPLUGIN_EDGESIZE_H_
+#define FILTERSPLUGIN_EDGESIZE_H_
+
+#include "FiltersPlugin.h"
+
+#include <GeomAPI_Shape.h>
+#include <ModelAPI_Filter.h>
+
+/**\class FiltersPlugin_EdgeSize
+* \ingroup DataModel
+* \brief Filter for edges with specific size
+*/
+class FiltersPlugin_EdgeSize : public ModelAPI_Filter
+{
+public:
+  FiltersPlugin_EdgeSize() : ModelAPI_Filter() {}
+
+  virtual const std::string& name() const {
+    static const std::string kName("Edge size");
+    return kName;
+  }
+
+  /// Returns true for edge type
+  virtual bool isSupported(GeomAPI_Shape::ShapeType theType) const override;
+
+  /// This method should contain the filter logic. It returns true if the given shape
+  /// is accepted by the filter.
+  /// \param theShape the given shape
+  /// \param theArgs arguments of the filter
+  virtual bool isOk(const GeomShapePtr& theShape, const ResultPtr&,
+                    const ModelAPI_FiltersArgs& theArgs) const override;
+
+  /// Returns XML string which represents GUI of the filter
+  virtual std::string xmlRepresentation() const override;
+
+  /// Initializes arguments of a filter.
+  virtual void initAttributes(ModelAPI_FiltersArgs& theArguments) override;
+
+};
+
+#endif
diff --git a/src/FiltersPlugin/FiltersPlugin_FaceSize.cpp b/src/FiltersPlugin/FiltersPlugin_FaceSize.cpp
new file mode 100644 (file)
index 0000000..52633b8
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright (C) 2014-2021  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 "FiltersPlugin_FaceSize.h"
+
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_AttributeDouble.h>
+
+#include <ModelAPI_Tools.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Shape.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+#include <GeomAPI_Wire.h>
+#include <GeomAlgoAPI_BasicProperties.h>
+
+#include <Precision.hxx>
+
+#include <map>
+#include <iostream>
+
+
+bool FiltersPlugin_FaceSize::isSupported(GeomAPI_Shape::ShapeType theType) const
+{
+  return theType == GeomAPI_Shape::FACE;
+}
+
+bool FiltersPlugin_FaceSize::isOk(const GeomShapePtr& theShape, const ResultPtr&,
+                                  const ModelAPI_FiltersArgs& theArgs) const
+{
+  AttributePtr anAttr = theArgs.argument("value");
+  AttributeDoublePtr aValue = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttr);
+  if (!aValue.get()|| !anAttr->isInitialized() )
+    return false;
+  double aVal = aValue->value();
+
+  anAttr = theArgs.argument("valueMax");
+  aValue = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttr);
+  if (!aValue.get()|| !anAttr->isInitialized() )
+    return false;
+  double aValMax = aValue->value();
+
+    if (aVal < 0.0)
+    return false;
+
+  double aTolerance = 0.0001;
+  double aLength;
+  double aSurfArea;
+  double aVolume;
+  std::string aError;
+  if( !GetBasicProperties(theShape,
+                          aTolerance,
+                          aLength,
+                          aSurfArea,
+                          aVolume,
+                          aError) )
+      return false;
+
+  anAttr = theArgs.argument("comparatorType");
+  AttributeStringPtr aCompAttr = std::dynamic_pointer_cast<ModelAPI_AttributeString>(anAttr);
+  if (!aCompAttr)
+    return false;
+  std::string aCompString = aCompAttr->value();
+
+  bool isOK = false;
+  if (aCompString == "inf")
+    isOK = aSurfArea < aVal && fabs(aSurfArea - aVal) > Precision::Confusion();
+  else if (aCompString == "infEq")
+    isOK = aSurfArea < aVal || fabs(aSurfArea - aVal) < Precision::Confusion();
+  else if (aCompString == "sup")
+    isOK = aSurfArea > aVal && fabs(aSurfArea - aVal) > Precision::Confusion();
+  else if (aCompString == "supEq")
+    isOK = aSurfArea > aVal || fabs(aSurfArea - aVal) < Precision::Confusion();
+  else if (aCompString == "isBetween")
+    isOK = (aSurfArea > aVal || fabs(aSurfArea - aVal) < Precision::Confusion())
+          && (aSurfArea < aValMax || fabs(aSurfArea - aVal) < Precision::Confusion());
+  else if (aCompString == "isStrictlyBetween")
+    isOK = (aSurfArea > aVal && fabs(aSurfArea - aVal) > Precision::Confusion())
+           && (aSurfArea < aValMax && fabs(aSurfArea - aValMax) > Precision::Confusion());
+  return isOK;
+}
+
+std::string FiltersPlugin_FaceSize::xmlRepresentation() const
+{
+  return xmlFromFile("filter-FaceSize.xml");
+}
+
+void FiltersPlugin_FaceSize::initAttributes(ModelAPI_FiltersArgs& theArguments)
+{
+  theArguments.initAttribute("comparatorType", ModelAPI_AttributeString::typeId());
+  theArguments.initAttribute("value", ModelAPI_AttributeDouble::typeId());
+  theArguments.initAttribute("valueMax", ModelAPI_AttributeDouble::typeId());
+}
+
diff --git a/src/FiltersPlugin/FiltersPlugin_FaceSize.h b/src/FiltersPlugin/FiltersPlugin_FaceSize.h
new file mode 100644 (file)
index 0000000..588e745
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright (C) 2014-2021  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 FILTERSPLUGIN_FACESIZE_H_
+#define FILTERSPLUGIN_FACESIZE_H_
+
+#include "FiltersPlugin.h"
+
+#include <GeomAPI_Shape.h>
+#include <ModelAPI_Filter.h>
+
+
+/**\class FiltersPlugin_FaceSize
+* \ingroup DataModel
+* \brief Filter for face with specific area
+*/
+class FiltersPlugin_FaceSize : public ModelAPI_Filter
+{
+public:
+  FiltersPlugin_FaceSize() : ModelAPI_Filter() {}
+
+  virtual const std::string& name() const {
+    static const std::string kName("Face size");
+    return kName;
+  }
+
+  /// Returns true for face type
+  virtual bool isSupported(GeomAPI_Shape::ShapeType theType) const override;
+
+  /// This method should contain the filter logic. It returns true if the given shape
+  /// is accepted by the filter.
+  /// \param theShape the given shape
+  /// \param theArgs arguments of the filter
+  virtual bool isOk(const GeomShapePtr& theShape, const ResultPtr&,
+                    const ModelAPI_FiltersArgs& theArgs) const override;
+
+  /// Returns XML string which represents GUI of the filter
+  virtual std::string xmlRepresentation() const override;
+
+  /// Initializes arguments of a filter.
+  virtual void initAttributes(ModelAPI_FiltersArgs& theArguments) override;
+
+};
+
+#endif
diff --git a/src/FiltersPlugin/FiltersPlugin_FeatureEdges.cpp b/src/FiltersPlugin/FiltersPlugin_FeatureEdges.cpp
new file mode 100644 (file)
index 0000000..79dd0aa
--- /dev/null
@@ -0,0 +1,142 @@
+// Copyright (C) 2014-2021  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 "FiltersPlugin_FeatureEdges.h"
+
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_AttributeDouble.h>
+
+#include <ModelAPI_ResultBody.h>
+#include <ModelAPI_Tools.h>
+#include <GeomAPI_ShapeExplorer.h>
+#include <GeomAlgoAPI_ContinuousFaces.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Shape.h>
+#include <GeomAPI_Wire.h>
+
+#include <map>
+#include <math.h>
+#include <iostream>
+
+typedef std::map<GeomShapePtr, SetOfShapes, GeomAPI_Shape::Comparator> MapShapeAndAncestors;
+
+//=================================================================================================
+static void mapEdgesAndFaces(const GeomShapePtr theShape, MapShapeAndAncestors& theMap)
+{
+  GeomAPI_ShapeExplorer aFExp(theShape, GeomAPI_Shape::FACE);
+  for (; aFExp.more(); aFExp.next()) {
+    GeomShapePtr aFace = aFExp.current();
+    GeomAPI_ShapeExplorer aEExp(aFace, GeomAPI_Shape::EDGE);
+    for (; aEExp.more(); aEExp.next())
+      theMap[aEExp.current()].insert(aFace);
+  }
+}
+
+//=================================================================================================
+static void cacheFeatureEdge(const GeomShapePtr theTopLevelShape,
+                             SetOfShapes& theCache,
+                             const double & theAngle)
+{
+  if (!theTopLevelShape)
+    return;
+
+  MapShapeAndAncestors anEdgesToFaces;
+  mapEdgesAndFaces(theTopLevelShape, anEdgesToFaces);
+
+  MapShapeAndAncestors::const_iterator aIt;
+  for (aIt = anEdgesToFaces.begin(); aIt != anEdgesToFaces.end(); ++aIt) {
+    GeomEdgePtr anEdge;
+    anEdge = GeomEdgePtr(new GeomAPI_Edge(aIt->first));
+
+    for (SetOfShapes::const_iterator aFIt = aIt->second.begin();
+         aFIt != aIt->second.end(); ++aFIt) {
+      SetOfShapes::const_iterator aFIt2 = aFIt;
+      ++aFIt2;
+      for (;aFIt2 != aIt->second.end(); ++aFIt2) {
+        std::string anError;
+        if (theCache.find(*aFIt) == theCache.end()) {
+          if (!isContinuousFaces(*aFIt,
+                                 *aFIt2,
+                                 anEdge->middlePoint(),
+                                 theAngle,
+                                 anError)) {
+            if( anError.empty())
+              theCache.insert(anEdge);
+          }
+        }
+      }
+    }
+  }
+}
+
+//=================================================================================================
+bool FiltersPlugin_FeatureEdges::isSupported(GeomAPI_Shape::ShapeType theType) const
+{
+  return theType == GeomAPI_Shape::EDGE;
+}
+
+//=================================================================================================
+bool FiltersPlugin_FeatureEdges::isOk(const GeomShapePtr& theShape, const ResultPtr& theResult,
+                                      const ModelAPI_FiltersArgs& theArgs) const
+{
+  AttributePtr anAttr = theArgs.argument("value");
+  AttributeDoublePtr aValue = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttr);
+
+  if (!aValue.get() || !anAttr->isInitialized())
+    return false;
+  double anAngle = aValue->value();
+
+  // check base result
+  ResultBodyPtr aBaseResult = ModelAPI_Tools::bodyOwner(theResult, true);
+  if (!aBaseResult) {
+    aBaseResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(theResult);
+    if (!aBaseResult.get()) {
+      return false;
+    }
+  }
+  if (fabs(myAngle - anAngle) > 1e-10
+      || !myBaseShape
+      || !myBaseShape->isSame(aBaseResult->shape())) {
+    const_cast<FiltersPlugin_FeatureEdges*>(this)->myAngle = anAngle;
+    const_cast<FiltersPlugin_FeatureEdges*>(this)->myBaseShape = aBaseResult->shape();
+    const_cast<FiltersPlugin_FeatureEdges*>(this)->myCachedShapes.clear();
+  }
+
+  if (myCachedShapes.empty()) {
+
+    cacheFeatureEdge(aBaseResult->shape(),
+                     const_cast<FiltersPlugin_FeatureEdges*>(this)->myCachedShapes, anAngle);
+  }
+
+  return myCachedShapes.find(theShape) != myCachedShapes.end();
+}
+
+//=================================================================================================
+std::string FiltersPlugin_FeatureEdges::xmlRepresentation() const
+{
+  return xmlFromFile("filter-FeatureEdges.xml");
+}
+
+//=================================================================================================
+void FiltersPlugin_FeatureEdges::initAttributes(ModelAPI_FiltersArgs& theArguments)
+{
+  theArguments.initAttribute("value", ModelAPI_AttributeDouble::typeId());
+}
+
diff --git a/src/FiltersPlugin/FiltersPlugin_FeatureEdges.h b/src/FiltersPlugin/FiltersPlugin_FeatureEdges.h
new file mode 100644 (file)
index 0000000..536bfee
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright (C) 2014-2021  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 FILTERSPLUGIN_FEATUREEDGES_H_
+#define FILTERSPLUGIN_FEATUREEDGES_H_
+
+#include "FiltersPlugin.h"
+
+#include <GeomAPI_Shape.h>
+#include <ModelAPI_Filter.h>
+
+#include <set>
+
+typedef std::set<GeomShapePtr, GeomAPI_Shape::Comparator> SetOfShapes;
+
+/**\class FiltersPlugin_FeatureEdges
+* \ingroup DataModel
+* \brief Filter for edges with feature angle
+*/
+class FiltersPlugin_FeatureEdges : public ModelAPI_Filter
+{
+public:
+  FiltersPlugin_FeatureEdges() : ModelAPI_Filter() {
+    myAngle = 0.0;
+  }
+
+  virtual const std::string& name() const {
+    static const std::string kName("Feature edges");
+    return kName;
+  }
+
+  /// Returns true for edge type
+  virtual bool isSupported(GeomAPI_Shape::ShapeType theType) const override;
+
+  /// This method should contain the filter logic. It returns true if the given shape
+  /// is accepted by the filter.
+  /// \param theShape the given shape
+  /// \param theArgs arguments of the filter
+  virtual bool isOk(const GeomShapePtr& theShape, const ResultPtr&,
+                    const ModelAPI_FiltersArgs& theArgs) const override;
+
+  /// Returns XML string which represents GUI of the filter
+  virtual std::string xmlRepresentation() const override;
+
+  /// Initializes arguments of a filter.
+  virtual void initAttributes(ModelAPI_FiltersArgs& theArguments) override;
+
+  private:
+    /// Shapes applicable for the filter
+    SetOfShapes myCachedShapes;
+    /// Angle tolerance
+    double myAngle;
+    /// the base shape
+    GeomShapePtr myBaseShape;
+};
+
+#endif
index db708db90bd3a019c807bab926c7f9856ca11cc9..343cdd2674882e3f08f707a77b22197cc5fb1c11 100644 (file)
 #include "FiltersPlugin_OnGeometry.h"
 #include "FiltersPlugin_OnPlaneSide.h"
 #include "FiltersPlugin_OppositeToEdge.h"
+#include "FiltersPlugin_EdgeSize.h"
+#include "FiltersPlugin_FaceSize.h"
+#include "FiltersPlugin_FeatureEdges.h"
+#include "FiltersPlugin_ContinuousFaces.h"
+#include "FiltersPlugin_VolumeSize.h"
 #include "FiltersPlugin_RelativeToSolid.h"
 #include "FiltersPlugin_ExternalFaces.h"
 #include "FiltersPlugin_Validators.h"
@@ -54,6 +59,11 @@ FiltersPlugin_Plugin::FiltersPlugin_Plugin()
   aFactory->registerFilter("OppositeToEdge", new FiltersPlugin_OppositeToEdge);
   aFactory->registerFilter("RelativeToSolid", new FiltersPlugin_RelativeToSolid);
   aFactory->registerFilter("ExternalFaces", new FiltersPlugin_ExternalFaces);
+  aFactory->registerFilter("EdgeSize", new FiltersPlugin_EdgeSize);
+  aFactory->registerFilter("FaceSize", new FiltersPlugin_FaceSize);
+  aFactory->registerFilter("VolumeSize", new FiltersPlugin_VolumeSize);
+  aFactory->registerFilter("FeatureEdges", new FiltersPlugin_FeatureEdges);
+  aFactory->registerFilter("ContinuousFaces", new FiltersPlugin_ContinuousFaces);
 
   Config_ModuleReader::loadScript("FiltersPlugin_TopoConnectedFaces");
 
diff --git a/src/FiltersPlugin/FiltersPlugin_VolumeSize.cpp b/src/FiltersPlugin/FiltersPlugin_VolumeSize.cpp
new file mode 100644 (file)
index 0000000..c50b58d
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright (C) 2014-2021  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 "FiltersPlugin_VolumeSize.h"
+
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_AttributeDouble.h>
+
+#include <ModelAPI_Tools.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Shape.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+#include <GeomAPI_Wire.h>
+#include <GeomAlgoAPI_BasicProperties.h>
+
+#include <Precision.hxx>
+
+#include <map>
+#include <iostream>
+
+
+bool FiltersPlugin_VolumeSize::isSupported(GeomAPI_Shape::ShapeType theType) const
+{
+  return theType == GeomAPI_Shape::SOLID;
+}
+
+bool FiltersPlugin_VolumeSize::isOk(const GeomShapePtr& theShape, const ResultPtr&,
+                                  const ModelAPI_FiltersArgs& theArgs) const
+{
+  AttributePtr anAttr = theArgs.argument("value");
+  AttributeDoublePtr aValue = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttr);
+  if (!aValue.get()|| !anAttr->isInitialized() )
+    return false;
+  double aVal = aValue->value();
+
+  anAttr = theArgs.argument("valueMax");
+  aValue = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttr);
+  if (!aValue.get()|| !anAttr->isInitialized() )
+    return false;
+  double aValMax = aValue->value();
+
+  if (aVal < 0.0)
+    return false;
+
+  double aTolerance = 0.0001;
+  double aLength;
+  double aSurfArea;
+  double aVolume;
+  std::string aError;
+  if( !GetBasicProperties(theShape,
+                          aTolerance,
+                          aLength,
+                          aSurfArea,
+                          aVolume,
+                          aError) )
+      return false;
+
+  anAttr = theArgs.argument("comparatorType");
+  AttributeStringPtr aCompAttr = std::dynamic_pointer_cast<ModelAPI_AttributeString>(anAttr);
+  if (!aCompAttr)
+    return false;
+  std::string aCompString = aCompAttr->value();
+
+  bool isOK = false;
+  if (aCompString == "inf")
+    isOK = aVolume < aVal && fabs(aVolume - aVal) > Precision::Confusion();
+  else if (aCompString == "infEq")
+    isOK = aVolume < aVal || fabs(aVolume - aVal) < Precision::Confusion();
+  else if (aCompString == "sup")
+    isOK = aVolume > aVal && fabs(aVolume - aVal) > Precision::Confusion();
+  else if (aCompString == "supEq")
+    isOK = aVolume > aVal || fabs(aVolume - aVal) < Precision::Confusion();
+  else if (aCompString == "isBetween")
+    isOK = (aVolume > aVal || fabs(aVolume - aVal) < Precision::Confusion())
+          && (aVolume < aValMax || fabs(aVolume - aVal) < Precision::Confusion());
+  else if (aCompString == "isStrictlyBetween")
+    isOK = (aVolume > aVal && fabs(aVolume - aVal) > Precision::Confusion())
+           && (aVolume < aValMax && fabs(aVolume - aValMax) > Precision::Confusion());
+  return isOK;
+}
+
+std::string FiltersPlugin_VolumeSize::xmlRepresentation() const
+{
+  return xmlFromFile("filter-VolumeSize.xml");
+}
+
+void FiltersPlugin_VolumeSize::initAttributes(ModelAPI_FiltersArgs& theArguments)
+{
+  theArguments.initAttribute("comparatorType", ModelAPI_AttributeString::typeId());
+  theArguments.initAttribute("value", ModelAPI_AttributeDouble::typeId());
+  theArguments.initAttribute("valueMax", ModelAPI_AttributeDouble::typeId());
+}
+
diff --git a/src/FiltersPlugin/FiltersPlugin_VolumeSize.h b/src/FiltersPlugin/FiltersPlugin_VolumeSize.h
new file mode 100644 (file)
index 0000000..1dfbf13
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright (C) 2014-2021  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 FILTERSPLUGIN_VOLUMESIZE_H_
+#define FILTERSPLUGIN_VOLUMESIZE_H_
+
+#include "FiltersPlugin.h"
+
+#include <GeomAPI_Shape.h>
+#include <ModelAPI_Filter.h>
+
+
+/**\class FiltersPlugin_VolumeSize
+* \ingroup DataModel
+* \brief Filter for solid with specific area
+*/
+class FiltersPlugin_VolumeSize : public ModelAPI_Filter
+{
+public:
+  FiltersPlugin_VolumeSize() : ModelAPI_Filter() {}
+
+  virtual const std::string& name() const {
+    static const std::string kName("Volume size");
+    return kName;
+  }
+
+  /// Returns true for face type
+  virtual bool isSupported(GeomAPI_Shape::ShapeType theType) const override;
+
+  /// This method should contain the filter logic. It returns true if the given shape
+  /// is accepted by the filter.
+  /// \param theShape the given shape
+  /// \param theArgs arguments of the filter
+  virtual bool isOk(const GeomShapePtr& theShape, const ResultPtr&,
+                    const ModelAPI_FiltersArgs& theArgs) const override;
+
+  /// Returns XML string which represents GUI of the filter
+  virtual std::string xmlRepresentation() const override;
+
+  /// Initializes arguments of a filter.
+  virtual void initAttributes(ModelAPI_FiltersArgs& theArguments) override;
+
+};
+
+#endif
index 16b245820d899be39917c06e3690113bc11d9bb4..622d9f09cf2cc1509938e28e9d7e5ecb19fc3c4b 100644 (file)
       <source>Belongs to</source>
       <translation>Appartient à</translation>
     </message>
+    <message>
+      <source>Edge size</source>
+      <translation>Taille d'arête</translation>
+    </message>
     <message>
       <source>External faces</source>
       <translation>Externe faces</translation>
     </message>
+    <message>
+      <source>Continuous faces</source>
+      <translation>Faces continues</translation>
+    </message>
+    <message>
+      <source>Feature edges</source>
+      <translation>Arêtes caractéristiques</translation>
+    </message>
+    <message>
+      <source>Face size</source>
+      <translation>Surface de face</translation>
+    </message>
     <message>
       <source>Horizontal faces</source>
       <translation>Faces horizontales</translation>
       <source>Vertical faces</source>
       <translation>Faces verticales</translation>
     </message>
+    <message>
+      <source>Volume size</source>
+      <translation>volume</translation>
+    </message>
     <message>
       <source>Attribute "%1" is not initialized.</source>
       <translation>Sélectionnez un objet.</translation>
       <translation>Sélectionner des objets pour limiter la sélection</translation>
     </message>
   </context>
+  <!-- Edge size -->
+  <context>
+    <name>EdgeSize</name>
+    <message>
+      <source>Size</source>
+      <translation>Longueur</translation>
+    </message>
+    <message>
+      <source>Min size</source>
+      <translation>Longueur Min</translation>
+    </message>
+    <message>
+      <source>Max size</source>
+      <translation>Longueur Max</translation>
+    </message>
+    <message>
+      <source>is between</source>
+      <translation>est compris entre</translation>
+    </message>
+    <message>
+      <source>is strictly between</source>
+      <translation>est compris strictement entre</translation>
+    </message>
+  </context>
+  
+  <!-- Face size -->
+  <context>
+    <name>FaceSize</name>
+    <message>
+      <source>Size</source>
+      <translation>Longueur</translation>
+    </message>
+    <message>
+      <source>Min size</source>
+      <translation>Longueur Min</translation>
+    </message>
+    <message>
+      <source>Max size</source>
+      <translation>Longueur Max</translation>
+    </message>
+    <message>
+      <source>is between</source>
+      <translation>est compris entre</translation>
+    </message>
+    <message>
+      <source>is strictly between</source>
+      <translation>est compris strictement entre</translation>
+    </message>
+  </context>
+
+  <!-- Volume size -->
+  <context>
+    <name>VolumeSize</name>
+    <message>
+      <source>Size</source>
+      <translation>Longueur</translation>
+    </message>
+    <message>
+      <source>Min size</source>
+      <translation>Longueur min</translation>
+    </message>
+    <message>
+      <source>Max size</source>
+      <translation>Longueur max</translation>
+    </message>
+    <message>
+      <source>is between</source>
+      <translation>est compris entre</translation>
+    </message>
+    <message>
+      <source>is strictly between</source>
+      <translation>est compris strictement entre</translation>
+    </message>
+  </context>
 
   <!-- OnGeometry -->
   <context>
diff --git a/src/FiltersPlugin/Test/TestFilter_ContinuousFaces.py b/src/FiltersPlugin/Test/TestFilter_ContinuousFaces.py
new file mode 100644 (file)
index 0000000..7df65fe
--- /dev/null
@@ -0,0 +1,87 @@
+# Copyright (C) 2014-2021  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 SketchAPI import *
+from GeomAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+
+###===========Test with fillet on solide===========================================================
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Box
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+
+### Create Fillet
+Fillet_1_objects_4 = [model.selection("FACE", "Box_1_1/Left"),
+                      model.selection("FACE", "Box_1_1/Front"),
+                      model.selection("FACE", "Box_1_1/Top"),
+                      model.selection("FACE", "Box_1_1/Right"),
+                      model.selection("FACE", "Box_1_1/Bottom")]
+Fillet_1 = model.addFillet(Part_1_doc, Fillet_1_objects_4, 2, keepSubResults = True)
+
+model.end()
+
+model.do()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "ContinuousFaces", args = [model.selection("FACE", "Fillet_1_1/MF:Fillet&Box_1_1/Left"), 5.0 ])])
+model.end()
+
+Reference = {}
+ResultFillet_1_1 = Fillet_1.result().resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(ResultFillet_1_1.shape(), GeomAPI_Shape.FACE)
+while exp.more():
+  Reference[model.selection(ResultFillet_1_1, exp.current())] = True
+  exp.next()
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+###===========Test with Chamfer by an angle of 43° on solid and filters with angle 50 ===========
+
+### Create Part
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+
+### Create Box
+Box_3 = model.addBox(Part_2_doc, 10, 10, 10)
+
+### Create Chamfer
+Chamfer_1_objects = [model.selection("FACE", "Box_1_1/Left"),
+                     model.selection("FACE", "Box_1_1/Front"),
+                     model.selection("FACE", "Box_1_1/Top"),
+                     model.selection("FACE", "Box_1_1/Right"),
+                     model.selection("FACE", "Box_1_1/Bottom")]
+Chamfer_2 = model.addChamfer(Part_2_doc, Chamfer_1_objects, False, 2, 43, keepSubResults = True)
+
+model.end()
+
+model.do()
+Filters = model.filters(Part_2_doc, [model.addFilter(name = "ContinuousFaces", args = [model.selection("FACE", "Chamfer_1_1/MF:Chamfer&Box_1_1/Left"), 50.0 ])])
+model.end()
+
+Reference = {}
+ResultChamfer_2_1 = Chamfer_2.result().resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(ResultChamfer_2_1.shape(), GeomAPI_Shape.FACE)
+while exp.more():
+  Reference[model.selection(ResultChamfer_2_1, exp.current())] = True
+  exp.next()
+model.checkFilter(Part_2_doc, model, Filters, Reference)
diff --git a/src/FiltersPlugin/Test/TestFilter_EdgeSize.py b/src/FiltersPlugin/Test/TestFilter_EdgeSize.py
new file mode 100644 (file)
index 0000000..d0a13f4
--- /dev/null
@@ -0,0 +1,170 @@
+# Copyright (C) 2014-2021  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 SketchAPI import *
+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, 100, 50, 100)
+
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "EdgeSize", args = [ "inf" , 60.0 ])])
+
+model.end()
+Reference = {
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Bottom]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Bottom]"): True,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"): False,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Left]"): False,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"): False,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"): False,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"): False,
+    model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"): False,
+    model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Top]"): False,
+    model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]"): False}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "EdgeSize", args = [ "sup" , 60.0 ])])
+model.end()
+
+Reference = {
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Bottom]"): False,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"): False,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Bottom]"): False,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"): False,
+    model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Left]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"): True,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"): True,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"): True,
+    model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"): True,
+    model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]"): True}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "EdgeSize", args = [ "inf" , 50.0 ])])
+model.end()
+
+Reference = {
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Bottom]"): False,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"): False,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Bottom]"): False,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"): False,
+    model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"): False,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Left]"): False,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"): False,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"): False,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"): False,
+    model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"): False,
+    model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Top]"): False,
+    model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]"): False}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "EdgeSize", args = [ "infEq" , 50.0 ])])
+model.end()
+
+Reference = {
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Bottom]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Bottom]"): True,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"): False,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Left]"): False,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"): False,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"): False,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"): False,
+    model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"): False,
+    model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Top]"): False,
+    model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]"): False}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "EdgeSize", args = [ "supEq" , 50.0 ])])
+model.end()
+
+Reference = {
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Bottom]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Bottom]"): True,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Left]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"): True,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"): True,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"): True,
+    model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"): True,
+    model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]"): True}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "EdgeSize", args = [ "isBetween" , 50.0 , 200.0])])
+model.end()
+
+Reference = {
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Bottom]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Bottom]"): True,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Left]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"): True,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"): True,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"): True,
+    model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"): True,
+    model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]"): True}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "EdgeSize", args = [ "isStrictlyBetween" , 50.0 , 200.0])])
+model.end()
+
+Reference = {
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Bottom]"): False,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"): False,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Bottom]"): False,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"): False,
+    model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Left]"): True,
+    model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"): True,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"): True,
+    model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"): True,
+    model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"): True,
+    model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Top]"): True,
+    model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]"): True}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
diff --git a/src/FiltersPlugin/Test/TestFilter_FaceSize.py b/src/FiltersPlugin/Test/TestFilter_FaceSize.py
new file mode 100644 (file)
index 0000000..8b12826
--- /dev/null
@@ -0,0 +1,142 @@
+# Copyright (C) 2014-2021  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 SketchAPI import *
+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, 100, 50, 100)
+
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "FaceSize", args = [ "inf" , 5000.0 ])])
+
+model.end()
+Reference = {
+    model.selection("FACE", "Box_1_1/Top"): False,
+    model.selection("FACE", "Box_1_1/Back"): False,
+    model.selection("FACE", "Box_1_1/Front"): False,
+    model.selection("FACE", "Box_1_1/Bottom"): False,
+    model.selection("FACE","Box_1_1/Right"): False,
+    model.selection("FACE","Box_1_1/Left"): False}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "FaceSize", args = [ "infEq" , 5000.0 ])])
+model.end()
+
+Reference = {
+    model.selection("FACE", "Box_1_1/Top"): True,
+    model.selection("FACE", "Box_1_1/Back"): True,
+    model.selection("FACE", "Box_1_1/Front"): True,
+    model.selection("FACE", "Box_1_1/Bottom"): True,
+    model.selection("FACE", "Box_1_1/Right"): False,
+    model.selection("FACE", "Box_1_1/Left"): False}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "FaceSize", args = [ "sup" , 5000.0 ])])
+model.end()
+
+Reference = {
+    model.selection("FACE", "Box_1_1/Top"): False,
+    model.selection("FACE", "Box_1_1/Back"): False,
+    model.selection("FACE", "Box_1_1/Front"): False,
+    model.selection("FACE", "Box_1_1/Bottom"): False,
+    model.selection("FACE", "Box_1_1/Right"): True,
+    model.selection("FACE", "Box_1_1/Left"): True}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "FaceSize", args = [ "inf" , 50.0 ])])
+model.end()
+
+Reference = {
+    model.selection("FACE", "Box_1_1/Top"): False,
+    model.selection("FACE", "Box_1_1/Back"): False,
+    model.selection("FACE", "Box_1_1/Front"): False,
+    model.selection("FACE", "Box_1_1/Bottom"): False,
+    model.selection("FACE", "Box_1_1/Right"): False,
+    model.selection("FACE", "Box_1_1/Left"): False}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "FaceSize", args = [ "supEq" , 5000.0 ])])
+model.end()
+
+Reference = {
+    model.selection("FACE", "Box_1_1/Top"): True,
+    model.selection("FACE", "Box_1_1/Back"): True,
+    model.selection("FACE", "Box_1_1/Front"): True,
+    model.selection("FACE", "Box_1_1/Bottom"): True,
+    model.selection("FACE", "Box_1_1/Right"): True,
+    model.selection("FACE", "Box_1_1/Left"): True}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "FaceSize", args = [ "supEq" , 7000.0 ])])
+model.end()
+
+Reference = {
+    model.selection("FACE", "Box_1_1/Top"): False,
+    model.selection("FACE", "Box_1_1/Back"): False,
+    model.selection("FACE", "Box_1_1/Front"): False,
+    model.selection("FACE", "Box_1_1/Bottom"): False,
+    model.selection("FACE", "Box_1_1/Right"): True,
+    model.selection("FACE", "Box_1_1/Left"): True}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "FaceSize", args = [ "isBetween" , 50.0 , 10000.0])])
+model.end()
+
+Reference = {
+    model.selection("FACE", "Box_1_1/Top"): True,
+    model.selection("FACE", "Box_1_1/Back"): True,
+    model.selection("FACE", "Box_1_1/Front"): True,
+    model.selection("FACE", "Box_1_1/Bottom"): True,
+    model.selection("FACE", "Box_1_1/Right"): True,
+    model.selection("FACE", "Box_1_1/Left"): True}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "FaceSize", args = [ "isStrictlyBetween" , 500.0 , 10000.0])])
+model.end()
+
+Reference = {
+    model.selection("FACE", "Box_1_1/Top"): True,
+    model.selection("FACE", "Box_1_1/Back"): True,
+    model.selection("FACE", "Box_1_1/Front"): True,
+    model.selection("FACE", "Box_1_1/Bottom"): True,
+    model.selection("FACE", "Box_1_1/Right"): False,
+    model.selection("FACE", "Box_1_1/Left"): False}
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
diff --git a/src/FiltersPlugin/Test/TestFilter_FeatureEdges.py b/src/FiltersPlugin/Test/TestFilter_FeatureEdges.py
new file mode 100644 (file)
index 0000000..324b987
--- /dev/null
@@ -0,0 +1,124 @@
+# Copyright (C) 2014-2021  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 SketchAPI import *
+from GeomAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+
+###===========Test with chamfer on face=========================================================
+
+### 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 Chamfer
+Chamfer_1 = model.addChamfer(Part_1_doc, [model.selection("FACE", "Box_1_1/Left")], True, 2, 2, keepSubResults = True)
+
+model.do()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "FeatureEdges",  args = [ 5.0 ])])
+model.end()
+
+Reference = {}
+ResultChamfer_1_1 = Chamfer_1.result().resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(ResultChamfer_1_1.shape(), GeomAPI_Shape.EDGE)
+while exp.more():
+  Reference[model.selection(ResultChamfer_1_1, exp.current())] = True
+  exp.next()
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.do()
+
+###===========Test with fillet on solide===========================================================
+
+### Create Part
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+
+### Create Box
+Box_2 = model.addBox(Part_2_doc, 10, 10, 10)
+
+### Create Fillet
+Fillet_1_objects_4 = [model.selection("FACE", "Box_1_1/Left"),
+                      model.selection("FACE", "Box_1_1/Front"),
+                      model.selection("FACE", "Box_1_1/Top"),
+                      model.selection("FACE", "Box_1_1/Right"),
+                      model.selection("FACE", "Box_1_1/Bottom")]
+Fillet_1 = model.addFillet(Part_2_doc, Fillet_1_objects_4, 2, keepSubResults = True)
+
+model.end()
+
+model.do()
+Filters = model.filters(Part_2_doc, [model.addFilter(name = "FeatureEdges",  args = [ 5.0 ])])
+model.end()
+
+
+###===========Test with Chamfer by an angle of 43° and filters with angle 30 and 50 ===========
+Reference = {}
+ResultFillet_1_1 = Fillet_1.result().resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(ResultFillet_1_1.shape(), GeomAPI_Shape.EDGE)
+while exp.more():
+  Reference[model.selection(ResultFillet_1_1, exp.current())] = False
+  exp.next()
+model.checkFilter(Part_2_doc, model, Filters, Reference)
+
+### Create Part
+Part_3 = model.addPart(partSet)
+Part_3_doc = Part_3.document()
+
+### Create Box
+Box_3 = model.addBox(Part_3_doc, 10, 10, 10)
+
+### Create Chamfer
+Chamfer_1_objects = [model.selection("FACE", "Box_1_1/Left"),
+                     model.selection("FACE", "Box_1_1/Front"),
+                     model.selection("FACE", "Box_1_1/Top"),
+                     model.selection("FACE", "Box_1_1/Right"),
+                     model.selection("FACE", "Box_1_1/Bottom")]
+Chamfer_2 = model.addChamfer(Part_3_doc, Chamfer_1_objects, False, 2, 43, keepSubResults = True)
+
+model.end()
+
+model.do()
+Filters = model.filters(Part_3_doc, [model.addFilter(name = "FeatureEdges",  args = [ 30.0 ])])
+model.end()
+
+Reference = {}
+ResultChamfer_2_1 = Chamfer_2.result().resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(ResultChamfer_2_1.shape(), GeomAPI_Shape.EDGE)
+while exp.more():
+  Reference[model.selection(ResultChamfer_2_1, exp.current())] = True
+  exp.next()
+model.checkFilter(Part_3_doc, model, Filters, Reference)
+
+model.do()
+Filters = model.filters(Part_3_doc, [model.addFilter(name = "FeatureEdges",  args = [ 50.0 ])])
+model.end()
+
+Reference = {}
+exp = GeomAPI_ShapeExplorer(ResultChamfer_2_1.shape(), GeomAPI_Shape.EDGE)
+while exp.more():
+  Reference[model.selection(ResultChamfer_2_1, exp.current())] = False
+  exp.next()
+model.checkFilter(Part_3_doc, model, Filters, Reference)
diff --git a/src/FiltersPlugin/Test/TestFilter_VolumeSize.py b/src/FiltersPlugin/Test/TestFilter_VolumeSize.py
new file mode 100644 (file)
index 0000000..22a4c3c
--- /dev/null
@@ -0,0 +1,159 @@
+# Copyright (C) 2014-2021  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 SketchAPI import *
+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, 100, 50, 100)
+
+### Create Point
+Point_1 = model.addPoint(Part_1_doc, 100, 0, 0)
+
+### Create Point
+Point_2 = model.addPoint(Part_1_doc, 250, 50, 100)
+
+### Create Box
+Box_2 = model.addBox(Part_1_doc, model.selection("VERTEX", "all-in-Point_1"), model.selection("VERTEX", "all-in-Point_2"))
+
+### Create Point
+Point_3 = model.addPoint(Part_1_doc, 100, 50, 250)
+
+### Create Box
+Box_3 = model.addBox(Part_1_doc, model.selection("VERTEX", "[Box_1_1/Back][Box_1_1/Left][Box_1_1/Top]"), model.selection("VERTEX", "Point_3"))
+
+### Create CompSolid
+CompSolid_1_objects = [model.selection("SOLID", "Box_3_1"),
+                       model.selection("SOLID", "Box_2_1"),
+                       model.selection("SOLID", "Box_1_1")]
+CompSolid_1 = model.addCompSolid(Part_1_doc, CompSolid_1_objects)
+
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "VolumeSize", args = [ "inf" , 500000.0 ])])
+
+model.end()
+
+Reference = {}
+ResultCompSolid_1 = CompSolid_1.result().resultSubShapePair()[0]
+ResultBox_1 = Box_1.result().resultSubShapePair()[0]
+ResultBox_2 = Box_2.result().resultSubShapePair()[0]
+ResultBox_3 = Box_3.result().resultSubShapePair()[0]
+
+exp = GeomAPI_ShapeExplorer(ResultCompSolid_1.shape(), GeomAPI_Shape.SOLID)
+while exp.more():
+  Reference[model.selection(ResultCompSolid_1, exp.current())] = False
+  exp.next()
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "VolumeSize", args = [ "infEq" , 500000.0 ])])
+model.end()
+
+Reference = {}
+exp = GeomAPI_ShapeExplorer(ResultBox_1.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_1, exp.current())] = True
+exp = GeomAPI_ShapeExplorer(ResultBox_2.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_2, exp.current())] = False
+exp = GeomAPI_ShapeExplorer(ResultBox_3.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_3, exp.current())] = False
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "VolumeSize", args = [ "sup" , 500000.0 ])])
+model.end()
+
+Reference = {}
+exp = GeomAPI_ShapeExplorer(ResultBox_1.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_1, exp.current())] = False
+exp = GeomAPI_ShapeExplorer(ResultBox_2.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_2, exp.current())] = True
+exp = GeomAPI_ShapeExplorer(ResultBox_3.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_3, exp.current())] = True
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "VolumeSize", args = [ "inf" , 50.0 ])])
+model.end()
+
+Reference = {}
+exp = GeomAPI_ShapeExplorer(ResultBox_1.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_1, exp.current())] = False
+exp = GeomAPI_ShapeExplorer(ResultBox_2.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_2, exp.current())] = False
+exp = GeomAPI_ShapeExplorer(ResultBox_3.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_3, exp.current())] = False
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "VolumeSize", args = [ "supEq" , 500000.0 ])])
+model.end()
+
+Reference = {}
+exp = GeomAPI_ShapeExplorer(ResultCompSolid_1.shape(), GeomAPI_Shape.SOLID)
+while exp.more():
+  Reference[model.selection(ResultCompSolid_1, exp.current())] = True
+  exp.next()
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "VolumeSize", args = [ "supEq" , 800000.0 ])])
+model.end()
+
+Reference = {}
+exp = GeomAPI_ShapeExplorer(ResultCompSolid_1.shape(), GeomAPI_Shape.SOLID)
+while exp.more():
+  Reference[model.selection(ResultCompSolid_1, exp.current())] = False
+  exp.next()
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "VolumeSize", args = [ "isBetween" , 50.0 , 600000.0])])
+model.end()
+Reference = {}
+exp = GeomAPI_ShapeExplorer(ResultBox_1.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_1, exp.current())] = True
+exp = GeomAPI_ShapeExplorer(ResultBox_2.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_2, exp.current())] = False
+exp = GeomAPI_ShapeExplorer(ResultBox_3.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_3, exp.current())] = False
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
+
+model.begin()
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "VolumeSize", args = [ "isStrictlyBetween" , 500.0 , 750000.0])])
+model.end()
+Reference = {}
+exp = GeomAPI_ShapeExplorer(ResultBox_1.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_1, exp.current())] = True
+exp = GeomAPI_ShapeExplorer(ResultBox_2.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_2, exp.current())] = False
+exp = GeomAPI_ShapeExplorer(ResultBox_3.shape(), GeomAPI_Shape.SOLID)
+Reference[model.selection(ResultBox_3, exp.current())] = False
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
index 4d393252f5b83346ca5b35780b488e42acff2eda..d40fbd3d5762d51a71ca83b1dbed71093cfc48d6 100644 (file)
@@ -34,15 +34,20 @@ FILTER_EXTERNAL_FACES = "ExternalFaces"
 FILTER_HORIZONTAL_FACES = "HorizontalFaces"
 FILTER_VERTICAL_FACES = "VerticalFaces"
 FILTER_CONNECTED_FACES = "TopoConnectedFaces"
+FILTER_EDGE_SIZE = "EdgeSize"
+FILTER_FACE_SIZE = "FaceSize"
+FILTER_VOLUME_SIZE = "VolumeSize"
+FILTER_FEATURE_EDGES = "FeatureEdges"
+FILTER_CONTINUOUS_FACES= "ContinuousFaces"
 
 # Reference data (supported filters) for each type of shape
 Reference = {
     GeomAPI_Shape.VERTEX : [FILTER_BELONGS_TO, FILTER_ON_PLANE, FILTER_ON_LINE, FILTER_ON_PLANE_SIDE, FILTER_RELATIVE_TO_SOLID],
-    GeomAPI_Shape.EDGE   : [FILTER_BELONGS_TO, FILTER_ON_PLANE, FILTER_ON_LINE, FILTER_ON_GEOMETRY, FILTER_ON_PLANE_SIDE, FILTER_OPPOSITE_TO_EDGE, FILTER_RELATIVE_TO_SOLID],
+    GeomAPI_Shape.EDGE   : [FILTER_BELONGS_TO, FILTER_ON_PLANE, FILTER_ON_LINE, FILTER_ON_GEOMETRY, FILTER_ON_PLANE_SIDE, FILTER_OPPOSITE_TO_EDGE, FILTER_RELATIVE_TO_SOLID, FILTER_EDGE_SIZE, FILTER_FEATURE_EDGES],
     GeomAPI_Shape.WIRE   : [FILTER_BELONGS_TO, FILTER_ON_PLANE, FILTER_ON_PLANE_SIDE, FILTER_RELATIVE_TO_SOLID],
-    GeomAPI_Shape.FACE   : [FILTER_BELONGS_TO, FILTER_ON_PLANE, FILTER_ON_GEOMETRY, FILTER_ON_PLANE_SIDE, FILTER_RELATIVE_TO_SOLID, FILTER_EXTERNAL_FACES, FILTER_HORIZONTAL_FACES, FILTER_VERTICAL_FACES, FILTER_CONNECTED_FACES],
+    GeomAPI_Shape.FACE   : [FILTER_BELONGS_TO, FILTER_ON_PLANE, FILTER_ON_GEOMETRY, FILTER_ON_PLANE_SIDE, FILTER_RELATIVE_TO_SOLID, FILTER_EXTERNAL_FACES, FILTER_HORIZONTAL_FACES, FILTER_VERTICAL_FACES, FILTER_CONNECTED_FACES, FILTER_FACE_SIZE, FILTER_CONTINUOUS_FACES],
     GeomAPI_Shape.SHELL  : [FILTER_BELONGS_TO, FILTER_ON_PLANE, FILTER_ON_PLANE_SIDE, FILTER_RELATIVE_TO_SOLID],
-    GeomAPI_Shape.SOLID  : [FILTER_BELONGS_TO, FILTER_ON_PLANE_SIDE],
+    GeomAPI_Shape.SOLID  : [FILTER_BELONGS_TO, FILTER_ON_PLANE_SIDE, FILTER_VOLUME_SIZE],
 }
 
 model.begin()
index 81b67a1dac2bf5debdb1c124ef9cc961daf5d8a6..3d9bbb4920e93119e76e41ea0bcae801fceb07f6 100644 (file)
@@ -57,6 +57,39 @@ By default, the result of Selection feature all selectable entities from all Sha
 - **Argument:** Any result object, multiple OR selection accepted
 - **Algorithm:** Returns only shapes that belong to selected results.
 
+**Edge size**
+
+- **Result type:** Edge
+- **Argument:** 
+    - **Comparator:** <, <=, >, >=, is between, is strictly between
+    - **Size** or  **Min size** and **Max size**
+- **Algorithm:** Returns all edges whose length respect comparator rules.
+
+**Face size**
+
+- **Result type:** Face
+- **Argument:** 
+    - **Comparator:** <, <=, >, >=, is between, is strictly between
+    - **Size** or  **Min size** and **Max size**
+- **Algorithm:** Returns all faces whose area respect comparator rules.
+
+**Volume size**
+
+- **Result type:** Solid
+- **Argument:** 
+    - **Comparator:** <, <=, >, >=, is between, is strictly between
+    - **Size** or  **Min size** and **Max size**
+- **Algorithm:** Returns all solids whose volume respect comparator rules.
+
+**Feature edges**
+
+This algorithm identifies edges between two faces discontinuous with an angular tolerance.
+
+- **Result type:** Edge
+- **Argument:** 
+    - **Angle** an angular tolerance used by G1 continuity criterion for comparing the angle between the normals 
+- **Algorithm:** Returns all edges between two discontinuous faces.
+
 **On a plane**
 
 - **Result type:** Vertex, Edge, Face
@@ -89,6 +122,16 @@ This algorithm is based on the Propagate geompy function. It works on a model pa
 - **Argument:** An edge belonging to a quadrangular face
 - **Algorithm:** Returns all Edges opposite to the given Edge on all quadrangular faces connected to this Edge. The algorithm is recursive: after an edge is found on one face, it adds edges opposite to this new one.
 
+**Continuous Faces**
+
+This algorithm identifies continuous faces with an angular tolerance given by topological propagation.
+
+- **Result type:** Face
+- **Argument:** 
+    - **Angle:** an angular tolerance used by G1 continuity criterion for comparing the angle between the normals. 
+    - **Faces:** Faces to start the propagation.    
+- **Algorithm:** Returns continuous faces.
+
 **On/In/Out a Solid**
 
 This algorithm reproduces the GetShapesOnShape function of geompy.
diff --git a/src/FiltersPlugin/filter-ContinuousFaces.xml b/src/FiltersPlugin/filter-ContinuousFaces.xml
new file mode 100644 (file)
index 0000000..5864b28
--- /dev/null
@@ -0,0 +1,14 @@
+<filter id="ContinuousFaces">
+  <doublevalue id="ContinuousFaces__value"
+      label="Angle"
+      min="0"
+      step="0.1"
+      default="5">
+  </doublevalue>
+  <multi_selector id="ContinuousFaces__faces"
+                  label="Faces:"
+                  tooltip="Select face."
+                  shape_types="faces">
+    <validator id="GeomValidators_ShapeType" parameters="face"/>
+  </multi_selector>
+</filter>
diff --git a/src/FiltersPlugin/filter-EdgeSize.xml b/src/FiltersPlugin/filter-EdgeSize.xml
new file mode 100644 (file)
index 0000000..bb459a6
--- /dev/null
@@ -0,0 +1,72 @@
+<filter id="EdgeSize">
+    <switch id="EdgeSize__comparatorType">
+    <case id="inf" title="&lt;">
+      <doublevalue id="EdgeSize__value"
+                  label="Size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+    </case> 
+    <case id="infEq" title="&lt;=">
+    <doublevalue id="EdgeSize__value"
+                  label="Size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+     </case>
+    <case id="sup" title="&gt;">
+    <doublevalue id="EdgeSize__value"
+                  label="Size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+     </case>
+    <case id="supEq" title="&gt;=">
+    <doublevalue id="EdgeSize__value"
+                  label="Size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+     </case>
+    <case id="isBetween" title="is between">
+     <doublevalue id="EdgeSize__value"
+                  label="Min size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+      <doublevalue id="EdgeSize__valueMax"
+                  label="Max size"
+                  min="0"
+                  step="0.1"
+                  default="10">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+    </case>
+    <case id="isStrictlyBetween" title="is strictly between">
+     <doublevalue id="EdgeSize__value"
+                  label="Min size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+      <doublevalue id="EdgeSize__valueMax"
+                  label="Max size"
+                  min="0"
+                  step="0.1"
+                  default="10">
+        <validator id="GeomValidators_Positive" />
+      </doublevalue>
+    </case>
+  </switch>
+</filter>
diff --git a/src/FiltersPlugin/filter-FaceSize.xml b/src/FiltersPlugin/filter-FaceSize.xml
new file mode 100644 (file)
index 0000000..2eff84f
--- /dev/null
@@ -0,0 +1,71 @@
+<filter id="FaceSize">
+    <switch id="FaceSize__comparatorType">
+    <case id="inf" title="&lt;">
+      <doublevalue id="FaceSize__value"
+                  label="Size"
+                  min="0"
+                  default="1">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+    </case> 
+    <case id="infEq" title="&lt;=">
+    <doublevalue id="FaceSize__value"
+                  label="Size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+     </case>
+    <case id="sup" title="&gt;">
+    <doublevalue id="FaceSize__value"
+                  label="Size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+     </case>
+    <case id="supEq" title="&gt;=">
+    <doublevalue id="FaceSize__value"
+                  label="Size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+     </case>
+    <case id="isBetween" title="is between">
+     <doublevalue id="FaceSize__value"
+                  label="Min size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+      <doublevalue id="FaceSize__valueMax"
+                  label="Max size"
+                  min="0"
+                  step="0.1"
+                  default="10">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+    </case>
+    <case id="isStrictlyBetween" title="is strictly between">
+     <doublevalue id="FaceSize__value"
+                  label="Min size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+      <doublevalue id="FaceSize__valueMax"
+                  label="Max size"
+                  min="0"
+                  step="0.1"
+                  default="10">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+    </case>
+  </switch>
+</filter>
diff --git a/src/FiltersPlugin/filter-FeatureEdges.xml b/src/FiltersPlugin/filter-FeatureEdges.xml
new file mode 100644 (file)
index 0000000..c4e9071
--- /dev/null
@@ -0,0 +1,8 @@
+<filter id="FeatureEdges">
+  <doublevalue id="FeatureEdges__value"
+              label="Angle"
+              min="0"
+              step="0.1"
+              default="5">
+  </doublevalue>
+</filter>
diff --git a/src/FiltersPlugin/filter-VolumeSize.xml b/src/FiltersPlugin/filter-VolumeSize.xml
new file mode 100644 (file)
index 0000000..fcb3320
--- /dev/null
@@ -0,0 +1,71 @@
+<filter id="VolumeSize">
+    <switch id="VolumeSize__comparatorType">
+    <case id="inf" title="&lt;">
+      <doublevalue id="VolumeSize__value"
+                  label="Size"
+                  min="0"
+                  default="1">
+        <validator id="GeomValidators_Positive" />
+      </doublevalue>
+    </case> 
+    <case id="infEq" title="&lt;=">
+    <doublevalue id="VolumeSize__value"
+                  label="Size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+     </case>
+    <case id="sup" title="&gt;">
+    <doublevalue id="VolumeSize__value"
+                  label="Size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+     </case>
+    <case id="supEq" title="&gt;=">
+    <doublevalue id="VolumeSize__value"
+                  label="Size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+     </case>
+    <case id="isBetween" title="is between">
+     <doublevalue id="VolumeSize__value"
+                  label="Min size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+      <doublevalue id="VolumeSize__valueMax"
+                  label="Max size"
+                  min="0"
+                  step="0.1"
+                  default="10">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+    </case>
+    <case id="isStrictlyBetween" title="is strictly between">
+     <doublevalue id="VolumeSize__value"
+                  label="Min size"
+                  min="0"
+                  step="0.1"
+                  default="1">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+      <doublevalue id="VolumeSize__valueMax"
+                  label="Max size"
+                  min="0"
+                  step="0.1"
+                  default="10">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+    </case>
+  </switch>
+</filter>
index 722601d08347ac2ec547050ffbc5e38fb3f66c4d..98aa0c3404835d86882b10545df937860cc9c5b0 100644 (file)
@@ -118,4 +118,9 @@ SET(TEST_NAMES
   Test17924.py
   Test17962.py
   Test19190.py
+  TestFilter_FaceSize.py
+  TestFilter_EdgeSize.py
+  TestFilter_FeatureEdges.py
+  TestFilter_ContinuousFaces.py
+  TestFilter_VolumeSize.py
 )
index 0c549a45beac44842cd83805e74271b840623e7e..d55d92608b18e308324920ed4257fe2c85ee2a0a 100644 (file)
@@ -33,6 +33,7 @@ SET(PROJECT_HEADERS
     GeomAlgoAPI_Prism.h
     GeomAlgoAPI_Revolution.h
     GeomAlgoAPI_Boolean.h
+    GeomAlgoAPI_BasicProperties.h
     GeomAlgoAPI_ThroughAll.h
     GeomAlgoAPI_Rotation.h
     GeomAlgoAPI_Translation.h
@@ -73,6 +74,7 @@ SET(PROJECT_HEADERS
     GeomAlgoAPI_XAOImport.h
     GeomAlgoAPI_Copy.h
     GeomAlgoAPI_ConeSegment.h
+    GeomAlgoAPI_ContinuousFaces.h
     GeomAlgoAPI_Ellipsoid.h
     GeomAlgoAPI_Symmetry.h
     GeomAlgoAPI_Scale.h
@@ -103,6 +105,7 @@ SET(PROJECT_SOURCES
     GeomAlgoAPI_Prism.cpp
     GeomAlgoAPI_Revolution.cpp
     GeomAlgoAPI_Boolean.cpp
+    GeomAlgoAPI_BasicProperties.cpp
     GeomAlgoAPI_ThroughAll.cpp
     GeomAlgoAPI_Rotation.cpp
     GeomAlgoAPI_Translation.cpp
@@ -143,6 +146,7 @@ SET(PROJECT_SOURCES
     GeomAlgoAPI_XAOImport.cpp
     GeomAlgoAPI_Copy.cpp
     GeomAlgoAPI_ConeSegment.cpp
+    GeomAlgoAPI_ContinuousFaces.cpp
     GeomAlgoAPI_Ellipsoid.cpp
     GeomAlgoAPI_Symmetry.cpp
     GeomAlgoAPI_Scale.cpp
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.cpp
new file mode 100644 (file)
index 0000000..174929d
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright (C) 2014-2021  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_BasicProperties.h"
+
+#include <GProp_GProps.hxx>
+#include <TopoDS_Shape.hxx>
+#include <BRepGProp.hxx>
+#include <TopExp_Explorer.hxx>
+#include <Standard_ErrorHandler.hxx>
+
+//=================================================================================================
+bool GetBasicProperties(  const std::shared_ptr<GeomAPI_Shape>& theShape,
+                          const double theTolerance,
+                          Standard_Real& theLength,
+                          Standard_Real& theSurfArea,
+                          Standard_Real& theVolume,
+                          std::string& theError)
+{
+
+  #ifdef _DEBUG
+  std::cout << "GetBasicProperties " << std::endl;
+  #endif
+
+  if (!theShape.get()) {
+    theError = "GetBasicProperties : An invalid argument";
+    return false;
+  }
+
+  TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
+
+  //Compute the parameters
+  GProp_GProps LProps, SProps;
+  Standard_Real anEps = theTolerance >= 0 ? theTolerance : 1.e-6;
+  try {
+    OCC_CATCH_SIGNALS;
+    BRepGProp::LinearProperties(aShape, LProps, Standard_True);
+    theLength = LProps.Mass();
+
+    BRepGProp::SurfaceProperties(aShape, SProps, anEps, Standard_True);
+    theSurfArea = SProps.Mass();
+
+    theVolume = 0.0;
+    if (aShape.ShapeType() < TopAbs_SHELL) {
+      for (TopExp_Explorer Exp (aShape, TopAbs_SOLID); Exp.More(); Exp.Next()) {
+        GProp_GProps VProps;
+        BRepGProp::VolumeProperties(Exp.Current(), VProps, anEps, Standard_True);
+        theVolume += VProps.Mass();
+      }
+    }
+  }
+  catch (Standard_Failure& aFail) {
+    theError = aFail.GetMessageString();
+    return false;
+  }
+
+  return true;
+
+}
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.h b/src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.h
new file mode 100644 (file)
index 0000000..e697dd0
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright (C) 2014-2021  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_BasicProperties_H_
+#define GeomAlgoAPI_BasicProperties_H_
+
+#include <GeomAlgoAPI.h>
+#include <GeomAPI_Shape.h>
+#include <Standard_TypeDef.hxx>
+
+/// Run chamfer operation with two distances or with a distance and an angle .
+  /// \param theShape      the shape
+  /// \param theTolerance  tolerance desirated
+  /// \param theLength     lenght calculated
+  /// \param theSurfArea   Surface Area calculated
+  /// \param theVolume     Volume calculated
+  /// \param theError      error
+GEOMALGOAPI_EXPORT
+bool GetBasicProperties(  const std::shared_ptr<GeomAPI_Shape>& theShape,
+                          const Standard_Real theTolerance,
+                          Standard_Real& theLength,
+                          Standard_Real& theSurfArea,
+                          Standard_Real& theVolume,
+                          std::string& theError);
+
+#endif
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.cpp
new file mode 100644 (file)
index 0000000..a7507e4
--- /dev/null
@@ -0,0 +1,132 @@
+// Copyright (C) 2014-2021  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_ContinuousFaces.h"
+
+#include <TopoDS_Shape.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS.hxx>
+#include <BRep_Tool.hxx>
+#include <LocalAnalysis_SurfaceContinuity.hxx>
+#include <ShapeAnalysis_Surface.hxx>
+#include <gp_Pnt.hxx>
+
+#include <Standard_ErrorHandler.hxx>
+
+const double PI = 3.141592653589793238463;
+
+//=======================================================================
+bool isContinuousFaces(const GeomShapePtr& theFace1,
+                       const GeomShapePtr& theFace2,
+                       const GeomPointPtr& thePoint,
+                       const double & theAngle,
+                       std::string& theError)
+{
+
+  #ifdef _DEBUG
+  std::cout << "isContinuousFaces " << std::endl;
+  #endif
+
+  if (!thePoint.get()) {
+      theError = "isContinuousFaces : An invalid argument";
+      return false;
+  }
+  const gp_Pnt& aPoint = thePoint->impl<gp_Pnt>();
+
+  // Getting base shape.
+  if (!theFace1.get()) {
+    theError = "isContinuousFaces : An invalid argument";
+    return false;
+  }
+
+  TopoDS_Shape aShape1 = theFace1->impl<TopoDS_Shape>();
+
+  if (aShape1.IsNull()) {
+    theError = "isContinuousFaces : An invalid argument";
+    return false;
+  }
+
+  // Getting base shape.
+  if (!theFace2.get()) {
+    theError = "isContinuousFaces : An invalid argument";
+    return false;
+  }
+
+  TopoDS_Shape aShape2 = theFace2->impl<TopoDS_Shape>();
+
+  if (aShape2.IsNull()) {
+    theError = "isContinuousFaces : An invalid argument";
+    return false;
+  }
+
+  TopoDS_Face aFace1 = TopoDS::Face(aShape1);
+  if (aFace1.IsNull()) {
+    theError = "isContinuousFaces : An invalid argument";
+    return false;
+  }
+
+  Handle(Geom_Surface) aSurf1 = BRep_Tool::Surface(aFace1);
+  if (aSurf1.IsNull()) {
+    theError = "isContinuousFaces : An invalid surface";
+    return false;
+  }
+
+  ShapeAnalysis_Surface aSAS1(aSurf1);
+  gp_Pnt2d aPointOnFace1 = aSAS1.ValueOfUV(aPoint, Precision::Confusion());
+
+  TopoDS_Face aFace2 = TopoDS::Face(aShape2);
+  if (aFace2.IsNull()) {
+    theError = "isContinuousFaces : An invalid argument";
+    return false;
+  }
+
+  Handle(Geom_Surface) aSurf2 = BRep_Tool::Surface(aFace2);
+  if (aSurf2.IsNull()) {
+    theError = "isContinuousFaces : An invalid surface";
+    return false;
+  }
+
+  ShapeAnalysis_Surface aSAS2(aSurf2);
+  gp_Pnt2d aPointOnFace2= aSAS2.ValueOfUV(aPoint, Precision::Confusion());
+
+  bool aRes = false;
+  try {
+    OCC_CATCH_SIGNALS;
+    LocalAnalysis_SurfaceContinuity aLocAnal(aSurf1,
+                                            aPointOnFace1.X(),
+                                            aPointOnFace1.Y(),
+                                            aSurf2,
+                                            aPointOnFace2.X(),
+                                            aPointOnFace2.Y(),
+                                            GeomAbs_Shape::GeomAbs_G1, // Order
+                                            0.001, // EpsNul
+                                            0.001, // EpsC0
+                                            0.001, // EpsC1
+                                            0.001, // EpsC2
+                                            theAngle * PI/ 180.0); //EpsG1
+
+    aRes = aLocAnal.IsG1();
+  }
+  catch (Standard_Failure const& anException) {
+    theError = "LocalAnalysis_SurfaceContinuity error :";
+    theError += anException.GetMessageString();
+  }
+
+  return aRes;
+}
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.h b/src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.h
new file mode 100644 (file)
index 0000000..0d0faad
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright (C) 2014-2021  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_CONTINUOUSFACES_H_
+#define GEOMALGOAPI_CONTINUOUSFACES_H_
+
+#include <GeomAlgoAPI.h>
+#include <GeomAPI_Shape.h>
+#include <Standard_TypeDef.hxx>
+#include <GeomAPI_Pnt.h>
+
+/// indicate if two faces are continuous
+/// with an angular tolerance used for G1 continuity to compare the angle between the normals
+/// \param theFace1  the first face
+/// \param theFace2  the second face
+/// \param thePoint  the point for the normal
+/// \param theAngle  the angular tolerance
+/// \param theError  error
+GEOMALGOAPI_EXPORT
+bool isContinuousFaces(const GeomShapePtr& theFace1,
+                       const GeomShapePtr& theFace2,
+                       const GeomPointPtr& thePoint,
+                       const double & theAngle,
+                       std::string& theError);
+
+#endif //GEOMALGOAPI_SHAREDFACES_H_
index 89cc9a2639e0d71ef040c6ee7f335fa78ae546c6..bc352836a520e18f79cceb1c501d21a82371fa67 100644 (file)
@@ -44,7 +44,7 @@ bool GeomValidators_Positive::isValid(const AttributePtr& theAttribute,
                                       const std::list<std::string>& theArguments,
                                       Events_InfoMessage& theError) const
 {
-  double aMinValue = 1.e-5;
+  double aMinValue = 1.e-12;
   if(theArguments.size() == 1) {
     std::list<std::string>::const_iterator anIt = theArguments.begin();
     double aValue = Config_PropManager::stringToDouble((*anIt).c_str());
index 2c10b1adbd5f12e2f927e9a63e300f4c602b810e..acfc5c633872fb86afd492e0c2ba19a153602538 100644 (file)
@@ -180,6 +180,7 @@ ModuleBase_FilterItem::ModuleBase_FilterItem(
       connect(aWidget, SIGNAL(focusOutWidget(ModuleBase_ModelWidget*)),
         theParent, SIGNAL(focusOutWidget(ModuleBase_ModelWidget*)));
       connect(aWidget, SIGNAL(objectUpdated()), theParent, SLOT(onObjectUpdated()));
+      aWidget->enableFocusProcessing();
     }
     aLayout->addWidget(aParamsWgt);
   }