]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Merge branch 'nrn/Lot2/AutoColor' into master
authorazv <azv@opencascade.com>
Wed, 13 Oct 2021 06:43:57 +0000 (09:43 +0300)
committerazv <azv@opencascade.com>
Wed, 13 Oct 2021 06:43:57 +0000 (09:43 +0300)
61 files changed:
CMakeCommon/FindSUIT.cmake
CMakeCommon/FindSalome.cmake
CMakeCommon/SalomeMacros.cmake
CMakeCommon/UnitTest.cmake
CMakeLists.txt
src/ExchangePlugin/Test/TestImportImage_1.py
src/ExchangePlugin/Test/TestImportImage_2.py
src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.cpp
src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.h
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/GeomAlgoAPI_ShapeTools.cpp
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h
src/GeomValidators/GeomValidators_Positive.cpp
src/Locale/CMakeLists.txt
src/Model/Model_AttributeSelection.cpp
src/Model/Model_Document.cpp
src/Model/Model_Session.h
src/ModelAPI/CMakeLists.txt
src/ModelAPI/ModelAPI_Session.h
src/ModuleBase/CMakeLists.txt
src/ModuleBase/ModuleBase_WidgetSelectionFilter.cpp
src/PartSet/CMakeLists.txt
src/PartSet/PartSet_Module.cpp
src/PythonAPI/CMakeLists.txt
src/PythonAPI/__init__.py
src/SHAPERGUI/CMakeLists.txt
src/XGUI/CMakeLists.txt
src/XGUI/XGUI_InspectionPanel.cpp
src/XGUI/XGUI_Workshop.cpp
src/XGUI/XGUI_msg_fr.ts
test.API/SHAPER/CMakeLists.txt

index fe8e6e4e92f9d53c9d5a484204e0161e3284f1c0..42a3956a3359b258dc2c1cb1d32d94600b374c4c 100644 (file)
 #
 
 IF(HAVE_SALOME)
-  SET(SUIT_INCLUDE ${SALOME_GUI_INCLUDE})
-  MESSAGE(STATUS "SUIT_INCLUDE: ${SALOME_GUI_INCLUDE}")
+  SET(SUIT_INCLUDE "${GUI_ROOT_DIR}/include/salome")
   SET(SUIT_LIB_DIR "${GUI_ROOT_DIR}/lib/salome")
 ELSE(HAVE_SALOME) 
   SET(SUIT_DIR $ENV{SUIT_DIR})
   IF(EXISTS ${SUIT_DIR})
-
     MESSAGE(STATUS "SUIT found at ${SUIT_DIR}")
     IF(WIN32)
         SET(SUIT_LIB_DIR ${SUIT_DIR}/lib)
@@ -49,3 +47,5 @@ ENDIF(HAVE_SALOME)
 
 FILE(TO_CMAKE_PATH ${SUIT_LIB_DIR} SUIT_LIB_DIR)
 FILE(TO_CMAKE_PATH ${SUIT_INCLUDE} SUIT_INCLUDE)
+MESSAGE(STATUS "SUIT includes: ${SUIT_INCLUDE}")
+MESSAGE(STATUS "SUIT libraries: ${SUIT_LIB_DIR}")
index 891a363ebf42c6b7cffedcac92bd8278f22df8c3..ff3e7d32da2b9040657aa4ec5e5b0c97e2e099c0 100644 (file)
 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 #
 
-SET(KERNEL_ROOT_DIR $ENV{KERNEL_ROOT_DIR} CACHE PATH "Path to the Salome KERNEL directory")
-SET(GUI_ROOT_DIR $ENV{GUI_ROOT_DIR} CACHE PATH "Path to the Salome GUI directory")
-SET(HAVE_SALOME NO)
-IF(EXISTS ${GUI_ROOT_DIR})
-       MESSAGE("-- SALOME found at " ${GUI_ROOT_DIR})
-       SET(HAVE_SALOME YES)
-
+IF(${HAVE_SALOME})
        FIND_LIBRARY(caf caf ${GUI_ROOT_DIR}/lib/salome)
        FIND_LIBRARY(CAM CAM ${GUI_ROOT_DIR}/lib/salome)
        FIND_LIBRARY(CASCatch CASCatch ${GUI_ROOT_DIR}/lib/salome)
@@ -65,9 +59,4 @@ IF(EXISTS ${GUI_ROOT_DIR})
        FIND_LIBRARY(vtkTools vtkTools ${GUI_ROOT_DIR}/lib/salome)
        FIND_LIBRARY(SalomeGuiHelpers SalomeGuiHelpers ${GUI_ROOT_DIR}/lib/salome)
        FIND_LIBRARY(SalomeTreeData SalomeTreeData ${GUI_ROOT_DIR}/lib/salome)
-
-       SET(SALOME_GUI_INCLUDE ${GUI_ROOT_DIR}/include/salome)
-       SET(SALOME_KERNEL_INCLUDE ${KERNEL_ROOT_DIR}/include/salome)
-        SET(SALOME_KERNEL_LIBDIR ${KERNEL_ROOT_DIR}/lib/salome)
-       ADD_DEFINITIONS( -DHAVE_SALOME )
-ENDIF(EXISTS ${GUI_ROOT_DIR})
+ENDIF()
index 1bbbc2b4bbbd7a5cbbed8536ea3017db825da701..e521da8a559624ec1eb8dcc5f391064d6b24b47b 100644 (file)
@@ -1025,3 +1025,80 @@ MACRO(SWIG_CHECK_GENERATION swig_module)
      ENDIF()
   ENDIF()
 ENDMACRO(SWIG_CHECK_GENERATION)
+
+#########################################################################
+# SALOME_SETUP_VERSION()
+#
+# USAGE: SALOME_SETUP_VERSION(version [DEVELOPMENT])
+#
+# ARGUMENTS:
+#   version   [in] Version decriptor (string).
+#
+# OPTIONS:
+#   DEVELOPMENT    Forces setting development flag.
+#
+# The macro sets the following variables:
+# - PROJECTNAME_MAJOR_VERSION - major version number
+# - PROJECTNAME_MINOR_VERSION - minor version number
+# - PROJECTNAME_PATCH_VERSION - release version number
+# - PROJECTNAME_VERSION       - full qualified version
+# - PROJECTNAME_VERSION_DEV   - development flag (0 value for released version)
+# - PROJECTNAME_XVERSION      - hexadecimal representation of version
+# - PROJECTNAME_GIT_SHA1      - git commit's sha1
+#
+FUNCTION(SALOME_SETUP_VERSION version)
+  # parse arguments
+  PARSE_ARGUMENTS(SALOME_SETUP_VERSION "" "DEVELOPMENT" ${ARGN})
+  # project name in upper case (if not set in master CMakeLists.txt)
+  STRING(TOUPPER ${PROJECT_NAME} _pkg_uc)
+  # parse version component
+  STRING(REGEX MATCHALL "[^.]" _components "${version}")
+  LIST(LENGTH _components _length)
+  IF(${_length} GREATER 0)
+    LIST(GET _components 0 _major)
+    LIST(REMOVE_AT _components 0)
+  ELSE()
+    SET(_major 0)
+  ENDIF()
+  LIST(LENGTH _components _length)
+  IF(${_length} GREATER 0)
+    LIST(GET _components 0 _minor)
+    LIST(REMOVE_AT _components 0)
+  ELSE()
+    SET(_minor 0)
+  ENDIF()
+  LIST(LENGTH _components _length)
+  IF(${_length} GREATER 0)
+    LIST(GET _components 0 _patch)
+    LIST(REMOVE_AT _components 0)
+  ELSE()
+    SET(_patch 0)
+  ENDIF()
+  # set project version: 'major', 'minor' and 'patch' components
+  SET(${_pkg_uc}_MAJOR_VERSION ${_major} PARENT_SCOPE)
+  SET(${_pkg_uc}_MINOR_VERSION ${_minor} PARENT_SCOPE)
+  SET(${_pkg_uc}_PATCH_VERSION ${_patch} PARENT_SCOPE)
+  SET(${_pkg_uc}_VERSION       ${_major}.${_minor}.${_patch} PARENT_SCOPE)
+  # set 'development' flag
+  IF(SALOME_SETUP_VERSION_DEVELOPMENT)
+    SET(${_pkg_uc}_VERSION_DEV 1 PARENT_SCOPE)
+  ELSE()
+    SET(${_pkg_uc}_VERSION_DEV 0 PARENT_SCOPE)
+  ENDIF()
+  # set hexa representation of version
+  SALOME_TOHEXA(${_major} _major_h)
+  SALOME_TOHEXA(${_minor} _minor_h)
+  SALOME_TOHEXA(${_patch} _patch_h)
+  SET(${_pkg_uc}_XVERSION "0x${_major_h}${_minor_h}${_patch_h}" PARENT_SCOPE)
+  # detect git sha1
+  EXECUTE_PROCESS(COMMAND git describe --dirty --tags --match=V* --always
+    WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+    OUTPUT_VARIABLE _git_version
+    ERROR_QUIET
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+  IF(_git_version)
+    SET(${_pkg_uc}_GIT_SHA1 "${_git_version}" PARENT_SCOPE)
+  ELSE(_)
+    SET(${_pkg_uc}_GIT_SHA1 "unknown" PARENT_SCOPE)
+  ENDIF()
+ENDFUNCTION()
index a3912e337d8aaf54d6c362e3262609912455f280..147f2529669160e85dd8080d4459ce51d193d184 100644 (file)
@@ -55,6 +55,9 @@ function(GENERATE_TESTS PATH testdir TESTS)
 
     # Full path to the python test file beeing executed
     SET(aTestFileName "${testdir}/${eachFileName}")
+    IF(NOT EXISTS ${aTestFileName})
+      SET(aTestFileName "${testdir}/Test/${eachFileName}")
+    ENDIF(NOT EXISTS ${aTestFileName})
     IF(EXISTS ${aTestFileName})
       ADD_TEST(NAME ${aTestName}
                COMMAND ${PYTHON_EXECUTABLE} ${aTestFileName})
@@ -64,13 +67,15 @@ function(GENERATE_TESTS PATH testdir TESTS)
       # Debug output...
       #MESSAGE(STATUS "Test added: ${aTestName} file: ${aTestFileName}")
     ELSE(EXISTS ${aTestFileName})
-      MESSAGE(WARNING "Can not find the test file: ${aTestFileName}")
+      MESSAGE(WARNING "Can not find the test file: ${eachFileName}")
+      MESSAGE(STATUS "Search paths are: ${testdir}")
+      MESSAGE(STATUS "                  ${testdir}/Test")
     ENDIF(EXISTS ${aTestFileName})
   endforeach(eachFileName ${ARGN})
 endfunction(GENERATE_TESTS)
 
 function(ADD_UNIT_TESTS)
-  GENERATE_TESTS(PATH "${CMAKE_CURRENT_SOURCE_DIR}/Test" TESTS ${ARGN})
+  GENERATE_TESTS(PATH "${CMAKE_CURRENT_SOURCE_DIR}" TESTS ${ARGN})
 endfunction(ADD_UNIT_TESTS)
 
 function(ADD_UNIT_TESTS_API)
index c566338c355ab33e7f84a192a852ffd49ca50f27..0b93f3b04a05d8afdb80ec4b3253ce21f299d4da 100644 (file)
 
 CMAKE_MINIMUM_REQUIRED(VERSION 2.8.10)
 
-PROJECT (SHAPER)
-SET(${PROJECT_NAME}_MAJOR_VERSION 9)
-SET(${PROJECT_NAME}_MINOR_VERSION 7)
-SET(${PROJECT_NAME}_PATCH_VERSION 0)
-SET(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION})
-SET(COMPONENT_NAME SHAPER)
+# Project name
+# ============
+PROJECT(SHAPER)
 
-# Ensure a proper linker behavior:
+# Ensure a proper linker behavior
+# ===============================
 CMAKE_POLICY(SET CMP0003 NEW)
 IF(WIN32)
   CMAKE_POLICY(SET CMP0020 OLD) # disable automatic linking to qtmain.lib
 ENDIF(WIN32)
 
+# Append path to common macros
+# ===========================
 SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMakeCommon" ${CMAKE_MODULE_PATH})
 
+# Detect SALOME mode; append path to SALOME macros
+# ================================================
+SET(HAVE_SALOME NO)
+SET(CONFIGURATION_ROOT_DIR $ENV{CONFIGURATION_ROOT_DIR} CACHE PATH "Path to the Salome CMake configuration files")
+IF(EXISTS ${CONFIGURATION_ROOT_DIR})
+  SET(HAVE_SALOME YES)
+  MESSAGE(STATUS "SALOME found; building with SALOME!")
+  SET(CMAKE_MODULE_PATH "${CONFIGURATION_ROOT_DIR}/cmake" ${CMAKE_MODULE_PATH})
+  INCLUDE(SalomeMacros)
+ELSE()
+  MESSAGE(STATUS "SALOME is not found; building without it!")
+  INCLUDE(SalomeMacros)
+ENDIF()
+
+# Versioning
+# ===========
+SALOME_SETUP_VERSION(9.7.0 DEVELOPMENT)
+MESSAGE(STATUS "Building ${PROJECT_NAME} ${${PROJECT_NAME}_VERSION} from \"${${PROJECT_NAME}_GIT_SHA1}\"")
+SET(COMPONENT_NAME SHAPER)
+
+# Options
+# =======
 IF (NOT CADBUILDER_BUILD_DOC)
   OPTION(SHAPER_BUILD_DOC "Generate SHAPER documentation" ON)
 ENDIF(NOT CADBUILDER_BUILD_DOC)
 
 INCLUDE(FindEclipse)
 INCLUDE(Common)
-INCLUDE(FindSalome)
-INCLUDE(FindSUIT)
 INCLUDE(FindTInspector)
+INCLUDE(FindSalomeQt5)
 
 IF(HAVE_SALOME)
-  SET(CONFIGURATION_ROOT_DIR $ENV{CONFIGURATION_ROOT_DIR} CACHE PATH "Path to the Salome CMake configuration files")
-  IF(EXISTS ${CONFIGURATION_ROOT_DIR})
-    SET(CMAKE_MODULE_PATH "${CONFIGURATION_ROOT_DIR}/cmake" ${CMAKE_MODULE_PATH})
-    INCLUDE(SalomeMacros)
-    INCLUDE(FindSalomeQt5)
-  ELSE()
-    MESSAGE(FATAL_ERROR "We absolutely need the Salome CMake configuration files, please define CONFIGURATION_ROOT_DIR !")
-  ENDIF()
+  INCLUDE(SalomeSetupPlatform) # From CONFIGURATION
+
+  ADD_DEFINITIONS(-DHAVE_SALOME)
+
   SET(KERNEL_ROOT_DIR $ENV{KERNEL_ROOT_DIR} CACHE PATH "Path to the Salome KERNEL")
   IF(EXISTS ${KERNEL_ROOT_DIR})
     FIND_PACKAGE(SalomeKERNEL REQUIRED)
     ADD_DEFINITIONS(${KERNEL_DEFINITIONS})
     INCLUDE_DIRECTORIES(${KERNEL_INCLUDE_DIRS})
+    SET(SALOME_KERNEL_LIBDIR ${KERNEL_ROOT_DIR}/lib/salome)
   ELSE(EXISTS ${KERNEL_ROOT_DIR})
     MESSAGE(FATAL_ERROR "We absolutely need a Salome KERNEL, please define KERNEL_ROOT_DIR")
   ENDIF(EXISTS ${KERNEL_ROOT_DIR})
+
   SET(GUI_ROOT_DIR $ENV{GUI_ROOT_DIR} CACHE PATH "Path to the Salome GUI")
   IF(EXISTS ${GUI_ROOT_DIR})
     FIND_PACKAGE(SalomeGUI REQUIRED)
   ELSE(EXISTS ${GUI_ROOT_DIR})
     MESSAGE(FATAL_ERROR "We absolutely need a Salome GUI, please define GUI_ROOT_DIR")
   ENDIF(EXISTS ${GUI_ROOT_DIR})
-  INCLUDE(SalomeSetupPlatform)   # From CONFIGURATION
 
   FIND_PACKAGE(SalomePythonInterp REQUIRED)
   FIND_PACKAGE(SalomePythonLibs REQUIRED)
-
   FIND_PACKAGE(SalomeOpenCASCADE REQUIRED)
-
+  INCLUDE(FindSalome)
 ELSE()
-  INCLUDE(SalomeMacros)
-  INCLUDE(FindSalomeQt5)
   INCLUDE(FindPython)
   INCLUDE(FindSalomeOpenCASCADE)
 ENDIF()
 
-# Common CMake macros
-# ===================
-
+INCLUDE(FindSUIT)
 
 # Find LibXml2
 IF(DEFINED ENV{LIBXML2_ROOT_DIR})
index 2c974d6bf62b120f40eceafef99e78f590806537..1c529e1963b575278c5d64d7b8a00703904e369d 100755 (executable)
 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 #
 
-import os
+import os, inspect
 from salome.shaper import model
 
+from PyQt5.Qt import QApplication
+
 import salome
+salome.salome_init_without_session()
 salome.salome_init(1)
+if QApplication.instance() is None:
+  app = QApplication([])
 
-data_dir = os.path.join(os.path.dirname(sys.argv[0]), "data")
+data_dir = os.path.join(os.path.dirname(inspect.getfile(lambda: None)), "data")
 
 model.begin()
 partSet = model.moduleDocument()
index 025bd9267f8a3397dbb129963690dcec1befbfa8..94b328fb3a5cf87f5ad01f4645bb7bbc6ac70e37 100755 (executable)
 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 #
 
-import os
+import os, inspect
 from salome.shaper import model
 
+from PyQt5.Qt import QApplication
+
 import salome
+salome.salome_init_without_session()
 salome.salome_init(1)
+if QApplication.instance() is None:
+  app = QApplication([])
 
-data_dir = os.path.join(os.path.dirname(sys.argv[0]), "data")
+data_dir = os.path.join(os.path.dirname(inspect.getfile(lambda: None)), "data")
 
 from tempfile import TemporaryDirectory
 tmp_dir = TemporaryDirectory()
index bf5293d83a0c3695653c13386790360dbfea3593..199fb3c6e8d221aefe19c8d0764bca0a816fe1ff 100644 (file)
@@ -199,6 +199,32 @@ bool FeaturesPlugin_CompositeBoolean::cutRecursiveCompound(const GeomShapePtr th
   return false; // no cuts
 }
 
+//=================================================================================================
+void FeaturesPlugin_CompositeBoolean::addSubShapes (const GeomShapePtr theCompound,
+                                                    const ListOfShape& theSubShapesToAvoid,
+                                                    ListOfShape& theSubShapesToAdd) {
+  for (GeomAPI_ShapeIterator aCompoundIt (theCompound);
+       aCompoundIt.more();
+       aCompoundIt.next()) {
+    GeomShapePtr aCompoundSS = aCompoundIt.current();
+    ListOfShape::const_iterator aUseIt = theSubShapesToAvoid.cbegin();
+    for (; aUseIt != theSubShapesToAvoid.cend(); aUseIt++) {
+      if (aCompoundSS->isEqual(*aUseIt)) {
+        break;
+      }
+    }
+    if (aUseIt == theSubShapesToAvoid.cend()) {
+      if (aCompoundSS->shapeType() == GeomAPI_Shape::COMPSOLID ||
+          aCompoundSS->shapeType() == GeomAPI_Shape::COMPOUND) {
+        addSubShapes(aCompoundSS, theSubShapesToAvoid, theSubShapesToAdd);
+      }
+      else {
+        theSubShapesToAdd.push_back(aCompoundSS);
+      }
+    }
+  }
+}
+
 //=================================================================================================
 bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools,
                                                   ListOfShape& theObjects,
@@ -239,10 +265,8 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools,
     ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
     if(aResCompSolidPtr.get()) {
       ResultBodyPtr aResRootPtr = ModelAPI_Tools::bodyOwner(aContext, true);
-      if (!aCompoundsMap.isBound(aResRootPtr->shape()) || myOperationType != BOOL_CUT) {
+      if (!aCompoundsMap.isBound(aResRootPtr->shape())) {
         // Compsolid or a simple (one-level) compound
-        // Or not CUT
-        // TODO: correct FUSE for complex compounds?
         GeomShapePtr aContextShape = aResCompSolidPtr->shape();
         std::map<GeomShapePtr, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
         for(; anIt != aCompSolidsObjects.end(); anIt++) {
@@ -386,6 +410,7 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools,
       theObjects.insert(theObjects.end(), anEdgesAndFaces.begin(), anEdgesAndFaces.end());
       theObjects.insert(theObjects.end(), anObjects.begin(), anObjects.end());
       theObjects.insert(theObjects.end(), aCompSolids.begin(), aCompSolids.end());
+      theObjects.insert(theObjects.end(), aCompounds.begin(), aCompounds.end());
 
       // Filter edges and faces in tools.
       ListOfShape aTools;
@@ -398,7 +423,7 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools,
         }
       }
 
-      if((anObjects.size() + aTools.size() +
+      if((anObjects.size() + aTools.size() + aCompounds.size() +
           aCompSolidsObjects.size() + anEdgesAndFaces.size()) < 2) {
         myFeature->setError("Error: Not enough objects for boolean operation.");
         return false;
@@ -409,31 +434,23 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools,
       aSolidsToFuse.insert(aSolidsToFuse.end(), anObjects.begin(), anObjects.end());
       aSolidsToFuse.insert(aSolidsToFuse.end(), aTools.begin(), aTools.end());
 
-      // Collecting solids from compsolids which will not be
+      // Collecting solids and compsolids from compounds which will not be
       // modified in boolean operation and will be added to result.
       ListOfShape aShapesToAdd;
-      for(std::map<GeomShapePtr, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
-          anIt != aCompSolidsObjects.end(); anIt++) {
+      for (ListOfShape::iterator anIt = aCompounds.begin();
+           anIt != aCompounds.end(); anIt++) {
+        GeomShapePtr aCompound = (*anIt);
+        addSubShapes(aCompound, anObjects, aShapesToAdd);
+      }
+
+      // Collecting solids from compsolids which will not be
+      // modified in boolean operation and will be added to result.
+      for (std::map<GeomShapePtr, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
+           anIt != aCompSolidsObjects.end(); anIt++) {
         GeomShapePtr aCompSolid = anIt->first;
         ListOfShape& aUsedShapes = anIt->second;
-        aSolidsToFuse.insert(aSolidsToFuse.end(), aUsedShapes.begin(), aUsedShapes.end());
-
-        // Collect solids from compsolid which will not be modified in boolean operation.
-        for (GeomAPI_ShapeIterator aCompSolidIt(aCompSolid);
-             aCompSolidIt.more();
-             aCompSolidIt.next())
-        {
-          GeomShapePtr aSolidInCompSolid = aCompSolidIt.current();
-          ListOfShape::iterator aUseIt = aUsedShapes.begin();
-          for(; aUseIt != aUsedShapes.end(); aUseIt++) {
-            if(aSolidInCompSolid->isEqual(*aUseIt)) {
-              break;
-            }
-          }
-          if(aUseIt == aUsedShapes.end()) {
-            aShapesToAdd.push_back(aSolidInCompSolid);
-          }
-        }
+        aSolidsToFuse.insert(aSolidsToFuse.end(), aUsedShapes.begin(), aUsedShapes.end()); //???
+        addSubShapes(aCompSolid, aUsedShapes, aShapesToAdd);
       }
 
       // Cut edges and faces(if we have any) with solids.
index bbcd26eb7cfd18c8eb163e5b1da495b7f841dd6d..3b91a61fad3f757fbac7f0cbc50054757c151462 100644 (file)
@@ -95,7 +95,8 @@ protected:
                           const GeomShapePtr theResultShapesCompound);
 
 private:
-  /// Makes cut operation recursively. Called from makeBoolean().
+  /// Makes cut operation recursively.
+  /// Called from makeBoolean().
   /// \param[in] theCompound the shape to be cut.
   /// \param[in] theTools list of tools.
   /// \param[out] theMakeShapeList list of according algos.
@@ -106,6 +107,16 @@ private:
                              std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
                              GeomShapePtr& theResult);
 
+  /// Add subshapes of \a theCompound to \a theSubShapesToAdd list,
+  /// except ones from \a theSubShapesToAvoid.
+  /// Called from makeBoolean().
+  /// \param[in] theCompound the shape to collect sub-shapes of.
+  /// \param[in] theSubShapesToAvoid list of shapes that should not be added to the result.
+  /// \param[out] theSubShapesToAdd list of found sub-shapes.
+  void addSubShapes (const GeomShapePtr theCompound,
+                     const ListOfShape& theSubShapesToAvoid,
+                     ListOfShape& theSubShapesToAdd);
+
 protected:
   ModelAPI_Feature* myFeature;
   OperationType myOperationType;
index 76bcad128228344ffa198d5d9eaf616564d873ae..90c2a768159d9604d52ec59847209ca2b900db0b 100644 (file)
@@ -74,6 +74,9 @@
           $1 = 0;
         }
       } 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..90a79bb5d7b477bcb9f3dec335aeb071de475906 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() > std::numeric_limits<double>::lowest() ) {
+      theDumper << myDouble.value();
+    }
+    else if (myValue.empty()) {
       theDumper << myBoolean;
-    else
+    }
+    else{
       theDumper << "\"" << myValue << "\"";
+    }
   }
 }
index 7b7cd30ff49f2f92383db5a285a70b72c87d84f1..dd569989421e74ba708920b2f576be19d814f24b 100644 (file)
 #include "FiltersAPI.h"
 
 #include <ModelAPI_AttributeSelection.h>
+#include <ModelHighAPI_Double.h>
 
 #include <ModelHighAPI_Dumper.h>
 #include <ModelHighAPI_Selection.h>
 
+#include <limits>
+
 /**\class FiltersAPI_Argument
  * \ingroup CPPHighAPI
  * \brief Argument of the Filter
@@ -39,6 +42,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 +64,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  = std::numeric_limits<double>::lowest() ;
   std::string myValue;
   ModelHighAPI_Selection mySelection;
   AttributeSelectionPtr mySelectionAttr;
index 215b2ef12892dc0dd5d915b978a8c9954ccdf3b9..329eee72dfd7c60a1869c847a6e81d389ebcce10 100644 (file)
 #include "FiltersAPI_Feature.h"
 
 #include <ModelAPI_Feature.h>
+#include <ModelAPI_FiltersFactory.h>
+#include <ModelAPI_Session.h>
 
 #include <ModelHighAPI_Dumper.h>
 #include <ModelHighAPI_Tools.h>
-#include <ModelAPI_Session.h>
-#include <ModelAPI_FiltersFactory.h>
 
 FiltersAPI_Feature::FiltersAPI_Feature(
     const std::shared_ptr<ModelAPI_Feature> & theFeature)
@@ -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() > std::numeric_limits<double>::lowest()) {
+      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..f1f37393a92cae45e76aace7c94bb46181569187 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,6 +73,12 @@ 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()));
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..f0e0fee
--- /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 <GeomAPI_ShapeExplorer.h>
+#include <GeomAPI_Wire.h>
+
+#include <GeomAlgoAPI_ShapeTools.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 (GeomAlgoAPI_ShapeTools::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()) {
+    for (size_t i = 0; i < aList->size(); i++)
+    {
+      ResultBodyPtr aBaseResult = ModelAPI_Tools::bodyOwner(aList->value(i)->context(), true);
+      if (!aBaseResult.get()) {
+        aBaseResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aList->value(i)->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..e274831
--- /dev/null
@@ -0,0 +1,116 @@
+// 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 <GeomAPI_Wire.h>
+
+#include <GeomAlgoAPI_ShapeTools.h>
+
+#include <Precision.hxx>
+
+#include <map>
+#include <cmath>
+
+//=================================================================================================
+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 - Precision::Confusion();
+  else if (aCompString == "infEq")
+    isOK = aLength < aVal + Precision::Confusion();
+  else if (aCompString == "sup")
+    isOK = aLength > aVal + Precision::Confusion();
+  else if (aCompString == "supEq")
+    isOK = aLength > aVal - Precision::Confusion();
+  else if (aCompString == "isBetween")
+    isOK = aVal <= aValMax
+           && aLength > aVal - Precision::Confusion()
+           && aLength < aValMax + Precision::Confusion();
+  else if (aCompString == "isStrictlyBetween")
+    isOK = aVal <= aValMax
+           && aLength > aVal + Precision::Confusion()
+           && 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..1311f57
--- /dev/null
@@ -0,0 +1,101 @@
+// 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 <GeomAlgoAPI_ShapeTools.h>
+#include <ModelAPI_Tools.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Shape.h>
+#include <GeomAPI_Wire.h>
+
+#include <Precision.hxx>
+
+#include <map>
+#include <cmath>
+
+//=================================================================================================
+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 aSurfArea = GeomAlgoAPI_ShapeTools::area(theShape);
+
+  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 - Precision::Confusion();
+  else if (aCompString == "infEq")
+    isOK = aSurfArea < aVal + Precision::Confusion();
+  else if (aCompString == "sup")
+    isOK = aSurfArea > aVal + Precision::Confusion();
+  else if (aCompString == "supEq")
+    isOK = aSurfArea > aVal - Precision::Confusion();
+  else if (aCompString == "isBetween")
+    isOK = aVal <= aValMax
+           && aSurfArea > aVal - Precision::Confusion()
+           && aSurfArea < aValMax + Precision::Confusion();
+  else if (aCompString == "isStrictlyBetween")
+    isOK = aVal <= aValMax
+           && aSurfArea > aVal + Precision::Confusion()
+           && 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..2849dc5
--- /dev/null
@@ -0,0 +1,144 @@
+// 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_Edge.h>
+#include <GeomAPI_Shape.h>
+#include <GeomAPI_ShapeExplorer.h>
+#include <GeomAPI_Wire.h>
+
+#include <GeomAlgoAPI_ShapeTools.h>
+
+#include <Precision.hxx>
+
+#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 (theAngle < Precision::Confusion()
+              || !GeomAlgoAPI_ShapeTools::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..59d25b9ddbe469f4c030a0e380f305a71608cf77 100644 (file)
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
-#include "FiltersPlugin_Plugin.h"
-#include "FiltersPlugin_Selection.h"
-#include "FiltersPlugin_HorizontalFace.h"
-#include "FiltersPlugin_VerticalFace.h"
 #include "FiltersPlugin_BelongsTo.h"
-#include "FiltersPlugin_OnPlane.h"
-#include "FiltersPlugin_OnLine.h"
+#include "FiltersPlugin_ContinuousFaces.h"
+#include "FiltersPlugin_EdgeSize.h"
+#include "FiltersPlugin_ExternalFaces.h"
+#include "FiltersPlugin_FaceSize.h"
+#include "FiltersPlugin_FeatureEdges.h"
+#include "FiltersPlugin_HorizontalFace.h"
 #include "FiltersPlugin_OnGeometry.h"
+#include "FiltersPlugin_OnLine.h"
+#include "FiltersPlugin_OnPlane.h"
 #include "FiltersPlugin_OnPlaneSide.h"
 #include "FiltersPlugin_OppositeToEdge.h"
+#include "FiltersPlugin_Plugin.h"
 #include "FiltersPlugin_RelativeToSolid.h"
-#include "FiltersPlugin_ExternalFaces.h"
+#include "FiltersPlugin_Selection.h"
 #include "FiltersPlugin_Validators.h"
+#include "FiltersPlugin_VerticalFace.h"
+#include "FiltersPlugin_VolumeSize.h"
 
 #include <Config_ModuleReader.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..9776296
--- /dev/null
@@ -0,0 +1,101 @@
+// 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 <GeomAlgoAPI_ShapeTools.h>
+#include <ModelAPI_Tools.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Shape.h>
+#include <GeomAPI_Wire.h>
+
+#include <Precision.hxx>
+
+#include <map>
+#include <cmath>
+
+//=================================================================================================
+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 aVolume = GeomAlgoAPI_ShapeTools::volume(theShape);
+
+  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 - Precision::Confusion();
+  else if (aCompString == "infEq")
+    isOK = aVolume < aVal + Precision::Confusion();
+  else if (aCompString == "sup")
+    isOK = aVolume > aVal + Precision::Confusion();
+  else if (aCompString == "supEq")
+    isOK = aVolume > aVal - Precision::Confusion();
+  else if (aCompString == "isBetween")
+    isOK = aVal <= aValMax
+          && aVolume > aVal - Precision::Confusion()
+          && aVolume < aValMax + Precision::Confusion();
+  else if (aCompString == "isStrictlyBetween")
+    isOK = aVal <= aValMax
+           && aVolume > aVal + Precision::Confusion()
+           && 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..7ff4f5b
--- /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 volume
+*/
+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 solid 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..eb39232e58d1a8d661d44fe39f90feb78e5251a1 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>
     </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>
     <name>OnGeometry</name>
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..45036ef
--- /dev/null
@@ -0,0 +1,15 @@
+<filter id="ContinuousFaces">
+  <doublevalue id="ContinuousFaces__value"
+               label="Angle"
+               min="0"
+               step="0.1"
+               default="5"
+               tooltip="Continuity angle">
+  </doublevalue>
+  <multi_selector id="ContinuousFaces__faces"
+                  label="Faces:"
+                  tooltip="Select faces"
+                  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..b6eaed8
--- /dev/null
@@ -0,0 +1,80 @@
+<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"
+                   tooltip="&lt; to">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+    </case>
+    <case id="infEq" title="&lt;=">
+      <doublevalue id="EdgeSize__value"
+                   label="Size"
+                   min="0"
+                   step="0.1"
+                   default="1"
+                   tooltip="&lt;= to">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+    </case>
+    <case id="sup" title="&gt;">
+      <doublevalue id="EdgeSize__value"
+                   label="Size"
+                   min="0"
+                   step="0.1"
+                   default="1"
+                   tooltip="&gt; to">
+        <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"
+                   tooltip="&gt;= to">
+        <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"
+                   tooltip="Min value">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+      <doublevalue id="EdgeSize__valueMax"
+                   label="Max size"
+                   min="0"
+                   step="0.1"
+                   default="10"
+                   tooltip="Max value">
+        <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"
+                   tooltip="Min value">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+      <doublevalue id="EdgeSize__valueMax"
+                   label="Max size"
+                   min="0"
+                   step="0.1"
+                   default="10"
+                   tooltip="Max value">
+        <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..41d75e6
--- /dev/null
@@ -0,0 +1,72 @@
+<filter id="FaceSize">
+  <switch id="FaceSize__comparatorType">
+    <case id="inf" title="&lt;">
+      <doublevalue id="FaceSize__value"
+                   label="Size"
+                   min="0"
+                   default="1"
+                   tooltip="&lt; to">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+    </case>
+    <case id="infEq" title="&lt;=">
+      <doublevalue id="FaceSize__value"
+                   label="Size"
+                   min="0" step="0.1"
+                   default="1"
+                   tooltip="&lt;= to">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+    </case>
+    <case id="sup" title="&gt;">
+      <doublevalue id="FaceSize__value"
+                   label="Size"
+                   min="0" step="0.1"
+                   default="1"
+                   tooltip="&gt; to">
+        <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"
+                   tooltip="&gt;= to">
+        <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"
+                   tooltip="Min value">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+      <doublevalue id="FaceSize__valueMax"
+                   label="Max size"
+                   min="0" step="0.1"
+                   default="10"
+                   tooltip="Max value">
+        <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"
+                   tooltip="Min value">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+      <doublevalue id="FaceSize__valueMax"
+                   label="Max size"
+                   min="0" step="0.1"
+                   default="10"
+                   tooltip="Max value">
+        <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..a96933f
--- /dev/null
@@ -0,0 +1,9 @@
+<filter id="FeatureEdges">
+  <doublevalue id="FeatureEdges__value"
+               label="Angle"
+               min="0"
+               step="0.1"
+               default="5"
+               tooltip="Edge angle">
+  </doublevalue>
+</filter>
diff --git a/src/FiltersPlugin/filter-VolumeSize.xml b/src/FiltersPlugin/filter-VolumeSize.xml
new file mode 100644 (file)
index 0000000..a09a030
--- /dev/null
@@ -0,0 +1,72 @@
+<filter id="VolumeSize">
+  <switch id="VolumeSize__comparatorType">
+    <case id="inf" title="&lt;">
+      <doublevalue id="VolumeSize__value"
+                   label="Size"
+                   min="0"
+                   default="1"
+                   tooltip="&lt; to">
+        <validator id="GeomValidators_Positive" />
+      </doublevalue>
+    </case>
+    <case id="infEq" title="&lt;=">
+      <doublevalue id="VolumeSize__value"
+                   label="Size"
+                   min="0" step="0.1"
+                   default="1"
+                   tooltip="&lt;= to">
+        <validator id="GeomValidators_Positive"/>
+      </doublevalue>
+    </case>
+    <case id="sup" title="&gt;">
+      <doublevalue id="VolumeSize__value"
+                   label="Size"
+                   min="0" step="0.1"
+                   default="1"
+                   tooltip="&gt; to">
+        <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"
+                   tooltip="&gt;="> to">
+        <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"
+                   tooltip="Min value">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+      <doublevalue id="VolumeSize__valueMax"
+                   label="Max size"
+                   min="0" step="0.1"
+                   default="10"
+                   tooltip="Max value">
+        <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"
+                   tooltip="Min value">
+        <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
+      </doublevalue>
+      <doublevalue id="VolumeSize__valueMax"
+                   label="Max size"
+                   min="0" step="0.1"
+                   default="10"
+                   tooltip="Max value">
+        <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 037bacbc41e191ab46b8a8c97a9d8e5b029db265..1d07bf469985dec693eafa428ede90f5eff94f5a 100644 (file)
 
 #include <NCollection_Vector.hxx>
 
+#include <LocalAnalysis_SurfaceContinuity.hxx>
+
 //==================================================================================================
 static GProp_GProps props(const TopoDS_Shape& theShape)
 {
@@ -133,11 +135,11 @@ static GProp_GProps props(const TopoDS_Shape& theShape)
 double GeomAlgoAPI_ShapeTools::length(const std::shared_ptr<GeomAPI_Shape> theShape)
 {
   GProp_GProps aGProps;
-  if(!theShape.get()) {
+  if (!theShape.get()) {
     return 0.0;
   }
   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
-  if(aShape.IsNull()) {
+  if (aShape.IsNull()) {
     return 0.0;
   }
 
@@ -148,11 +150,11 @@ double GeomAlgoAPI_ShapeTools::length(const std::shared_ptr<GeomAPI_Shape> theSh
 //==================================================================================================
 double GeomAlgoAPI_ShapeTools::volume(const std::shared_ptr<GeomAPI_Shape> theShape)
 {
-  if(!theShape.get()) {
+  if (!theShape.get()) {
     return 0.0;
   }
   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
-  if(aShape.IsNull()) {
+  if (aShape.IsNull()) {
     return 0.0;
   }
   const Standard_Real anEps = 1.e-6;
@@ -169,11 +171,11 @@ double GeomAlgoAPI_ShapeTools::volume(const std::shared_ptr<GeomAPI_Shape> theSh
 double GeomAlgoAPI_ShapeTools::area (const std::shared_ptr<GeomAPI_Shape> theShape)
 {
   GProp_GProps aGProps;
-  if(!theShape.get()) {
+  if (!theShape.get()) {
     return 0.0;
   }
   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
-  if(aShape.IsNull()) {
+  if (aShape.IsNull()) {
     return 0.0;
   }
   const Standard_Real anEps = 1.e-6;
@@ -182,20 +184,119 @@ double GeomAlgoAPI_ShapeTools::area (const std::shared_ptr<GeomAPI_Shape> theSha
   return aGProps.Mass();
 }
 
+//==================================================================================================
+bool GeomAlgoAPI_ShapeTools::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 * M_PI / 180.0); //EpsG1
+    aRes = aLocAnal.IsG1();
+  }
+  catch (Standard_Failure const& anException) {
+    theError = "LocalAnalysis_SurfaceContinuity error :";
+    theError += anException.GetMessageString();
+  }
+
+  return aRes;
+}
+
 //==================================================================================================
 std::shared_ptr<GeomAPI_Pnt>
   GeomAlgoAPI_ShapeTools::centreOfMass(const std::shared_ptr<GeomAPI_Shape> theShape)
 {
   GProp_GProps aGProps;
-  if(!theShape) {
+  if (!theShape) {
     return std::shared_ptr<GeomAPI_Pnt>();
   }
   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
-  if(aShape.IsNull()) {
+  if (aShape.IsNull()) {
     return std::shared_ptr<GeomAPI_Pnt>();
   }
   gp_Pnt aCentre;
-  if(aShape.ShapeType() == TopAbs_VERTEX) {
+  if (aShape.ShapeType() == TopAbs_VERTEX) {
     aCentre = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
   } else {
     aGProps = props(aShape);
@@ -266,17 +367,17 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
 
   GeomShapePtr aResult = theCompound;
 
-  if(!theCompound.get()) {
+  if (!theCompound.get()) {
     return aResult;
   }
 
-  if(theType != GeomAPI_Shape::SHELL && theType != GeomAPI_Shape::COMPSOLID) {
+  if (theType != GeomAPI_Shape::SHELL && theType != GeomAPI_Shape::COMPSOLID) {
     return aResult;
   }
 
   TopAbs_ShapeEnum aTS = TopAbs_EDGE;
   TopAbs_ShapeEnum aTA = TopAbs_FACE;
-  if(theType == GeomAPI_Shape::COMPSOLID) {
+  if (theType == GeomAPI_Shape::COMPSOLID) {
     aTS = TopAbs_FACE;
     aTA = TopAbs_SOLID;
   }
@@ -289,15 +390,15 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
   // Get free shapes.
   int anOrder = 0;
   const TopoDS_Shape& aShapesComp = theCompound->impl<TopoDS_Shape>();
-  for(TopoDS_Iterator anIter(aShapesComp); anIter.More(); anIter.Next(), anOrder++) {
+  for (TopoDS_Iterator anIter(aShapesComp); anIter.More(); anIter.Next(), anOrder++) {
     const TopoDS_Shape& aShape = anIter.Value();
-    if(aShape.ShapeType() > aTA) {
+    if (aShape.ShapeType() > aTA) {
       std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
       aGeomShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aShape));
       aResFreeShapes.push_back(aGeomShape);
       anInputOrder[aGeomShape] = anOrder;
     } else {
-      for(TopExp_Explorer anExp(aShape, aTA); anExp.More(); anExp.Next()) {
+      for (TopExp_Explorer anExp(aShape, aTA); anExp.More(); anExp.Next()) {
         anAncestorsOrder.Bind(anExp.Current(), anOrder);
       }
     }
@@ -306,7 +407,7 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
   // Map sub-shapes and shapes.
   TopTools_IndexedDataMapOfShapeListOfShape aMapSA;
   TopExp::MapShapesAndAncestors(aShapesComp, aTS, aTA, aMapSA);
-  if(aMapSA.IsEmpty()) {
+  if (aMapSA.IsEmpty()) {
     return aResult;
   }
   theResuts.clear();
@@ -314,13 +415,13 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
   // Get all shapes with common sub-shapes and free shapes.
   NCollection_Map<TopoDS_Shape> aFreeShapes;
   NCollection_Vector<NCollection_Map<TopoDS_Shape>> aShapesWithCommonSubshapes;
-  for(TopTools_IndexedDataMapOfShapeListOfShape::Iterator
+  for (TopTools_IndexedDataMapOfShapeListOfShape::Iterator
       anIter(aMapSA); anIter.More(); anIter.Next()) {
     TopTools_ListOfShape& aListOfShape = anIter.ChangeValue();
-    if(aListOfShape.IsEmpty()) {
+    if (aListOfShape.IsEmpty()) {
       continue;
     }
-    else if(aListOfShape.Size() == 1) {
+    else if (aListOfShape.Size() == 1) {
       const TopoDS_Shape& aF = aListOfShape.First();
       aFreeShapes.Add(aF);
       aListOfShape.Clear();
@@ -333,17 +434,17 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
         aFreeShapes.Remove(aListIt.Value());
       }
       aListOfShape.Clear();
-      for(NCollection_List<TopoDS_Shape>::Iterator
+      for (NCollection_List<TopoDS_Shape>::Iterator
           aTempIter(aTempList); aTempIter.More(); aTempIter.Next()) {
         const TopoDS_Shape& aTempShape = aTempIter.Value();
-        for(TopTools_IndexedDataMapOfShapeListOfShape::Iterator
+        for (TopTools_IndexedDataMapOfShapeListOfShape::Iterator
             anIter2(aMapSA); anIter2.More(); anIter2.Next()) {
           TopTools_ListOfShape& aTempListOfShape = anIter2.ChangeValue();
-          if(aTempListOfShape.IsEmpty()) {
+          if (aTempListOfShape.IsEmpty()) {
             continue;
-          } else if(aTempListOfShape.Size() == 1 && aTempListOfShape.First() == aTempShape) {
+          } else if (aTempListOfShape.Size() == 1 && aTempListOfShape.First() == aTempShape) {
             aTempListOfShape.Clear();
-          } else if(aTempListOfShape.Size() > 1) {
+          } else if (aTempListOfShape.Size() > 1) {
             TopTools_ListOfShape::Iterator anIt1(aTempListOfShape);
             for (; anIt1.More(); anIt1.Next()) {
               if (anIt1.Value() == aTempShape) {
@@ -369,7 +470,7 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
   }
 
   // Combine shapes with common sub-shapes.
-  for(NCollection_Vector<NCollection_Map<TopoDS_Shape>>::Iterator
+  for (NCollection_Vector<NCollection_Map<TopoDS_Shape>>::Iterator
       anIter(aShapesWithCommonSubshapes); anIter.More(); anIter.Next()) {
     TopoDS_Shell aShell;
     TopoDS_CompSolid aCSolid;
@@ -378,9 +479,9 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
     theType ==
       GeomAPI_Shape::COMPSOLID ? aBuilder.MakeCompSolid(aCSolid) : aBuilder.MakeShell(aShell);
     NCollection_Map<TopoDS_Shape>& aShapesMap = anIter.ChangeValue();
-    for(TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) {
+    for (TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) {
       const TopoDS_Shape& aShape = anExp.Current();
-      if(aShapesMap.Contains(aShape)) {
+      if (aShapesMap.Contains(aShape)) {
         theType ==
           GeomAPI_Shape::COMPSOLID ? aBuilder.Add(aCSolid, aShape) : aBuilder.Add(aShell, aShape);
         aShapesMap.Remove(aShape);
@@ -398,9 +499,9 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
   }
 
   // Adding free shapes.
-  for(TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) {
+  for (TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) {
     const TopoDS_Shape& aShape = anExp.Current();
-    if(aFreeShapes.Contains(aShape)) {
+    if (aFreeShapes.Contains(aShape)) {
       std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
       aGeomShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aShape));
       aResFreeShapes.push_back(aGeomShape);
@@ -408,10 +509,10 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
     }
   }
 
-  if(aResCombinedShapes.size() == 1 && aResFreeShapes.size() == 0) {
+  if (aResCombinedShapes.size() == 1 && aResFreeShapes.size() == 0) {
     aResult = aResCombinedShapes.front();
     theResuts.push_back(aResult);
-  } else if(aResCombinedShapes.size() == 0 && aResFreeShapes.size() == 1) {
+  } else if (aResCombinedShapes.size() == 0 && aResFreeShapes.size() == 1) {
     aResult = aResFreeShapes.front();
     theResuts.push_back(aResult);
   } else {
@@ -421,10 +522,10 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
     // put to result compound and result list in accordance to the order numbers
     std::map<GeomShapePtr, int>::iterator anInputIter = anInputOrder.begin();
     std::map<int, GeomShapePtr> aNums;
-    for(; anInputIter != anInputOrder.end(); anInputIter++)
+    for (; anInputIter != anInputOrder.end(); anInputIter++)
       aNums[anInputIter->second] = anInputIter->first;
     std::map<int, GeomShapePtr>::iterator aNumsIter = aNums.begin();
-    for(; aNumsIter != aNums.end(); aNumsIter++) {
+    for (; aNumsIter != aNums.end(); aNumsIter++) {
       aBuilder.Add(aResultComp, (aNumsIter->second)->impl<TopoDS_Shape>());
       theResuts.push_back(aNumsIter->second);
     }
@@ -438,12 +539,12 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
 static void addSimpleShapeToList(const TopoDS_Shape& theShape,
                                  NCollection_List<TopoDS_Shape>& theList)
 {
-  if(theShape.IsNull()) {
+  if (theShape.IsNull()) {
     return;
   }
 
-  if(theShape.ShapeType() == TopAbs_COMPOUND) {
-    for(TopoDS_Iterator anIt(theShape); anIt.More(); anIt.Next()) {
+  if (theShape.ShapeType() == TopAbs_COMPOUND) {
+    for (TopoDS_Iterator anIt(theShape); anIt.More(); anIt.Next()) {
       addSimpleShapeToList(anIt.Value(), theList);
     }
   } else {
@@ -459,7 +560,7 @@ static TopoDS_Compound makeCompound(const NCollection_List<TopoDS_Shape> theShap
   BRep_Builder aBuilder;
   aBuilder.MakeCompound(aCompound);
 
-  for(NCollection_List<TopoDS_Shape>::Iterator anIt(theShapes); anIt.More(); anIt.Next()) {
+  for (NCollection_List<TopoDS_Shape>::Iterator anIt(theShapes); anIt.More(); anIt.Next()) {
     aBuilder.Add(aCompound, anIt.Value());
   }
 
@@ -570,7 +671,7 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::groupSharedTopology(
   for (NCollection_Vector<TopTools_MapOfShape>::Iterator anIt(aGroups); anIt.More(); anIt.Next()) {
     const TopTools_MapOfShape& aGroup = anIt.ChangeValue();
     GeomShapePtr aGeomShape(new GeomAPI_Shape());
-    if(aGroup.Size() == 1) {
+    if (aGroup.Size() == 1) {
       TopTools_MapOfShape::Iterator aOneShapeIter(aGroup);
       aGeomShape->setImpl(new TopoDS_Shape(aOneShapeIter.Value()));
     } else {
@@ -589,7 +690,7 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::groupSharedTopology(
     aBuilder.Add(aCompound, aGeomShape->impl<TopoDS_Shape>());
   }
 
-  if(!aCompound.IsNull()) {
+  if (!aCompound.IsNull()) {
     aResult->setImpl(new TopoDS_Shape(aCompound));
   }
 
@@ -628,7 +729,7 @@ std::list<std::shared_ptr<GeomAPI_Pnt> >
     BRepBndLib::Add(aShape, aBndBox);
   }
 
-  if(theEnlarge != 0.0) {
+  if (theEnlarge != 0.0) {
     // We enlarge bounding box just to be sure that plane will be large enough to cut all objects.
     aBndBox.Enlarge(theEnlarge);
   }
@@ -637,9 +738,9 @@ std::list<std::shared_ptr<GeomAPI_Pnt> >
   Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
   Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
   std::list<std::shared_ptr<GeomAPI_Pnt> > aResultPoints;
-  for(int i = 0; i < 2; i++) {
-    for(int j = 0; j < 2; j++) {
-      for(int k = 0; k < 2; k++) {
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      for (int k = 0; k < 2; k++) {
         std::shared_ptr<GeomAPI_Pnt> aPnt(new GeomAPI_Pnt(aXArr[i], aYArr[j], aZArr[k]));
         aResultPoints.push_back(aPnt);
       }
@@ -656,27 +757,27 @@ std::shared_ptr<GeomAPI_Face> GeomAlgoAPI_ShapeTools::fitPlaneToBox(
 {
   std::shared_ptr<GeomAPI_Face> aResultFace;
 
-  if(!thePlane.get()) {
+  if (!thePlane.get()) {
     return aResultFace;
   }
 
   const TopoDS_Shape& aShape = thePlane->impl<TopoDS_Shape>();
-  if(aShape.ShapeType() != TopAbs_FACE) {
+  if (aShape.ShapeType() != TopAbs_FACE) {
     return aResultFace;
   }
 
   TopoDS_Face aFace = TopoDS::Face(aShape);
   Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
-  if(aSurf.IsNull()) {
+  if (aSurf.IsNull()) {
     return aResultFace;
   }
 
   GeomLib_IsPlanarSurface isPlanar(aSurf);
-  if(!isPlanar.IsPlanar()) {
+  if (!isPlanar.IsPlanar()) {
     return aResultFace;
   }
 
-  if(thePoints.size() != 8) {
+  if (thePoints.size() != 8) {
     return aResultFace;
   }
 
@@ -693,10 +794,10 @@ std::shared_ptr<GeomAPI_Face> GeomAlgoAPI_ShapeTools::fitPlaneToBox(
     const gp_Pnt& aPntOnFace = anIntAna.Point(1);
     Standard_Real aPntU(0), aPntV(0);
     GeomLib_Tool::Parameters(aFacePlane, aPntOnFace, Precision::Confusion(), aPntU, aPntV);
-    if(aPntU < UMin) UMin = aPntU;
-    if(aPntU > UMax) UMax = aPntU;
-    if(aPntV < VMin) VMin = aPntV;
-    if(aPntV > VMax) VMax = aPntV;
+    if (aPntU < UMin) UMin = aPntU;
+    if (aPntU > UMax) UMax = aPntU;
+    if (aPntV < VMin) VMin = aPntV;
+    if (aPntV > VMax) VMax = aPntV;
   }
   aResultFace.reset(new GeomAPI_Face());
   aResultFace->setImpl(new TopoDS_Face(BRepLib_MakeFace(aFacePln, UMin, UMax, VMin, VMax).Face()));
@@ -743,7 +844,7 @@ void GeomAlgoAPI_ShapeTools::makeFacesWithHoles(const std::shared_ptr<GeomAPI_Pn
 
   BRepAlgo_FaceRestrictor aFRestrictor;
   aFRestrictor.Init(aFace, Standard_False, Standard_True);
-  for(ListOfShape::const_iterator anIt = theWires.cbegin();
+  for (ListOfShape::const_iterator anIt = theWires.cbegin();
       anIt != theWires.cend();
       ++anIt) {
     TopoDS_Wire aWire = TopoDS::Wire((*anIt)->impl<TopoDS_Shape>());
@@ -752,11 +853,11 @@ void GeomAlgoAPI_ShapeTools::makeFacesWithHoles(const std::shared_ptr<GeomAPI_Pn
 
   aFRestrictor.Perform();
 
-  if(!aFRestrictor.IsDone()) {
+  if (!aFRestrictor.IsDone()) {
     return;
   }
 
-  for(; aFRestrictor.More(); aFRestrictor.Next()) {
+  for (; aFRestrictor.More(); aFRestrictor.Next()) {
     GeomShapePtr aShape(new GeomAPI_Shape());
     aShape->setImpl(new TopoDS_Shape(aFRestrictor.Current()));
     theFaces.push_back(aShape);
@@ -770,12 +871,12 @@ std::shared_ptr<GeomAPI_Pln> GeomAlgoAPI_ShapeTools::findPlane(const ListOfShape
   BRep_Builder aBuilder;
   aBuilder.MakeCompound(aCompound);
 
-  for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
+  for (ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
     aBuilder.Add(aCompound, (*anIt)->impl<TopoDS_Shape>());
   }
   BRepBuilderAPI_FindPlane aFindPlane(aCompound);
 
-  if(aFindPlane.Found() != Standard_True) {
+  if (aFindPlane.Found() != Standard_True) {
     return std::shared_ptr<GeomAPI_Pln>();
   }
 
@@ -796,28 +897,28 @@ bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(
   const std::shared_ptr<GeomAPI_Shape> theSubShape,
   const std::shared_ptr<GeomAPI_Shape> theBaseShape)
 {
-  if(!theSubShape.get() || !theBaseShape.get()) {
+  if (!theSubShape.get() || !theBaseShape.get()) {
     return false;
   }
 
   const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
   const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
 
-  if(aSubShape.ShapeType() == TopAbs_VERTEX) {
+  if (aSubShape.ShapeType() == TopAbs_VERTEX) {
     // If sub-shape is a vertex check distance to shape. If it is <= Precision::Confusion() then OK.
     BRepExtrema_DistShapeShape aDist(aBaseShape, aSubShape);
     aDist.Perform();
-    if(!aDist.IsDone() || aDist.Value() > Precision::Confusion()) {
+    if (!aDist.IsDone() || aDist.Value() > Precision::Confusion()) {
       return false;
     }
   } else if (aSubShape.ShapeType() == TopAbs_EDGE) {
-    if(aBaseShape.ShapeType() == TopAbs_FACE) {
+    if (aBaseShape.ShapeType() == TopAbs_FACE) {
       // Check that edge is on face surface.
       TopoDS_Face aFace = TopoDS::Face(aBaseShape);
       TopoDS_Edge anEdge = TopoDS::Edge(aSubShape);
       BRepLib_CheckCurveOnSurface aCheck(anEdge, aFace);
       aCheck.Perform();
-      if(!aCheck.IsDone() || aCheck.MaxDistance() > Precision::Confusion()) {
+      if (!aCheck.IsDone() || aCheck.MaxDistance() > Precision::Confusion()) {
         return false;
       }
 
@@ -826,15 +927,15 @@ bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(
       ShapeAnalysis::FindBounds(anEdge, aV1, aV2);
       gp_Pnt aPnt1 = BRep_Tool::Pnt(aV1);
       gp_Pnt aPnt2 = BRep_Tool::Pnt(aV2);
-      for(TopExp_Explorer anExp(aBaseShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
+      for (TopExp_Explorer anExp(aBaseShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
         const TopoDS_Shape& anEdgeOnFace = anExp.Current();
         BRepExtrema_DistShapeShape aDist(anEdgeOnFace, anEdge);
         aDist.Perform();
-        if(aDist.IsDone() && aDist.Value() <= Precision::Confusion()) {
+        if (aDist.IsDone() && aDist.Value() <= Precision::Confusion()) {
           // Edge intersect face bound. Check that it is not on edge begin or end.
-          for(Standard_Integer anIndex = 1; anIndex <= aDist.NbSolution(); ++anIndex) {
+          for (Standard_Integer anIndex = 1; anIndex <= aDist.NbSolution(); ++anIndex) {
             gp_Pnt aPntOnSubShape = aDist.PointOnShape2(anIndex);
-            if(aPntOnSubShape.Distance(aPnt1) > Precision::Confusion()
+            if (aPntOnSubShape.Distance(aPnt1) > Precision::Confusion()
                 && aPntOnSubShape.Distance(aPnt2) > Precision::Confusion()) {
               return false;
             }
@@ -851,7 +952,7 @@ bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(
       ShapeAnalysis_Surface aSAS(aSurface);
       gp_Pnt2d aPointOnFace = aSAS.ValueOfUV(aPointToCheck, Precision::Confusion());
       BRepTopAdaptor_FClass2d aFClass2d(aFace, Precision::Confusion());
-      if(aFClass2d.Perform(aPointOnFace) == TopAbs_OUT) {
+      if (aFClass2d.Perform(aPointOnFace) == TopAbs_OUT) {
         return false;
       }
 
@@ -868,7 +969,7 @@ bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(
 //==================================================================================================
 bool GeomAlgoAPI_ShapeTools::isShapeValid(const std::shared_ptr<GeomAPI_Shape> theShape)
 {
-  if(!theShape.get()) {
+  if (!theShape.get()) {
     return false;
   }
 
@@ -882,7 +983,7 @@ std::shared_ptr<GeomAPI_Shape>
 {
   GeomShapePtr anOuterWire;
 
-  if(!theFace.get() || !theFace->isFace()) {
+  if (!theFace.get() || !theFace->isFace()) {
     return anOuterWire;
   }
 
@@ -937,7 +1038,7 @@ bool GeomAlgoAPI_ShapeTools::isTangent(const std::shared_ptr<GeomAPI_Edge> theEd
 bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr<GeomAPI_Edge> theEdge,
                                         const std::shared_ptr<GeomAPI_Face> theFace)
 {
-  if(!theEdge.get() || !theFace.get()) {
+  if (!theEdge.get() || !theFace.get()) {
     return false;
   }
 
@@ -953,7 +1054,7 @@ std::list<std::shared_ptr<GeomAPI_Vertex> > GeomAlgoAPI_ShapeTools::intersect(
   const std::shared_ptr<GeomAPI_Edge> theEdge, const std::shared_ptr<GeomAPI_Face> theFace)
 {
   std::list<std::shared_ptr<GeomAPI_Vertex> > aResult;
-  if(!theEdge.get() || !theFace.get()) {
+  if (!theEdge.get() || !theFace.get()) {
     return aResult;
   }
 
@@ -968,7 +1069,7 @@ std::list<std::shared_ptr<GeomAPI_Vertex> > GeomAlgoAPI_ShapeTools::intersect(
   if (!anIntAlgo.IsDone())
     return aResult;
   // searching for points-intersection
-  for(int anIntNum = 1; anIntNum <= anIntAlgo.NbPoints() + anIntAlgo.NbSegments(); anIntNum++) {
+  for (int anIntNum = 1; anIntNum <= anIntAlgo.NbPoints() + anIntAlgo.NbSegments(); anIntNum++) {
     gp_Pnt anInt;
     if (anIntNum <= anIntAlgo.NbPoints()) {
       anInt = anIntAlgo.Point(anIntNum);
@@ -1331,12 +1432,12 @@ void GeomAlgoAPI_ShapeTools::computeThroughAll(const ListOfShape& theObjects,
           TopExp_Explorer anExp(aBaseShape, TopAbs_FACE);
           const TopoDS_Shape& aFace = anExp.Current();
           Handle(Geom_Surface) aSurface = BRep_Tool::Surface(TopoDS::Face(aFace));
-          if(aSurface->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
+          if (aSurface->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
             Handle(Geom_RectangularTrimmedSurface) aTrimSurface =
               Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
             aSurface = aTrimSurface->BasisSurface();
           }
-          if(aSurface->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
+          if (aSurface->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
             return;
           }
           aPlane = Handle(Geom_Plane)::DownCast(aSurface);
index b1f154948890d96c8de783aec26bd0c4a4ff70ee..5f511d73c2bd2ba211de2941d9e01f16f8c45e7a 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <GeomAPI_Shape.h>
 #include <GeomAPI_Vertex.h>
+#include <GeomAPI_Pnt.h>
 #include <map>
 #include <set>
 #ifdef WIN32
@@ -56,6 +57,19 @@ public:
   /// \return the total area of the faces of the current shape or 0.0 if it can be computed.
   GEOMALGOAPI_EXPORT static double area(const std::shared_ptr<GeomAPI_Shape> theShape);
 
+  /// 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 static bool isContinuousFaces(const GeomShapePtr& theFace1,
+                                                   const GeomShapePtr& theFace2,
+                                                   const GeomPointPtr& thePoint,
+                                                   const double & theAngle,
+                                                   std::string& theError);
+
   /// \return the center of mass of the current face.
   /// The coordinates returned for the center of mass
   /// are expressed in the absolute Cartesian coordinate system.
index 89cc9a2639e0d71ef040c6ee7f335fa78ae546c6..4d5527eba3c3174150703a904109ca8f89693752 100644 (file)
@@ -44,11 +44,11 @@ bool GeomValidators_Positive::isValid(const AttributePtr& theAttribute,
                                       const std::list<std::string>& theArguments,
                                       Events_InfoMessage& theError) const
 {
-  double aMinValue = 1.e-5;
-  if(theArguments.size() == 1) {
+  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());
-    if(aValue != 0) {
+    if (aValue != 0) {
       // very probably ok
       aMinValue = aValue;
     }
@@ -79,6 +79,5 @@ bool GeomValidators_Positive::isValid(const AttributePtr& theAttribute,
       return false;
     }
   }
-
   return true;
 }
index 332af8b86e832e5a05352734a2395774f5672885..a111cc1938e2bf87d5f14eac073d602a5efabb45 100644 (file)
 INCLUDE(Common)
 INCLUDE(UnitTest)
 
+IF(NOT Boost_INCLUDE_DIR)
+  FILE(TO_CMAKE_PATH "$ENV{BOOST_ROOT_DIR}" BOOST_ROOT)
+  FIND_PACKAGE(Boost REQUIRED)
+ENDIF()
+
 INCLUDE_DIRECTORIES(
     ${CMAKE_CURRENT_SOURCE_DIR}
     ${Boost_INCLUDE_DIR}
index 432c6f1c2e7740d37293b040c46aafd89823e727..9f48443fa5e4aa95eecb068156e18a72a393133e 100644 (file)
@@ -454,10 +454,11 @@ bool Model_AttributeSelection::isInitialized()
 
 Model_AttributeSelection::Model_AttributeSelection(TDF_Label& theLabel)
 : myRef(theLabel),
+  myTmpCenterType(NOT_CENTER),
+  myParent(NULL),
   myIsGeometricalSelection(false)
 {
   myIsInitialized = myRef.isInitialized();
-  myParent = NULL;
 }
 
 void Model_AttributeSelection::setID(const std::string theID)
index 94903c205b044a660676fc5b2cc9ae43219adca8..505b77f3647d91ff9dab7230d1fbf16bd047766f 100644 (file)
@@ -75,7 +75,6 @@
 #include <OSD_Protection.hxx>
 
 #ifdef TINSPECTOR
-#include <CDF_Session.hxx>
 #include <CDF_Directory.hxx>
 #endif
 
@@ -117,7 +116,7 @@ Model_Document::Model_Document(const int theID, const std::string theKind)
       myIsSetCurrentFeature(false)
 {
 #ifdef TINSPECTOR
-  CDF_Session::CurrentSession()->Directory()->Add(myDoc);
+  ModelAPI_Session::get()->application()->NewDocument("BinOcaf", myDoc);
 #endif
   myObjs = new Model_Objects(myDoc->Main());
   myDoc->SetUndoLimit(UNDO_LIMIT);
index af47051239a97eb6bb5ffe347717bdf849e7b2af..218659d5a887dc4c5734fa32ad4eaf9435df82e3 100644 (file)
 #include <Events_Listener.h>
 #include <map>
 
+#ifdef TINSPECTOR
+#include "Model_Application.h"
+#endif
+
 class Model_Document;
 
 /**\class Model_Session
@@ -155,6 +159,12 @@ class Model_Session : public ModelAPI_Session, public Events_Listener
   /// Set state of the auto-update of features result in the application
   MODEL_EXPORT virtual void blockAutoUpdate(const bool theBlock);
 
+#ifdef TINSPECTOR
+  MODEL_EXPORT virtual Handle(TDocStd_Application) application() {
+    return Model_Application::getApplication();
+  }
+#endif
+
  protected:
   /// Loads (if not done yet) the information about the features and plugins
   void LoadPluginsInfo();
index c6a298461b7dcd1b40c05f563a50ef25f1c8ec99..d2d565eee5fcf6aede037889cb2cbc3906c8c5de 100644 (file)
@@ -122,6 +122,10 @@ SET(PROJECT_LIBRARIES
 SET(CMAKE_SWIG_FLAGS -threads -w325,321,362,383,302,403,451,473)
 ADD_DEFINITIONS(-DMODELAPI_EXPORTS)
 
+IF(TKTInspector)
+    ADD_DEFINITIONS(-DTINSPECTOR)
+ENDIF()
+
 ADD_LIBRARY(ModelAPI SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS})
 SET_TARGET_PROPERTIES(ModelAPI PROPERTIES LINKER_LANGUAGE CXX)
 TARGET_LINK_LIBRARIES(ModelAPI ${PROJECT_LIBRARIES})
@@ -131,6 +135,7 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Config
                     ${PROJECT_SOURCE_DIR}/src/GeomAPI
                     ${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI
                     ${PROJECT_SOURCE_DIR}/src/Locale
+                    ${OpenCASCADE_INCLUDE_DIR}
 )
 
 
index e5db16f7588b7e511549161dd7ac2a33ae5f8dad..339263fb0f0ceccd48008f63fdf2829226396c6f 100644 (file)
 #include <list>
 #include <memory>
 
+#ifdef TINSPECTOR
+#include <Standard_Handle.hxx>
+#include <TDocStd_Application.hxx>
+#endif
+
 class ModelAPI_Feature;
 class ModelAPI_Plugin;
 class ModelAPI_Document;
@@ -138,6 +143,10 @@ class MODELAPI_EXPORT ModelAPI_Session
   /// Set state of the auto-update of features result in the application
   virtual void blockAutoUpdate(const bool theBlock) = 0;
 
+#ifdef TINSPECTOR
+  virtual Handle(TDocStd_Application) application() = 0;
+#endif
+
  protected:
   /// Sets the session interface implementation (once per application launch)
   static void setSession(std::shared_ptr<ModelAPI_Session> theManager);
index b1b93d92e85e5d09f8940521e5967a7c5f829898..3ad8e06e48ba1ec2274f4237ebee0fe49327a0ec 100644 (file)
@@ -283,10 +283,6 @@ INCLUDE_DIRECTORIES(
     ${SUIT_INCLUDE}
 )
 
-IF(${HAVE_SALOME})
-  INCLUDE_DIRECTORIES(${SALOME_KERNEL_INCLUDE})
-ENDIF(${HAVE_SALOME})
-
 ADD_DEFINITIONS(-DMODULEBASE_EXPORTS ${OpenCASCADE_DEFINITIONS})
 ADD_LIBRARY(ModuleBase SHARED
        ${PROJECT_SOURCES}
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);
   }
index 6bfdb34a5fb3773fa4d793bb6649c7ad3d02b48e..ebc905b4251303ca0ec6c2422c2e55bbdd14cb42 100644 (file)
@@ -183,11 +183,9 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/XGUI
                     ${SUIT_INCLUDE}
 )
 
-IF(${HAVE_SALOME})
-  INCLUDE_DIRECTORIES(${SALOME_KERNEL_INCLUDE})
-ELSE(${HAVE_SALOME})
+IF(NOT ${HAVE_SALOME})
   INCLUDE_DIRECTORIES(${APPELEMENTS_INCLUDE_DIR})
-ENDIF(${HAVE_SALOME})
+ENDIF()
 
 ADD_DEFINITIONS(-DPARTSET_EXPORTS ${OpenCASCADE_DEFINITIONS})
 ADD_LIBRARY(PartSet SHARED
index c1ee1a6f0f611a10d9f3aacec3b7913fa15d81a1..a3095a374c5735baed2d52c0136cd790d74e6518 100644 (file)
 
 #include <SelectMgr_ListIteratorOfListOfFilter.hxx>
 #include <Graphic3d_Texture2Dmanual.hxx>
-#include <OCCViewer_Utilities.h>
 
+#ifdef HAVE_SALOME
+#include <OCCViewer_Utilities.h>
+#endif
 
 #define FEATURE_ITEM_COLOR "0,0,225"
 
@@ -1406,6 +1408,7 @@ double getResultTransparency(const ResultPtr& theResult)
 //******************************************************
 void PartSet_Module::setTexture(const std::string & theTextureFile, const AISObjectPtr& thePrs)
 {
+#ifdef HAVE_SALOME
   Handle(AIS_InteractiveObject) anAIS = thePrs->impl<Handle(AIS_InteractiveObject)>();
   if (!anAIS.IsNull())
   {
@@ -1438,6 +1441,7 @@ void PartSet_Module::setTexture(const std::string & theTextureFile, const AISObj
       anAISShape->SetDisplayMode(AIS_Shaded);
     }
   }
+#endif
 }
 
 //******************************************************
index c31de74db858b9a89a2614d186da3205ada0b94a..7ea948ca0b6a360a7670b7dae6461d17b6866d07 100644 (file)
@@ -18,9 +18,8 @@
 #
 
 INSTALL(DIRECTORY geom model examples DESTINATION ${SHAPER_INSTALL_PYTHON_API})
-INSTALL(FILES __init__.py DESTINATION ${SHAPER_INSTALL_PYTHON_API})
-#INSTALL(FILES __init__.py DESTINATION ${_pydir}/salome)
 INSTALL(FILES initConfig.py DESTINATION ${SHAPER_INSTALL_PYTHON_API})
+SALOME_CONFIGURE_FILE(__init__.py __init__.py INSTALL ${SHAPER_INSTALL_PYTHON_API})
 
 # --------- Unit tests -----------
 INCLUDE(UnitTest)
index 5cd38a6135d95ab8a37d4236081536a7b354e833..1032880556f75355229f662fd471b4030da04d45 100644 (file)
@@ -16,3 +16,5 @@
 #
 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 #
+
+__version__ = "@SHAPER_GIT_SHA1@"
index c54f62f8369306a0691a74681fb520c0cdb9e94a..99078ef8ddd69dcf4bce9e7bd9740ead076a951f 100644 (file)
@@ -105,15 +105,10 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/XGUI
                     ${PROJECT_SOURCE_DIR}/src/GeomAPI
                     ${PROJECT_SOURCE_DIR}/src/Config
                     ${PROJECT_SOURCE_DIR}/src/ExchangePlugin
-                    ${SALOME_GUI_INCLUDE}
-                    ${SALOME_KERNEL_INCLUDE}
+                    ${SUIT_INCLUDE}
                     ${OpenCASCADE_INCLUDE_DIR}
 )
 
-IF(${HAVE_SALOME})
-  INCLUDE_DIRECTORIES(${SALOME_KERNEL_INCLUDE})
-ENDIF(${HAVE_SALOME})
-
 ADD_LIBRARY(SHAPER SHARED
     ${PROJECT_SOURCES}
     ${PROJECT_HEADERS}
index 2d93bce21e3fa1adee474e97e50780a99830a14b..14f9b291b382a4c13dce5ab33d255c29010cb72f 100644 (file)
@@ -207,10 +207,6 @@ SET(PROJECT_INCLUDES
     ${OpenCASCADE_INCLUDE_DIR}
     ${SUIT_INCLUDE})
 
-IF(${HAVE_SALOME})
-  INCLUDE_DIRECTORIES(${SALOME_KERNEL_INCLUDE})
-ENDIF(${HAVE_SALOME})
-
 IF(NOT ${HAVE_SALOME})
     SET(PROJECT_INCLUDES ${PROJECT_INCLUDES} ${APPELEMENTS_INCLUDE_DIR})
 ENDIF(NOT ${HAVE_SALOME})
index 58092f3bfa585dac324edf0c93aa96173599c6b6..523bdd94f981c2f878749061348bc0390ebe3d2a 100644 (file)
@@ -404,9 +404,9 @@ void XGUI_InspectionPanel::fillEdge(const GeomEdgePtr& theEdge)
     if (aCircle) {
       addStartEndPoints = aStartPnt->distance(aEndPnt) >= Precision::Confusion();
       if (addStartEndPoints)
-        myTypeLbl->setText("Arc of circle");
+        myTypeLbl->setText(tr("Arc of circle"));
       else
-        myTypeLbl->setText("Circle");
+        myTypeLbl->setText(tr("Circle"));
 
       appendPointToParameters(tr("Center"), aCircle->center(), aParams);
       appendDirToParameters(tr("Normal"), aCircle->normal(), aParams);
@@ -418,9 +418,9 @@ void XGUI_InspectionPanel::fillEdge(const GeomEdgePtr& theEdge)
       if (anEllipse) {
         addStartEndPoints = aStartPnt->distance(aEndPnt) >= Precision::Confusion();
         if (addStartEndPoints)
-          myTypeLbl->setText("Arc of ellipse");
+          myTypeLbl->setText(tr("Arc of ellipse"));
         else
-          myTypeLbl->setText("Ellipse");
+          myTypeLbl->setText(tr("Ellipse"));
 
         appendPointToParameters(tr("Center"), anEllipse->center(), aParams);
         appendDirToParameters(tr("Normal"), anEllipse->normal(), aParams);
@@ -478,6 +478,7 @@ void XGUI_InspectionPanel::fillFace(const GeomFacePtr& theFace)
       if (anEdge->isCircle() || anEdge->isEllipse()) {
         fillEdge(anEdge);
         isCommonCase = false;
+        myTypeLbl->setText(tr("Disk"));
       }
     }
     else {
index 01b2fff9959dfcac486202faf9db041d19480b41..4342023ae4653ec085b1b1636606393714314c04 100644 (file)
 #include <iterator>
 
 #ifdef TINSPECTOR
-#include <CDF_Session.hxx>
-#include <CDF_Application.hxx>
+#include <TDocStd_Application.hxx>
 #include <inspector/TInspector_Communicator.hxx>
 #include <inspector/VInspector_CallBack.hxx>
 static TInspector_Communicator* MyTCommunicator;
 static Handle(VInspector_CallBack) MyVCallBack;
-
 #endif
 
 #ifdef _DEBUG
@@ -681,6 +679,7 @@ void XGUI_Workshop::showHelpPage(const QString& thePage) const
 #endif
     QString aFileName = aDocDir + aSep + thePage;
     if (QFile::exists(aFileName)) {
+#ifdef HAVE_SALOME
       SUIT_Application* app = SUIT_Session::session()->activeApplication();
       if (app)
         app->onHelpContextModule("SHAPER", aFileName);
@@ -688,6 +687,10 @@ void XGUI_Workshop::showHelpPage(const QString& thePage) const
         QUrl aUrl = QUrl::fromLocalFile(aFileName);
         QDesktopServices::openUrl(aUrl);
       }
+#else
+      QUrl aUrl = QUrl::fromLocalFile(aFileName);
+      QDesktopServices::openUrl(aUrl);
+#endif
     }
   }
 }
@@ -1822,7 +1825,7 @@ void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked)
   }
 #ifdef TINSPECTOR
   else if (theId == "TINSPECTOR_VIEW") {
-    Handle(CDF_Application) anApplication = CDF_Session::CurrentSession()->CurrentApplication();
+    Handle(TDocStd_Application) anApplication = ModelAPI_Session::get()->application();
     if (!anApplication.IsNull())
     {
       if (!MyTCommunicator)
index 39d6ef572843f67340ff41dfd84a40e5a263c479..42c57b1a60fd525389235fcef4e85463413b8447 100644 (file)
         <source>Line segment</source>
         <translation>Segment de ligne</translation>
     </message>
+    <message>
+        <source>Arc of circle</source>
+        <translation>Arc de cercle</translation>
+    </message>
+    <message>
+        <source>Circle</source>
+        <translation>Cercle</translation>
+    </message>
+    <message>
+        <source>Disk</source>
+        <translation>Disque</translation>
+    </message>
     <message>
         <source>Center</source>
         <translation>Centre</translation>
         <source>Radius</source>
         <translation>Rayon</translation>
     </message>
+    <message>
+        <source>Arc of ellipse</source>
+        <translation>Arc d'ellipse</translation>
+    </message>
     <message>
         <source>Major radius</source>
         <translation>Rayon principal</translation>
index a049e5d4d22d36abcee67e75bfb50f21e3c021b1..814ab2ee842b52aa36ed5227a54f71708f897ec1 100644 (file)
@@ -31,6 +31,5 @@ if(${HAVE_SALOME})
   DESTINATION ${TEST_INSTALL_DIRECTORY}
   RENAME CTestTestfile.cmake)
   install(FILES tests.set DESTINATION ${TEST_INSTALL_DIRECTORY})
-  message(${TEST_NAMES})
   install(FILES ${TEST_NAMES} DESTINATION ${TEST_INSTALL_DIRECTORY})
 endif(${HAVE_SALOME})