From 3e573a0137c66c2463f81db99f6e18a4e53bcafe Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me?= Date: Mon, 2 Nov 2020 15:01:08 +0100 Subject: [PATCH] Integration : { Integrated by : Nicolas RECHATIN } { Code from : Jerome LUCAS } + Implementation of Filters "Edge size", "Face size" and "Volume Size" + Add Filter Feature Edge and Continuous Faces + Documentation error + Units tests for filter Edge Size and Face Size + Add test for "feature Edges" + Add test "Continuous face" filters, traduction + Add precision in geom_validator for zero value. + Add test for filter VolumeSize + Copyright update --- src/FiltersAPI/FiltersAPI.i | 19 +- src/FiltersAPI/FiltersAPI_Argument.cpp | 19 +- src/FiltersAPI/FiltersAPI_Argument.h | 10 +- src/FiltersAPI/FiltersAPI_Feature.cpp | 26 ++- src/FiltersAPI/FiltersAPI_Filter.cpp | 8 + src/FiltersPlugin/CMakeLists.txt | 22 +- .../FiltersPlugin_ContinuousFaces.cpp | 195 ++++++++++++++++++ .../FiltersPlugin_ContinuousFaces.h | 73 +++++++ src/FiltersPlugin/FiltersPlugin_EdgeSize.cpp | 111 ++++++++++ src/FiltersPlugin/FiltersPlugin_EdgeSize.h | 60 ++++++ src/FiltersPlugin/FiltersPlugin_FaceSize.cpp | 110 ++++++++++ src/FiltersPlugin/FiltersPlugin_FaceSize.h | 61 ++++++ .../FiltersPlugin_FeatureEdges.cpp | 142 +++++++++++++ .../FiltersPlugin_FeatureEdges.h | 73 +++++++ src/FiltersPlugin/FiltersPlugin_Plugin.cpp | 10 + .../FiltersPlugin_VolumeSize.cpp | 110 ++++++++++ src/FiltersPlugin/FiltersPlugin_VolumeSize.h | 61 ++++++ src/FiltersPlugin/FiltersPlugin_msg_fr.ts | 94 +++++++++ .../Test/TestFilter_ContinuousFaces.py | 87 ++++++++ src/FiltersPlugin/Test/TestFilter_EdgeSize.py | 170 +++++++++++++++ src/FiltersPlugin/Test/TestFilter_FaceSize.py | 142 +++++++++++++ .../Test/TestFilter_FeatureEdges.py | 124 +++++++++++ .../Test/TestFilter_VolumeSize.py | 159 ++++++++++++++ .../Test/TestFilters_Supported.py | 11 +- src/FiltersPlugin/doc/FiltersPlugin.rst | 43 ++++ src/FiltersPlugin/filter-ContinuousFaces.xml | 14 ++ src/FiltersPlugin/filter-EdgeSize.xml | 72 +++++++ src/FiltersPlugin/filter-FaceSize.xml | 71 +++++++ src/FiltersPlugin/filter-FeatureEdges.xml | 8 + src/FiltersPlugin/filter-VolumeSize.xml | 71 +++++++ src/FiltersPlugin/tests.set | 5 + src/GeomAlgoAPI/CMakeLists.txt | 4 + .../GeomAlgoAPI_BasicProperties.cpp | 75 +++++++ src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.h | 42 ++++ .../GeomAlgoAPI_ContinuousFaces.cpp | 132 ++++++++++++ src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.h | 42 ++++ .../GeomValidators_Positive.cpp | 2 +- .../ModuleBase_WidgetSelectionFilter.cpp | 1 + 38 files changed, 2458 insertions(+), 21 deletions(-) create mode 100644 src/FiltersPlugin/FiltersPlugin_ContinuousFaces.cpp create mode 100644 src/FiltersPlugin/FiltersPlugin_ContinuousFaces.h create mode 100644 src/FiltersPlugin/FiltersPlugin_EdgeSize.cpp create mode 100644 src/FiltersPlugin/FiltersPlugin_EdgeSize.h create mode 100644 src/FiltersPlugin/FiltersPlugin_FaceSize.cpp create mode 100644 src/FiltersPlugin/FiltersPlugin_FaceSize.h create mode 100644 src/FiltersPlugin/FiltersPlugin_FeatureEdges.cpp create mode 100644 src/FiltersPlugin/FiltersPlugin_FeatureEdges.h create mode 100644 src/FiltersPlugin/FiltersPlugin_VolumeSize.cpp create mode 100644 src/FiltersPlugin/FiltersPlugin_VolumeSize.h create mode 100644 src/FiltersPlugin/Test/TestFilter_ContinuousFaces.py create mode 100644 src/FiltersPlugin/Test/TestFilter_EdgeSize.py create mode 100644 src/FiltersPlugin/Test/TestFilter_FaceSize.py create mode 100644 src/FiltersPlugin/Test/TestFilter_FeatureEdges.py create mode 100644 src/FiltersPlugin/Test/TestFilter_VolumeSize.py create mode 100644 src/FiltersPlugin/filter-ContinuousFaces.xml create mode 100644 src/FiltersPlugin/filter-EdgeSize.xml create mode 100644 src/FiltersPlugin/filter-FaceSize.xml create mode 100644 src/FiltersPlugin/filter-FeatureEdges.xml create mode 100644 src/FiltersPlugin/filter-VolumeSize.xml create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.cpp create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.h create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.cpp create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.h diff --git a/src/FiltersAPI/FiltersAPI.i b/src/FiltersAPI/FiltersAPI.i index 76bcad128..99e680515 100644 --- a/src/FiltersAPI/FiltersAPI.i +++ b/src/FiltersAPI/FiltersAPI.i @@ -45,6 +45,8 @@ %shared_ptr(FiltersAPI_Feature) %shared_ptr(FiltersAPI_Filter) +%shared_ptr(ModelHighAPI_Interface) + // function with named parameters %feature("kwargs") addFilter; @@ -73,7 +75,10 @@ if (!temp_string) { $1 = 0; } - } else + }else + if (!PyFloat_Check(item) && PyLong_Check(item)) + $1 = 0; + else if (!PyUnicode_Check(item) && !PyBool_Check(item)) $1 = 0; } @@ -83,13 +88,14 @@ %typemap(in) const std::list & (std::list 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)); @@ -99,7 +105,7 @@ } 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)); @@ -112,15 +118,18 @@ } 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; } } diff --git a/src/FiltersAPI/FiltersAPI_Argument.cpp b/src/FiltersAPI/FiltersAPI_Argument.cpp index 30d5e36cd..8cc6880bd 100644 --- a/src/FiltersAPI/FiltersAPI_Argument.cpp +++ b/src/FiltersAPI/FiltersAPI_Argument.cpp @@ -28,6 +28,16 @@ FiltersAPI_Argument::FiltersAPI_Argument(const bool theValue) { } +FiltersAPI_Argument::FiltersAPI_Argument(const ModelHighAPI_Double theValue) + : myDouble(theValue) +{ +} + +FiltersAPI_Argument::FiltersAPI_Argument(const double& theValue) +{ + myDouble = theValue; +} + FiltersAPI_Argument::FiltersAPI_Argument(const std::string& theValue) : myValue(theValue) { @@ -54,9 +64,14 @@ void FiltersAPI_Argument::dump(ModelHighAPI_Dumper& theDumper) const theDumper << "model.selection()"; // mySelectionAttr; } else if (mySelection.variantType() == ModelHighAPI_Selection::VT_Empty) { - if (myValue.empty()) + if (myDouble.value() > -100000000000 ){ + theDumper << myDouble.value(); + } + else if (myValue.empty()){ theDumper << myBoolean; - else + } + else{ theDumper << "\"" << myValue << "\""; + } } } diff --git a/src/FiltersAPI/FiltersAPI_Argument.h b/src/FiltersAPI/FiltersAPI_Argument.h index 7b7cd30ff..050bacd14 100644 --- a/src/FiltersAPI/FiltersAPI_Argument.h +++ b/src/FiltersAPI/FiltersAPI_Argument.h @@ -23,6 +23,7 @@ #include "FiltersAPI.h" #include +#include #include #include @@ -39,6 +40,12 @@ public: FILTERSAPI_EXPORT FiltersAPI_Argument(const bool theValue); + FILTERSAPI_EXPORT + FiltersAPI_Argument(const ModelHighAPI_Double theValue); + + FILTERSAPI_EXPORT + FiltersAPI_Argument(const double& theValue); + FILTERSAPI_EXPORT FiltersAPI_Argument(const std::string& theValue); @@ -55,13 +62,14 @@ public: const bool boolean() const { return myBoolean; } const std::string& string() const { return myValue; } const ModelHighAPI_Selection& selection() const { return mySelection; } - + const ModelHighAPI_Double& dble() const { return myDouble; } /// Dump wrapped feature FILTERSAPI_EXPORT void dump(ModelHighAPI_Dumper& theDumper) const; private: bool myBoolean; + ModelHighAPI_Double myDouble = -100000000000; std::string myValue; ModelHighAPI_Selection mySelection; AttributeSelectionPtr mySelectionAttr; diff --git a/src/FiltersAPI/FiltersAPI_Feature.cpp b/src/FiltersAPI/FiltersAPI_Feature.cpp index 215b2ef12..9a24140f4 100644 --- a/src/FiltersAPI/FiltersAPI_Feature.cpp +++ b/src/FiltersAPI/FiltersAPI_Feature.cpp @@ -41,14 +41,19 @@ FiltersAPI_Feature::~FiltersAPI_Feature() static void separateArguments(const std::list& theArguments, std::list& theSelections, std::list& theTextArgs, - std::list& theBoolArgs) + std::list& theBoolArgs, + std::list& theDoubleArgs) { std::list::const_iterator anIt = theArguments.begin(); for (; anIt != theArguments.end(); ++anIt) { if (anIt->selection().variantType() != ModelHighAPI_Selection::VT_Empty) theSelections.push_back(anIt->selection()); - else if (anIt->string().empty()) + else if (anIt->dble().value() > -100000000000) { + theDoubleArgs.push_back(anIt->dble()); + } + else if (anIt->string().empty()){ theBoolArgs.push_back(anIt->boolean()); + } else theTextArgs.push_back(anIt->string()); } @@ -68,7 +73,8 @@ void FiltersAPI_Feature::setFilters(const std::list& theFilters) std::list aSelections; std::list aTexts; std::list aBools; - separateArguments(anArgs, aSelections, aTexts, aBools); + std::list aDoubles; + separateArguments(anArgs, aSelections, aTexts, aBools, aDoubles); std::list aFilterArgs = aBase->filterArgs(aFilterID); std::list::iterator aFIt = aFilterArgs.begin(); @@ -78,6 +84,7 @@ void FiltersAPI_Feature::setFilters(const std::list& theFilters) if (aReversedFlag) ++aFIt; // fill arguments of the filter + std::list::const_iterator anItDle = aDoubles.begin(); for (; aFIt != aFilterArgs.end(); ++aFIt) { AttributeSelectionListPtr aSelList = std::dynamic_pointer_cast(*aFIt); @@ -98,8 +105,17 @@ void FiltersAPI_Feature::setFilters(const std::list& theFilters) else { AttributeBooleanPtr aBoolean = std::dynamic_pointer_cast(*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(*aFIt); + if (aDouble) { + fillAttribute((*anItDle).value(), aDouble); + anItDle++; + } + } } } } diff --git a/src/FiltersAPI/FiltersAPI_Filter.cpp b/src/FiltersAPI/FiltersAPI_Filter.cpp index 5ae1afb02..37d7881e6 100644 --- a/src/FiltersAPI/FiltersAPI_Filter.cpp +++ b/src/FiltersAPI/FiltersAPI_Filter.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -72,11 +73,18 @@ FiltersAPI_Filter::FiltersAPI_Filter(const std::string& theName, continue; } + AttributeDoublePtr aDouble = std::dynamic_pointer_cast(*anArgIt); + if (aDouble) { + myFilterArguments.push_back(FiltersAPI_Argument(aDouble->value())); + continue; + } + AttributeBooleanPtr aBoolean = std::dynamic_pointer_cast(*anArgIt); if (aBoolean) { myFilterArguments.push_back(FiltersAPI_Argument(aBoolean->value())); continue; } + } } diff --git a/src/FiltersPlugin/CMakeLists.txt b/src/FiltersPlugin/CMakeLists.txt index 7b77d8466..f32f2047d 100644 --- a/src/FiltersPlugin/CMakeLists.txt +++ b/src/FiltersPlugin/CMakeLists.txt @@ -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 index 000000000..0ab82ea2c --- /dev/null +++ b/src/FiltersPlugin/FiltersPlugin_ContinuousFaces.cpp @@ -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 +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +typedef std::map MapShapeAndAncestors; + +//================================================================================================= +static void mapEdgesAndFaces(const GeomShapePtr theShape, MapShapeAndAncestors& theMap) +{ + GeomAPI_ShapeExplorer aFExp(theShape, GeomAPI_Shape::FACE); + for (; aFExp.more(); aFExp.next()) { + GeomShapePtr aFace = aFExp.current(); + GeomAPI_ShapeExplorer aEExp(aFace, GeomAPI_Shape::EDGE); + for (; aEExp.more(); aEExp.next()) + theMap[aEExp.current()].insert(aFace); + } +} + +//================================================================================================= +// Find all continuous faces for the given. +static void cacheContinuousFace(const GeomShapePtr theFace, + const MapShapeAndAncestors& theEdgeToFaces, + SetOfShapes& theCache, + const double & theAngle) +{ + + MapShapeAndAncestors::const_iterator aFound; + GeomAPI_ShapeExplorer aEExp(theFace, GeomAPI_Shape::EDGE); + for (; aEExp.more(); aEExp.next()){ + aFound = theEdgeToFaces.find(aEExp.current()); + if (aFound == theEdgeToFaces.end()) + continue; + + GeomEdgePtr anEdge; + anEdge = GeomEdgePtr(new GeomAPI_Edge(aEExp.current())); + + for (SetOfShapes::const_iterator aFIt = aFound->second.begin(); + aFIt != aFound->second.end(); ++aFIt) { + std::string anError = ""; + if (theCache.find(*aFIt) == theCache.end()) { + GeomPointPtr aPoint = anEdge->middlePoint(); + if (isContinuousFaces(theFace, + *aFIt, + aPoint, + theAngle, + anError)) { + theCache.insert(*aFIt); + cacheContinuousFace(*aFIt, theEdgeToFaces, theCache, theAngle); + } + } + } + } +} + +//================================================================================================= +static void cacheContinuousFaces(const GeomShapePtr theTopLevelShape, + const SetOfShapes& theFaces, + SetOfShapes& theCache, + const double & theAngle) +{ + if (!theTopLevelShape || theFaces.empty()) + return; + + MapShapeAndAncestors anEdgesToFaces; + mapEdgesAndFaces(theTopLevelShape, anEdgesToFaces); + + for (SetOfShapes::const_iterator aFIt = theFaces.begin(); + aFIt != theFaces.end(); ++aFIt) { + // keep the original face + theCache.insert(*aFIt); + // cache continuous face + cacheContinuousFace(*aFIt, anEdgesToFaces, theCache,theAngle); + } +} + +//================================================================================================= +static bool updateFaces(const AttributeSelectionListPtr& theList, + SetOfShapes& theFaces) +{ + bool aNewCache = false; + if (theFaces.size() != theList->size()) { + aNewCache = true; + } else { + for (int i = 0; i < theList->size(); i++) { + AttributeSelectionPtr aCurAttr = theList->value(i); + GeomShapePtr aFace = aCurAttr->value(); + if (theFaces.empty() || theFaces.find(aFace) == theFaces.end()) { + aNewCache = true; + break; + } + } + } + if (aNewCache) { + theFaces.clear(); + for (int i = 0; i < theList->size(); i++) { + AttributeSelectionPtr aCurAttr = theList->value(i); + GeomShapePtr aFace = aCurAttr->value(); + theFaces.insert(aFace); + } + } + return aNewCache; +} + +//================================================================================================= +bool FiltersPlugin_ContinuousFaces::isSupported(GeomAPI_Shape::ShapeType theType) const +{ + return theType == GeomAPI_Shape::FACE; +} + +//================================================================================================= +bool FiltersPlugin_ContinuousFaces::isOk(const GeomShapePtr& theShape, const ResultPtr&, + const ModelAPI_FiltersArgs& theArgs) const +{ + AttributePtr aAttr = theArgs.argument("faces"); + AttributeSelectionListPtr aList = + std::dynamic_pointer_cast(aAttr); + if (!aList.get()) + return false; + + AttributePtr anAttr = theArgs.argument("value"); + AttributeDoublePtr aValue = std::dynamic_pointer_cast(anAttr); + if (!aValue.get()|| !anAttr->isInitialized()) + return false; + double anAngle= aValue->value(); + + bool aNewCache = updateFaces(aList, + const_cast(this)->myFaces); + + if (aNewCache || fabs(myAngle - anAngle) > 1e-10 ) { + const_cast(this)->myAngle = anAngle; + const_cast(this)->myCachedShapes.clear(); + } + + if (myCachedShapes.empty()) { + ResultBodyPtr aBaseResult = ModelAPI_Tools::bodyOwner(aList->value(0)->context(), true); + if (!aBaseResult.get()) { + aBaseResult = std::dynamic_pointer_cast(aList->value(0)->context()); + if (!aBaseResult.get()) + return false; + } + cacheContinuousFaces(aBaseResult->shape(), + const_cast(this)->myFaces, + const_cast(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 index 000000000..386b2de17 --- /dev/null +++ b/src/FiltersPlugin/FiltersPlugin_ContinuousFaces.h @@ -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 +#include + +#include + +typedef std::set 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 index 000000000..a5b6ff8fb --- /dev/null +++ b/src/FiltersPlugin/FiltersPlugin_EdgeSize.cpp @@ -0,0 +1,111 @@ +// Copyright (C) 2014-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "FiltersPlugin_EdgeSize.h" + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + + +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(anAttr); + if (!aValue.get()|| !anAttr->isInitialized() ) + return false; + double aVal = aValue->value(); + + anAttr = theArgs.argument("valueMax"); + aValue = std::dynamic_pointer_cast(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(anAttr); + if (!aCompAttr) + return false; + std::string aCompString = aCompAttr->value(); + + bool isOK = false; + if (aCompString == "inf") + isOK = aLength < aVal && fabs(aLength - aVal) > Precision::Confusion(); + else if (aCompString == "infEq") + isOK = aLength < aVal || fabs(aLength - aVal) < Precision::Confusion(); + else if (aCompString == "sup") + isOK = aLength > aVal && fabs(aLength - aVal) > Precision::Confusion(); + else if (aCompString == "supEq") + isOK = aLength > aVal || fabs(aLength - aVal) < Precision::Confusion(); + else if (aCompString == "isBetween") + isOK = (aLength > aVal || fabs(aLength - aVal) < Precision::Confusion()) + && (aLength < aValMax || fabs(aLength - aVal) < Precision::Confusion()); + else if (aCompString == "isStrictlyBetween") + isOK = (aLength > aVal && fabs(aLength - aVal) > Precision::Confusion()) + && (aLength < aValMax && fabs(aLength - aValMax) > Precision::Confusion()); + return isOK; +} + +std::string FiltersPlugin_EdgeSize::xmlRepresentation() const +{ + return xmlFromFile("filter-EdgeSize.xml"); +} + +void FiltersPlugin_EdgeSize::initAttributes(ModelAPI_FiltersArgs& theArguments) +{ + theArguments.initAttribute("comparatorType", ModelAPI_AttributeString::typeId()); + theArguments.initAttribute("value", ModelAPI_AttributeDouble::typeId()); + theArguments.initAttribute("valueMax", ModelAPI_AttributeDouble::typeId()); +} + diff --git a/src/FiltersPlugin/FiltersPlugin_EdgeSize.h b/src/FiltersPlugin/FiltersPlugin_EdgeSize.h new file mode 100644 index 000000000..fc53fec9a --- /dev/null +++ b/src/FiltersPlugin/FiltersPlugin_EdgeSize.h @@ -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 +#include + +/**\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 index 000000000..52633b834 --- /dev/null +++ b/src/FiltersPlugin/FiltersPlugin_FaceSize.cpp @@ -0,0 +1,110 @@ +// Copyright (C) 2014-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "FiltersPlugin_FaceSize.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + + +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(anAttr); + if (!aValue.get()|| !anAttr->isInitialized() ) + return false; + double aVal = aValue->value(); + + anAttr = theArgs.argument("valueMax"); + aValue = std::dynamic_pointer_cast(anAttr); + if (!aValue.get()|| !anAttr->isInitialized() ) + return false; + double aValMax = aValue->value(); + + if (aVal < 0.0) + return false; + + double aTolerance = 0.0001; + double aLength; + double aSurfArea; + double aVolume; + std::string aError; + if( !GetBasicProperties(theShape, + aTolerance, + aLength, + aSurfArea, + aVolume, + aError) ) + return false; + + anAttr = theArgs.argument("comparatorType"); + AttributeStringPtr aCompAttr = std::dynamic_pointer_cast(anAttr); + if (!aCompAttr) + return false; + std::string aCompString = aCompAttr->value(); + + bool isOK = false; + if (aCompString == "inf") + isOK = aSurfArea < aVal && fabs(aSurfArea - aVal) > Precision::Confusion(); + else if (aCompString == "infEq") + isOK = aSurfArea < aVal || fabs(aSurfArea - aVal) < Precision::Confusion(); + else if (aCompString == "sup") + isOK = aSurfArea > aVal && fabs(aSurfArea - aVal) > Precision::Confusion(); + else if (aCompString == "supEq") + isOK = aSurfArea > aVal || fabs(aSurfArea - aVal) < Precision::Confusion(); + else if (aCompString == "isBetween") + isOK = (aSurfArea > aVal || fabs(aSurfArea - aVal) < Precision::Confusion()) + && (aSurfArea < aValMax || fabs(aSurfArea - aVal) < Precision::Confusion()); + else if (aCompString == "isStrictlyBetween") + isOK = (aSurfArea > aVal && fabs(aSurfArea - aVal) > Precision::Confusion()) + && (aSurfArea < aValMax && fabs(aSurfArea - aValMax) > Precision::Confusion()); + return isOK; +} + +std::string FiltersPlugin_FaceSize::xmlRepresentation() const +{ + return xmlFromFile("filter-FaceSize.xml"); +} + +void FiltersPlugin_FaceSize::initAttributes(ModelAPI_FiltersArgs& theArguments) +{ + theArguments.initAttribute("comparatorType", ModelAPI_AttributeString::typeId()); + theArguments.initAttribute("value", ModelAPI_AttributeDouble::typeId()); + theArguments.initAttribute("valueMax", ModelAPI_AttributeDouble::typeId()); +} + diff --git a/src/FiltersPlugin/FiltersPlugin_FaceSize.h b/src/FiltersPlugin/FiltersPlugin_FaceSize.h new file mode 100644 index 000000000..588e7452e --- /dev/null +++ b/src/FiltersPlugin/FiltersPlugin_FaceSize.h @@ -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 +#include + + +/**\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 index 000000000..79dd0aa65 --- /dev/null +++ b/src/FiltersPlugin/FiltersPlugin_FeatureEdges.cpp @@ -0,0 +1,142 @@ +// Copyright (C) 2014-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "FiltersPlugin_FeatureEdges.h" + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +typedef std::map MapShapeAndAncestors; + +//================================================================================================= +static void mapEdgesAndFaces(const GeomShapePtr theShape, MapShapeAndAncestors& theMap) +{ + GeomAPI_ShapeExplorer aFExp(theShape, GeomAPI_Shape::FACE); + for (; aFExp.more(); aFExp.next()) { + GeomShapePtr aFace = aFExp.current(); + GeomAPI_ShapeExplorer aEExp(aFace, GeomAPI_Shape::EDGE); + for (; aEExp.more(); aEExp.next()) + theMap[aEExp.current()].insert(aFace); + } +} + +//================================================================================================= +static void cacheFeatureEdge(const GeomShapePtr theTopLevelShape, + SetOfShapes& theCache, + const double & theAngle) +{ + if (!theTopLevelShape) + return; + + MapShapeAndAncestors anEdgesToFaces; + mapEdgesAndFaces(theTopLevelShape, anEdgesToFaces); + + MapShapeAndAncestors::const_iterator aIt; + for (aIt = anEdgesToFaces.begin(); aIt != anEdgesToFaces.end(); ++aIt) { + GeomEdgePtr anEdge; + anEdge = GeomEdgePtr(new GeomAPI_Edge(aIt->first)); + + for (SetOfShapes::const_iterator aFIt = aIt->second.begin(); + aFIt != aIt->second.end(); ++aFIt) { + SetOfShapes::const_iterator aFIt2 = aFIt; + ++aFIt2; + for (;aFIt2 != aIt->second.end(); ++aFIt2) { + std::string anError; + if (theCache.find(*aFIt) == theCache.end()) { + if (!isContinuousFaces(*aFIt, + *aFIt2, + anEdge->middlePoint(), + theAngle, + anError)) { + if( anError.empty()) + theCache.insert(anEdge); + } + } + } + } + } +} + +//================================================================================================= +bool FiltersPlugin_FeatureEdges::isSupported(GeomAPI_Shape::ShapeType theType) const +{ + return theType == GeomAPI_Shape::EDGE; +} + +//================================================================================================= +bool FiltersPlugin_FeatureEdges::isOk(const GeomShapePtr& theShape, const ResultPtr& theResult, + const ModelAPI_FiltersArgs& theArgs) const +{ + AttributePtr anAttr = theArgs.argument("value"); + AttributeDoublePtr aValue = std::dynamic_pointer_cast(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(theResult); + if (!aBaseResult.get()) { + return false; + } + } + if (fabs(myAngle - anAngle) > 1e-10 + || !myBaseShape + || !myBaseShape->isSame(aBaseResult->shape())) { + const_cast(this)->myAngle = anAngle; + const_cast(this)->myBaseShape = aBaseResult->shape(); + const_cast(this)->myCachedShapes.clear(); + } + + if (myCachedShapes.empty()) { + + cacheFeatureEdge(aBaseResult->shape(), + const_cast(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 index 000000000..536bfee6f --- /dev/null +++ b/src/FiltersPlugin/FiltersPlugin_FeatureEdges.h @@ -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 +#include + +#include + +typedef std::set 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 diff --git a/src/FiltersPlugin/FiltersPlugin_Plugin.cpp b/src/FiltersPlugin/FiltersPlugin_Plugin.cpp index db708db90..343cdd267 100644 --- a/src/FiltersPlugin/FiltersPlugin_Plugin.cpp +++ b/src/FiltersPlugin/FiltersPlugin_Plugin.cpp @@ -27,6 +27,11 @@ #include "FiltersPlugin_OnGeometry.h" #include "FiltersPlugin_OnPlaneSide.h" #include "FiltersPlugin_OppositeToEdge.h" +#include "FiltersPlugin_EdgeSize.h" +#include "FiltersPlugin_FaceSize.h" +#include "FiltersPlugin_FeatureEdges.h" +#include "FiltersPlugin_ContinuousFaces.h" +#include "FiltersPlugin_VolumeSize.h" #include "FiltersPlugin_RelativeToSolid.h" #include "FiltersPlugin_ExternalFaces.h" #include "FiltersPlugin_Validators.h" @@ -54,6 +59,11 @@ FiltersPlugin_Plugin::FiltersPlugin_Plugin() aFactory->registerFilter("OppositeToEdge", new FiltersPlugin_OppositeToEdge); aFactory->registerFilter("RelativeToSolid", new FiltersPlugin_RelativeToSolid); aFactory->registerFilter("ExternalFaces", new FiltersPlugin_ExternalFaces); + aFactory->registerFilter("EdgeSize", new FiltersPlugin_EdgeSize); + aFactory->registerFilter("FaceSize", new FiltersPlugin_FaceSize); + aFactory->registerFilter("VolumeSize", new FiltersPlugin_VolumeSize); + aFactory->registerFilter("FeatureEdges", new FiltersPlugin_FeatureEdges); + aFactory->registerFilter("ContinuousFaces", new FiltersPlugin_ContinuousFaces); Config_ModuleReader::loadScript("FiltersPlugin_TopoConnectedFaces"); diff --git a/src/FiltersPlugin/FiltersPlugin_VolumeSize.cpp b/src/FiltersPlugin/FiltersPlugin_VolumeSize.cpp new file mode 100644 index 000000000..c50b58d91 --- /dev/null +++ b/src/FiltersPlugin/FiltersPlugin_VolumeSize.cpp @@ -0,0 +1,110 @@ +// Copyright (C) 2014-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "FiltersPlugin_VolumeSize.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + + +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(anAttr); + if (!aValue.get()|| !anAttr->isInitialized() ) + return false; + double aVal = aValue->value(); + + anAttr = theArgs.argument("valueMax"); + aValue = std::dynamic_pointer_cast(anAttr); + if (!aValue.get()|| !anAttr->isInitialized() ) + return false; + double aValMax = aValue->value(); + + if (aVal < 0.0) + return false; + + double aTolerance = 0.0001; + double aLength; + double aSurfArea; + double aVolume; + std::string aError; + if( !GetBasicProperties(theShape, + aTolerance, + aLength, + aSurfArea, + aVolume, + aError) ) + return false; + + anAttr = theArgs.argument("comparatorType"); + AttributeStringPtr aCompAttr = std::dynamic_pointer_cast(anAttr); + if (!aCompAttr) + return false; + std::string aCompString = aCompAttr->value(); + + bool isOK = false; + if (aCompString == "inf") + isOK = aVolume < aVal && fabs(aVolume - aVal) > Precision::Confusion(); + else if (aCompString == "infEq") + isOK = aVolume < aVal || fabs(aVolume - aVal) < Precision::Confusion(); + else if (aCompString == "sup") + isOK = aVolume > aVal && fabs(aVolume - aVal) > Precision::Confusion(); + else if (aCompString == "supEq") + isOK = aVolume > aVal || fabs(aVolume - aVal) < Precision::Confusion(); + else if (aCompString == "isBetween") + isOK = (aVolume > aVal || fabs(aVolume - aVal) < Precision::Confusion()) + && (aVolume < aValMax || fabs(aVolume - aVal) < Precision::Confusion()); + else if (aCompString == "isStrictlyBetween") + isOK = (aVolume > aVal && fabs(aVolume - aVal) > Precision::Confusion()) + && (aVolume < aValMax && fabs(aVolume - aValMax) > Precision::Confusion()); + return isOK; +} + +std::string FiltersPlugin_VolumeSize::xmlRepresentation() const +{ + return xmlFromFile("filter-VolumeSize.xml"); +} + +void FiltersPlugin_VolumeSize::initAttributes(ModelAPI_FiltersArgs& theArguments) +{ + theArguments.initAttribute("comparatorType", ModelAPI_AttributeString::typeId()); + theArguments.initAttribute("value", ModelAPI_AttributeDouble::typeId()); + theArguments.initAttribute("valueMax", ModelAPI_AttributeDouble::typeId()); +} + diff --git a/src/FiltersPlugin/FiltersPlugin_VolumeSize.h b/src/FiltersPlugin/FiltersPlugin_VolumeSize.h new file mode 100644 index 000000000..1dfbf13db --- /dev/null +++ b/src/FiltersPlugin/FiltersPlugin_VolumeSize.h @@ -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 +#include + + +/**\class FiltersPlugin_VolumeSize +* \ingroup DataModel +* \brief Filter for solid with specific area +*/ +class FiltersPlugin_VolumeSize : public ModelAPI_Filter +{ +public: + FiltersPlugin_VolumeSize() : ModelAPI_Filter() {} + + virtual const std::string& name() const { + static const std::string kName("Volume size"); + return kName; + } + + /// Returns true for face type + virtual bool isSupported(GeomAPI_Shape::ShapeType theType) const override; + + /// This method should contain the filter logic. It returns true if the given shape + /// is accepted by the filter. + /// \param theShape the given shape + /// \param theArgs arguments of the filter + virtual bool isOk(const GeomShapePtr& theShape, const ResultPtr&, + const ModelAPI_FiltersArgs& theArgs) const override; + + /// Returns XML string which represents GUI of the filter + virtual std::string xmlRepresentation() const override; + + /// Initializes arguments of a filter. + virtual void initAttributes(ModelAPI_FiltersArgs& theArguments) override; + +}; + +#endif diff --git a/src/FiltersPlugin/FiltersPlugin_msg_fr.ts b/src/FiltersPlugin/FiltersPlugin_msg_fr.ts index 16b245820..622d9f09c 100644 --- a/src/FiltersPlugin/FiltersPlugin_msg_fr.ts +++ b/src/FiltersPlugin/FiltersPlugin_msg_fr.ts @@ -63,10 +63,26 @@ Belongs to Appartient à + + Edge size + Taille d'arête + External faces Externe faces + + Continuous faces + Faces continues + + + Feature edges + Arêtes caractéristiques + + + Face size + Surface de face + Horizontal faces Faces horizontales @@ -103,6 +119,10 @@ Vertical faces Faces verticales + + Volume size + volume + Attribute "%1" is not initialized. Sélectionnez un objet. @@ -139,6 +159,80 @@ Sélectionner des objets pour limiter la sélection + + + EdgeSize + + Size + Longueur + + + Min size + Longueur Min + + + Max size + Longueur Max + + + is between + est compris entre + + + is strictly between + est compris strictement entre + + + + + + FaceSize + + Size + Longueur + + + Min size + Longueur Min + + + Max size + Longueur Max + + + is between + est compris entre + + + is strictly between + est compris strictement entre + + + + + + VolumeSize + + Size + Longueur + + + Min size + Longueur min + + + Max size + Longueur max + + + is between + est compris entre + + + is strictly between + est compris strictement entre + + diff --git a/src/FiltersPlugin/Test/TestFilter_ContinuousFaces.py b/src/FiltersPlugin/Test/TestFilter_ContinuousFaces.py new file mode 100644 index 000000000..7df65fe10 --- /dev/null +++ b/src/FiltersPlugin/Test/TestFilter_ContinuousFaces.py @@ -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 index 000000000..d0a13f487 --- /dev/null +++ b/src/FiltersPlugin/Test/TestFilter_EdgeSize.py @@ -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 index 000000000..8b12826e5 --- /dev/null +++ b/src/FiltersPlugin/Test/TestFilter_FaceSize.py @@ -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 index 000000000..324b98744 --- /dev/null +++ b/src/FiltersPlugin/Test/TestFilter_FeatureEdges.py @@ -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 index 000000000..22a4c3ca1 --- /dev/null +++ b/src/FiltersPlugin/Test/TestFilter_VolumeSize.py @@ -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) diff --git a/src/FiltersPlugin/Test/TestFilters_Supported.py b/src/FiltersPlugin/Test/TestFilters_Supported.py index 4d393252f..d40fbd3d5 100644 --- a/src/FiltersPlugin/Test/TestFilters_Supported.py +++ b/src/FiltersPlugin/Test/TestFilters_Supported.py @@ -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() diff --git a/src/FiltersPlugin/doc/FiltersPlugin.rst b/src/FiltersPlugin/doc/FiltersPlugin.rst index 81b67a1da..3d9bbb492 100644 --- a/src/FiltersPlugin/doc/FiltersPlugin.rst +++ b/src/FiltersPlugin/doc/FiltersPlugin.rst @@ -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 index 000000000..5864b282e --- /dev/null +++ b/src/FiltersPlugin/filter-ContinuousFaces.xml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/src/FiltersPlugin/filter-EdgeSize.xml b/src/FiltersPlugin/filter-EdgeSize.xml new file mode 100644 index 000000000..bb459a633 --- /dev/null +++ b/src/FiltersPlugin/filter-EdgeSize.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/FiltersPlugin/filter-FaceSize.xml b/src/FiltersPlugin/filter-FaceSize.xml new file mode 100644 index 000000000..2eff84f7b --- /dev/null +++ b/src/FiltersPlugin/filter-FaceSize.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/FiltersPlugin/filter-FeatureEdges.xml b/src/FiltersPlugin/filter-FeatureEdges.xml new file mode 100644 index 000000000..c4e9071e4 --- /dev/null +++ b/src/FiltersPlugin/filter-FeatureEdges.xml @@ -0,0 +1,8 @@ + + + + diff --git a/src/FiltersPlugin/filter-VolumeSize.xml b/src/FiltersPlugin/filter-VolumeSize.xml new file mode 100644 index 000000000..fcb332097 --- /dev/null +++ b/src/FiltersPlugin/filter-VolumeSize.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/FiltersPlugin/tests.set b/src/FiltersPlugin/tests.set index 722601d08..98aa0c340 100644 --- a/src/FiltersPlugin/tests.set +++ b/src/FiltersPlugin/tests.set @@ -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 ) diff --git a/src/GeomAlgoAPI/CMakeLists.txt b/src/GeomAlgoAPI/CMakeLists.txt index 0c549a45b..d55d92608 100644 --- a/src/GeomAlgoAPI/CMakeLists.txt +++ b/src/GeomAlgoAPI/CMakeLists.txt @@ -33,6 +33,7 @@ SET(PROJECT_HEADERS GeomAlgoAPI_Prism.h GeomAlgoAPI_Revolution.h GeomAlgoAPI_Boolean.h + GeomAlgoAPI_BasicProperties.h GeomAlgoAPI_ThroughAll.h GeomAlgoAPI_Rotation.h GeomAlgoAPI_Translation.h @@ -73,6 +74,7 @@ SET(PROJECT_HEADERS GeomAlgoAPI_XAOImport.h GeomAlgoAPI_Copy.h GeomAlgoAPI_ConeSegment.h + GeomAlgoAPI_ContinuousFaces.h GeomAlgoAPI_Ellipsoid.h GeomAlgoAPI_Symmetry.h GeomAlgoAPI_Scale.h @@ -103,6 +105,7 @@ SET(PROJECT_SOURCES GeomAlgoAPI_Prism.cpp GeomAlgoAPI_Revolution.cpp GeomAlgoAPI_Boolean.cpp + GeomAlgoAPI_BasicProperties.cpp GeomAlgoAPI_ThroughAll.cpp GeomAlgoAPI_Rotation.cpp GeomAlgoAPI_Translation.cpp @@ -143,6 +146,7 @@ SET(PROJECT_SOURCES GeomAlgoAPI_XAOImport.cpp GeomAlgoAPI_Copy.cpp GeomAlgoAPI_ConeSegment.cpp + GeomAlgoAPI_ContinuousFaces.cpp GeomAlgoAPI_Ellipsoid.cpp GeomAlgoAPI_Symmetry.cpp GeomAlgoAPI_Scale.cpp diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.cpp new file mode 100644 index 000000000..174929da1 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.cpp @@ -0,0 +1,75 @@ +// Copyright (C) 2014-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "GeomAlgoAPI_BasicProperties.h" + +#include +#include +#include +#include +#include + +//================================================================================================= +bool GetBasicProperties( const std::shared_ptr& theShape, + const double theTolerance, + Standard_Real& theLength, + Standard_Real& theSurfArea, + Standard_Real& theVolume, + std::string& theError) +{ + + #ifdef _DEBUG + std::cout << "GetBasicProperties " << std::endl; + #endif + + if (!theShape.get()) { + theError = "GetBasicProperties : An invalid argument"; + return false; + } + + TopoDS_Shape aShape = theShape->impl(); + + //Compute the parameters + GProp_GProps LProps, SProps; + Standard_Real anEps = theTolerance >= 0 ? theTolerance : 1.e-6; + try { + OCC_CATCH_SIGNALS; + BRepGProp::LinearProperties(aShape, LProps, Standard_True); + theLength = LProps.Mass(); + + BRepGProp::SurfaceProperties(aShape, SProps, anEps, Standard_True); + theSurfArea = SProps.Mass(); + + theVolume = 0.0; + if (aShape.ShapeType() < TopAbs_SHELL) { + for (TopExp_Explorer Exp (aShape, TopAbs_SOLID); Exp.More(); Exp.Next()) { + GProp_GProps VProps; + BRepGProp::VolumeProperties(Exp.Current(), VProps, anEps, Standard_True); + theVolume += VProps.Mass(); + } + } + } + catch (Standard_Failure& aFail) { + theError = aFail.GetMessageString(); + return false; + } + + return true; + +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.h b/src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.h new file mode 100644 index 000000000..e697dd090 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_BasicProperties.h @@ -0,0 +1,42 @@ +// Copyright (C) 2014-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef GeomAlgoAPI_BasicProperties_H_ +#define GeomAlgoAPI_BasicProperties_H_ + +#include +#include +#include + +/// Run chamfer operation with two distances or with a distance and an angle . + /// \param theShape the shape + /// \param theTolerance tolerance desirated + /// \param theLength lenght calculated + /// \param theSurfArea Surface Area calculated + /// \param theVolume Volume calculated + /// \param theError error +GEOMALGOAPI_EXPORT +bool GetBasicProperties( const std::shared_ptr& theShape, + const Standard_Real theTolerance, + Standard_Real& theLength, + Standard_Real& theSurfArea, + Standard_Real& theVolume, + std::string& theError); + +#endif diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.cpp new file mode 100644 index 000000000..a7507e432 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.cpp @@ -0,0 +1,132 @@ +// Copyright (C) 2014-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "GeomAlgoAPI_ContinuousFaces.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +const double PI = 3.141592653589793238463; + +//======================================================================= +bool isContinuousFaces(const GeomShapePtr& theFace1, + const GeomShapePtr& theFace2, + const GeomPointPtr& thePoint, + const double & theAngle, + std::string& theError) +{ + + #ifdef _DEBUG + std::cout << "isContinuousFaces " << std::endl; + #endif + + if (!thePoint.get()) { + theError = "isContinuousFaces : An invalid argument"; + return false; + } + const gp_Pnt& aPoint = thePoint->impl(); + + // Getting base shape. + if (!theFace1.get()) { + theError = "isContinuousFaces : An invalid argument"; + return false; + } + + TopoDS_Shape aShape1 = theFace1->impl(); + + 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(); + + if (aShape2.IsNull()) { + theError = "isContinuousFaces : An invalid argument"; + return false; + } + + TopoDS_Face aFace1 = TopoDS::Face(aShape1); + if (aFace1.IsNull()) { + theError = "isContinuousFaces : An invalid argument"; + return false; + } + + Handle(Geom_Surface) aSurf1 = BRep_Tool::Surface(aFace1); + if (aSurf1.IsNull()) { + theError = "isContinuousFaces : An invalid surface"; + return false; + } + + ShapeAnalysis_Surface aSAS1(aSurf1); + gp_Pnt2d aPointOnFace1 = aSAS1.ValueOfUV(aPoint, Precision::Confusion()); + + TopoDS_Face aFace2 = TopoDS::Face(aShape2); + if (aFace2.IsNull()) { + theError = "isContinuousFaces : An invalid argument"; + return false; + } + + Handle(Geom_Surface) aSurf2 = BRep_Tool::Surface(aFace2); + if (aSurf2.IsNull()) { + theError = "isContinuousFaces : An invalid surface"; + return false; + } + + ShapeAnalysis_Surface aSAS2(aSurf2); + gp_Pnt2d aPointOnFace2= aSAS2.ValueOfUV(aPoint, Precision::Confusion()); + + bool aRes = false; + try { + OCC_CATCH_SIGNALS; + LocalAnalysis_SurfaceContinuity aLocAnal(aSurf1, + aPointOnFace1.X(), + aPointOnFace1.Y(), + aSurf2, + aPointOnFace2.X(), + aPointOnFace2.Y(), + GeomAbs_Shape::GeomAbs_G1, // Order + 0.001, // EpsNul + 0.001, // EpsC0 + 0.001, // EpsC1 + 0.001, // EpsC2 + theAngle * PI/ 180.0); //EpsG1 + + aRes = aLocAnal.IsG1(); + } + catch (Standard_Failure const& anException) { + theError = "LocalAnalysis_SurfaceContinuity error :"; + theError += anException.GetMessageString(); + } + + return aRes; +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.h b/src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.h new file mode 100644 index 000000000..0d0faade4 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ContinuousFaces.h @@ -0,0 +1,42 @@ +// Copyright (C) 2014-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef GEOMALGOAPI_CONTINUOUSFACES_H_ +#define GEOMALGOAPI_CONTINUOUSFACES_H_ + +#include +#include +#include +#include + +/// indicate if two faces are continuous +/// with an angular tolerance used for G1 continuity to compare the angle between the normals +/// \param theFace1 the first face +/// \param theFace2 the second face +/// \param thePoint the point for the normal +/// \param theAngle the angular tolerance +/// \param theError error +GEOMALGOAPI_EXPORT +bool isContinuousFaces(const GeomShapePtr& theFace1, + const GeomShapePtr& theFace2, + const GeomPointPtr& thePoint, + const double & theAngle, + std::string& theError); + +#endif //GEOMALGOAPI_SHAREDFACES_H_ diff --git a/src/GeomValidators/GeomValidators_Positive.cpp b/src/GeomValidators/GeomValidators_Positive.cpp index 89cc9a263..bc352836a 100644 --- a/src/GeomValidators/GeomValidators_Positive.cpp +++ b/src/GeomValidators/GeomValidators_Positive.cpp @@ -44,7 +44,7 @@ bool GeomValidators_Positive::isValid(const AttributePtr& theAttribute, const std::list& theArguments, Events_InfoMessage& theError) const { - double aMinValue = 1.e-5; + double aMinValue = 1.e-12; if(theArguments.size() == 1) { std::list::const_iterator anIt = theArguments.begin(); double aValue = Config_PropManager::stringToDouble((*anIt).c_str()); diff --git a/src/ModuleBase/ModuleBase_WidgetSelectionFilter.cpp b/src/ModuleBase/ModuleBase_WidgetSelectionFilter.cpp index 2c10b1adb..acfc5c633 100644 --- a/src/ModuleBase/ModuleBase_WidgetSelectionFilter.cpp +++ b/src/ModuleBase/ModuleBase_WidgetSelectionFilter.cpp @@ -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); } -- 2.39.2