From 23603541d5f525a7589f370d7654084aa92360af Mon Sep 17 00:00:00 2001 From: mbs Date: Tue, 20 Dec 2022 19:25:10 +0000 Subject: [PATCH] support fuzzy parameter in all boolean operations --- src/FeaturesAPI/FeaturesAPI_BooleanCommon.cpp | 24 +++- src/FeaturesAPI/FeaturesAPI_BooleanCommon.h | 18 ++- src/FeaturesAPI/FeaturesAPI_BooleanCut.cpp | 20 ++- src/FeaturesAPI/FeaturesAPI_BooleanCut.h | 15 +- src/FeaturesAPI/FeaturesAPI_BooleanFill.cpp | 18 ++- src/FeaturesAPI/FeaturesAPI_BooleanFill.h | 15 +- src/FeaturesAPI/FeaturesAPI_BooleanFuse.cpp | 26 +++- src/FeaturesAPI/FeaturesAPI_BooleanFuse.h | 18 ++- src/FeaturesAPI/FeaturesAPI_BooleanSmash.cpp | 18 ++- src/FeaturesAPI/FeaturesAPI_BooleanSmash.h | 15 +- src/FeaturesAPI/FeaturesAPI_Intersection.cpp | 18 ++- src/FeaturesAPI/FeaturesAPI_Intersection.h | 15 +- src/FeaturesAPI/FeaturesAPI_Partition.cpp | 21 ++- src/FeaturesAPI/FeaturesAPI_Partition.h | 15 +- src/FeaturesAPI/FeaturesAPI_Union.cpp | 22 ++- src/FeaturesAPI/FeaturesAPI_Union.h | 15 +- src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp | 21 +-- src/FeaturesPlugin/FeaturesPlugin_Boolean.h | 7 + .../FeaturesPlugin_BooleanCommon.cpp | 31 +++- .../FeaturesPlugin_BooleanCommon.h | 14 -- .../FeaturesPlugin_BooleanCut.cpp | 13 +- .../FeaturesPlugin_BooleanFill.cpp | 12 +- .../FeaturesPlugin_BooleanFuse.cpp | 22 ++- .../FeaturesPlugin_BooleanSmash.cpp | 23 ++- .../FeaturesPlugin_Intersection.cpp | 14 +- .../FeaturesPlugin_Intersection.h | 7 + .../FeaturesPlugin_Partition.cpp | 26 +++- src/FeaturesPlugin/FeaturesPlugin_Partition.h | 8 ++ src/FeaturesPlugin/FeaturesPlugin_Union.cpp | 15 ++ src/FeaturesPlugin/FeaturesPlugin_Union.h | 7 + .../FeaturesPlugin_VersionedBoolean.cpp | 23 +-- .../FeaturesPlugin_VersionedBoolean.h | 3 + src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts | 99 +++++++++++++ src/FeaturesPlugin/FeaturesPlugin_msg_ru.ts | 13 +- .../Test/TestBooleanCommon_Fuzzy.py | 80 +++++++++++ .../Test/TestBooleanCut_Fuzzy_1.py | 89 ++++++++++++ .../Test/TestBooleanCut_Fuzzy_2.py | 132 ++++++++++++++++++ .../Test/TestBooleanFuse_Fuzzy.py | 85 +++++++++++ src/FeaturesPlugin/boolean_common_widget.xml | 11 ++ src/FeaturesPlugin/boolean_fuse_widget.xml | 11 ++ src/FeaturesPlugin/boolean_smash_widget.xml | 11 ++ src/FeaturesPlugin/boolean_split_widget.xml | 11 ++ src/FeaturesPlugin/boolean_widget.xml | 11 ++ src/FeaturesPlugin/doc/booleanArguments.rst | 5 + src/FeaturesPlugin/doc/commonFeature.rst | 8 +- src/FeaturesPlugin/doc/cutFeature.rst | 4 +- src/FeaturesPlugin/doc/fuseFeature.rst | 8 +- src/FeaturesPlugin/doc/images/Partition.png | Bin 8393 -> 10116 bytes src/FeaturesPlugin/doc/images/Smash.png | Bin 9320 -> 11143 bytes src/FeaturesPlugin/doc/images/Split_panel.png | Bin 10886 -> 10935 bytes ...boolean_common_advanced_property_panel.png | Bin 6665 -> 12145 bytes .../boolean_common_simple_property_panel.png | Bin 5214 -> 10802 bytes .../doc/images/boolean_cut_property_panel.png | Bin 3946 -> 10149 bytes .../boolean_fuse_advanced_property_panel.png | Bin 7377 -> 14231 bytes .../boolean_fuse_simple_property_panel.png | Bin 5921 -> 13063 bytes .../images/intersection_property_panel.png | Bin 7351 -> 8732 bytes .../doc/intersectionFeature.rst | 10 +- src/FeaturesPlugin/doc/partitionFeature.rst | 9 +- src/FeaturesPlugin/doc/smashFeature.rst | 4 +- src/FeaturesPlugin/doc/splitFeature.rst | 4 +- src/FeaturesPlugin/doc/unionFeature.rst | 5 +- src/FeaturesPlugin/intersection_widget.xml | 11 ++ src/FeaturesPlugin/partition_widget.xml | 11 ++ src/FeaturesPlugin/tests.set | 4 + src/FeaturesPlugin/union_widget.xml | 11 ++ src/GeomAlgoAPI/GeomAlgoAPI_Boolean.cpp | 28 ++-- src/GeomAlgoAPI/GeomAlgoAPI_Boolean.h | 30 +++- src/GeomAlgoAPI/GeomAlgoAPI_Intersection.cpp | 11 +- src/GeomAlgoAPI/GeomAlgoAPI_Intersection.h | 9 +- src/GeomAlgoAPI/GeomAlgoAPI_Partition.cpp | 10 +- src/GeomAlgoAPI/GeomAlgoAPI_Partition.h | 11 +- src/GeomAlgoAPI/GeomAlgoAPI_PaveFiller.cpp | 11 +- src/GeomAlgoAPI/GeomAlgoAPI_PaveFiller.h | 8 +- 73 files changed, 1154 insertions(+), 150 deletions(-) create mode 100644 src/FeaturesPlugin/Test/TestBooleanCommon_Fuzzy.py create mode 100644 src/FeaturesPlugin/Test/TestBooleanCut_Fuzzy_1.py create mode 100644 src/FeaturesPlugin/Test/TestBooleanCut_Fuzzy_2.py create mode 100644 src/FeaturesPlugin/Test/TestBooleanFuse_Fuzzy.py diff --git a/src/FeaturesAPI/FeaturesAPI_BooleanCommon.cpp b/src/FeaturesAPI/FeaturesAPI_BooleanCommon.cpp index b6d06c30c..7b8fe4217 100644 --- a/src/FeaturesAPI/FeaturesAPI_BooleanCommon.cpp +++ b/src/FeaturesAPI/FeaturesAPI_BooleanCommon.cpp @@ -34,12 +34,14 @@ FeaturesAPI_BooleanCommon::FeaturesAPI_BooleanCommon( //================================================================================================== FeaturesAPI_BooleanCommon::FeaturesAPI_BooleanCommon( const std::shared_ptr& theFeature, - const std::list& theMainObjects) + const std::list& theMainObjects, + const ModelHighAPI_Double& theFuzzy) : ModelHighAPI_Interface(theFeature) { if(initialize()) { fillAttribute(FeaturesPlugin_BooleanCommon::CREATION_METHOD_SIMPLE(), mycreationMethod); fillAttribute(theMainObjects, mymainObjects); + fillAttribute(theFuzzy, myfuzzyValue); execute(false); } @@ -49,13 +51,15 @@ FeaturesAPI_BooleanCommon::FeaturesAPI_BooleanCommon( FeaturesAPI_BooleanCommon::FeaturesAPI_BooleanCommon( const std::shared_ptr& theFeature, const std::list& theMainObjects, - const std::list& theToolObjects) + const std::list& theToolObjects, + const ModelHighAPI_Double& theFuzzy) : ModelHighAPI_Interface(theFeature) { if(initialize()) { fillAttribute(FeaturesPlugin_BooleanCommon::CREATION_METHOD_ADVANCED(), mycreationMethod); fillAttribute(theMainObjects, mymainObjects); fillAttribute(theToolObjects, mytoolObjects); + fillAttribute(theFuzzy, myfuzzyValue); execute(false); } @@ -86,6 +90,14 @@ void FeaturesAPI_BooleanCommon::setToolObjects( execute(); } +//================================================================================================== +void FeaturesAPI_BooleanCommon::setFuzzyValue(const ModelHighAPI_Double& theFuzzy) +{ + fillAttribute(theFuzzy, myfuzzyValue); + + execute(); +} + //================================================================================================== void FeaturesAPI_BooleanCommon::setAdvancedMode(const bool theMode) { @@ -111,6 +123,7 @@ void FeaturesAPI_BooleanCommon::dump(ModelHighAPI_Dumper& theDumper) const aBase->selectionList(FeaturesPlugin_BooleanCommon::OBJECT_LIST_ID()); AttributeSelectionListPtr aTools = aBase->selectionList(FeaturesPlugin_BooleanCommon::TOOL_LIST_ID()); + double aFuzzy = aBase->real(FeaturesPlugin_BooleanCommon::FUZZY_PARAM_ID())->value(); theDumper << "(" << aDocName << ", " << anObjects; @@ -118,6 +131,8 @@ void FeaturesAPI_BooleanCommon::dump(ModelHighAPI_Dumper& theDumper) const theDumper << ", " << aTools; } + theDumper << ", fuzzyParam = " << aFuzzy; + if (!aBase->data()->version().empty()) theDumper << ", keepSubResults = True"; @@ -128,6 +143,7 @@ void FeaturesAPI_BooleanCommon::dump(ModelHighAPI_Dumper& theDumper) const BooleanCommonPtr addCommon(const std::shared_ptr& thePart, const std::list& theMainObjects, const std::list& theToolObjects, + const ModelHighAPI_Double& fuzzyParam, const bool keepSubResults) { std::shared_ptr aFeature = thePart->addFeature(FeaturesAPI_BooleanCommon::ID()); @@ -135,8 +151,8 @@ BooleanCommonPtr addCommon(const std::shared_ptr& thePart, aFeature->data()->setVersion(""); BooleanCommonPtr aCommon; if (theToolObjects.empty()) - aCommon.reset(new FeaturesAPI_BooleanCommon(aFeature, theMainObjects)); + aCommon.reset(new FeaturesAPI_BooleanCommon(aFeature, theMainObjects, fuzzyParam)); else - aCommon.reset(new FeaturesAPI_BooleanCommon(aFeature, theMainObjects, theToolObjects)); + aCommon.reset(new FeaturesAPI_BooleanCommon(aFeature, theMainObjects, theToolObjects, fuzzyParam)); return aCommon; } diff --git a/src/FeaturesAPI/FeaturesAPI_BooleanCommon.h b/src/FeaturesAPI/FeaturesAPI_BooleanCommon.h index c2a055d30..b5daab109 100644 --- a/src/FeaturesAPI/FeaturesAPI_BooleanCommon.h +++ b/src/FeaturesAPI/FeaturesAPI_BooleanCommon.h @@ -26,6 +26,7 @@ #include #include +#include class ModelHighAPI_Integer; class ModelHighAPI_Selection; @@ -43,25 +44,29 @@ public: /// Constructor with values. FEATURESAPI_EXPORT FeaturesAPI_BooleanCommon(const std::shared_ptr& theFeature, - const std::list& theMainObjects); + const std::list& theMainObjects, + const ModelHighAPI_Double& theFuzzy = ModelHighAPI_Double(1.e-8)); /// Constructor with values. FEATURESAPI_EXPORT FeaturesAPI_BooleanCommon(const std::shared_ptr& theFeature, const std::list& theMainObjects, - const std::list& theToolObjects); + const std::list& theToolObjects, + const ModelHighAPI_Double& theFuzzy = ModelHighAPI_Double(1.e-8)); /// Destructor. FEATURESAPI_EXPORT virtual ~FeaturesAPI_BooleanCommon(); - INTERFACE_3(FeaturesPlugin_BooleanCommon::ID(), + INTERFACE_4(FeaturesPlugin_BooleanCommon::ID(), creationMethod, FeaturesPlugin_BooleanCommon::CREATION_METHOD(), ModelAPI_AttributeString, /** Creation method */, mainObjects, FeaturesPlugin_BooleanCommon::OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList, /** Main objects */, toolObjects, FeaturesPlugin_BooleanCommon::TOOL_LIST_ID(), - ModelAPI_AttributeSelectionList, /** Tool objects*/) + ModelAPI_AttributeSelectionList, /** Tool objects*/, + fuzzyValue, FeaturesPlugin_BooleanCommon::FUZZY_PARAM_ID(), + ModelAPI_AttributeDouble, /** Fuzzy parameter*/) /// Set main objects. FEATURESAPI_EXPORT @@ -71,6 +76,10 @@ public: FEATURESAPI_EXPORT void setToolObjects(const std::list& theToolObjects); + /// Set fuzzy parameter. + FEATURESAPI_EXPORT + void setFuzzyValue(const ModelHighAPI_Double& theFuzzy); + /// Set mode. FEATURESAPI_EXPORT void setAdvancedMode(const bool theMode); @@ -89,6 +98,7 @@ FEATURESAPI_EXPORT BooleanCommonPtr addCommon( const std::shared_ptr& part, const std::list& objects, const std::list& tools = std::list(), + const ModelHighAPI_Double& fuzzyParam = ModelHighAPI_Double(1.e-8), const bool keepSubResults = false); #endif // FeaturesAPI_BooleanCommon_H_ diff --git a/src/FeaturesAPI/FeaturesAPI_BooleanCut.cpp b/src/FeaturesAPI/FeaturesAPI_BooleanCut.cpp index 658defee7..8bb3e9e40 100644 --- a/src/FeaturesAPI/FeaturesAPI_BooleanCut.cpp +++ b/src/FeaturesAPI/FeaturesAPI_BooleanCut.cpp @@ -34,12 +34,14 @@ FeaturesAPI_BooleanCut::FeaturesAPI_BooleanCut(const std::shared_ptr& theFeature, const std::list& theMainObjects, - const std::list& theToolObjects) + const std::list& theToolObjects, + const ModelHighAPI_Double& theFuzzy) : ModelHighAPI_Interface(theFeature) { if(initialize()) { fillAttribute(theMainObjects, mymainObjects); fillAttribute(theToolObjects, mytoolObjects); + fillAttribute(theFuzzy, myfuzzyParam); execute(false); } @@ -67,6 +69,14 @@ void FeaturesAPI_BooleanCut::setToolObjects(const std::listselectionList(FeaturesPlugin_BooleanCut::OBJECT_LIST_ID()); AttributeSelectionListPtr aTools = aBase->selectionList(FeaturesPlugin_BooleanCut::TOOL_LIST_ID()); + double aFuzzy = aBase->real(FeaturesPlugin_BooleanCut::FUZZY_PARAM_ID())->value(); theDumper << "(" << aDocName << ", " << anObjects << ", " << aTools; + theDumper << ", fuzzyParam = " << aFuzzy; + if (!aBase->data()->version().empty()) theDumper << ", keepSubResults = True"; @@ -92,12 +105,11 @@ void FeaturesAPI_BooleanCut::dump(ModelHighAPI_Dumper& theDumper) const BooleanCutPtr addCut(const std::shared_ptr& thePart, const std::list& theMainObjects, const std::list& theToolObjects, + const ModelHighAPI_Double& fuzzyParam, const bool keepSubResults) { std::shared_ptr aFeature = thePart->addFeature(FeaturesAPI_BooleanCut::ID()); if (!keepSubResults) aFeature->data()->setVersion(""); - return BooleanCutPtr(new FeaturesAPI_BooleanCut(aFeature, - theMainObjects, - theToolObjects)); + return BooleanCutPtr(new FeaturesAPI_BooleanCut(aFeature, theMainObjects, theToolObjects, fuzzyParam)); } diff --git a/src/FeaturesAPI/FeaturesAPI_BooleanCut.h b/src/FeaturesAPI/FeaturesAPI_BooleanCut.h index 0035c6fdb..09f673743 100644 --- a/src/FeaturesAPI/FeaturesAPI_BooleanCut.h +++ b/src/FeaturesAPI/FeaturesAPI_BooleanCut.h @@ -26,6 +26,7 @@ #include #include +#include class ModelHighAPI_Integer; class ModelHighAPI_Selection; @@ -44,17 +45,20 @@ public: FEATURESAPI_EXPORT FeaturesAPI_BooleanCut(const std::shared_ptr& theFeature, const std::list& theMainObjects, - const std::list& theToolObjects); + const std::list& theToolObjects, + const ModelHighAPI_Double& theFuzzy = ModelHighAPI_Double(1.e-8)); /// Destructor. FEATURESAPI_EXPORT virtual ~FeaturesAPI_BooleanCut(); - INTERFACE_2(FeaturesPlugin_BooleanCut::ID(), + INTERFACE_3(FeaturesPlugin_BooleanCut::ID(), mainObjects, FeaturesPlugin_BooleanCut::OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList, /** Main objects */, toolObjects, FeaturesPlugin_BooleanCut::TOOL_LIST_ID(), - ModelAPI_AttributeSelectionList, /** Tool objects*/) + ModelAPI_AttributeSelectionList, /** Tool objects*/, + fuzzyParam, FeaturesPlugin_BooleanCut::FUZZY_PARAM_ID(), + ModelAPI_AttributeDouble, /** Fuzzy parameter */) /// Set main objects. FEATURESAPI_EXPORT @@ -64,6 +68,10 @@ public: FEATURESAPI_EXPORT void setToolObjects(const std::list& theToolObjects); + /// Set fuzzy parameter. + FEATURESAPI_EXPORT + void setFuzzyValue(const ModelHighAPI_Double& theFuzzy); + /// Dump wrapped feature FEATURESAPI_EXPORT virtual void dump(ModelHighAPI_Dumper& theDumper) const; @@ -78,6 +86,7 @@ FEATURESAPI_EXPORT BooleanCutPtr addCut(const std::shared_ptr& thePart, const std::list& theMainObjects, const std::list& theToolObjects, + const ModelHighAPI_Double& fuzzyParam = ModelHighAPI_Double(1.e-8), const bool keepSubResults = false); #endif // FeaturesAPI_BooleanCut_H_ diff --git a/src/FeaturesAPI/FeaturesAPI_BooleanFill.cpp b/src/FeaturesAPI/FeaturesAPI_BooleanFill.cpp index 7c4716cec..09d4a4774 100644 --- a/src/FeaturesAPI/FeaturesAPI_BooleanFill.cpp +++ b/src/FeaturesAPI/FeaturesAPI_BooleanFill.cpp @@ -35,12 +35,14 @@ FeaturesAPI_BooleanFill::FeaturesAPI_BooleanFill( FeaturesAPI_BooleanFill::FeaturesAPI_BooleanFill( const std::shared_ptr& theFeature, const std::list& theMainObjects, - const std::list& theToolObjects) + const std::list& theToolObjects, + const ModelHighAPI_Double& theFuzzy) : ModelHighAPI_Interface(theFeature) { if(initialize()) { fillAttribute(theMainObjects, mymainObjects); fillAttribute(theToolObjects, mytoolObjects); + fillAttribute(theFuzzy, myfuzzyParam); execute(false); } @@ -70,6 +72,14 @@ void FeaturesAPI_BooleanFill::setToolObjects( execute(); } +//================================================================================================== +void FeaturesAPI_BooleanFill::setFuzzyValue(const ModelHighAPI_Double& theFuzzy) +{ + fillAttribute(theFuzzy, myfuzzyParam); + + execute(); +} + //================================================================================================== void FeaturesAPI_BooleanFill::dump(ModelHighAPI_Dumper& theDumper) const { @@ -82,9 +92,12 @@ void FeaturesAPI_BooleanFill::dump(ModelHighAPI_Dumper& theDumper) const aBase->selectionList(FeaturesPlugin_BooleanFill::OBJECT_LIST_ID()); AttributeSelectionListPtr aTools = aBase->selectionList(FeaturesPlugin_BooleanFill::TOOL_LIST_ID()); + double aFuzzy = aBase->real(FeaturesPlugin_BooleanFill::FUZZY_PARAM_ID())->value(); theDumper << "(" << aDocName << ", " << anObjects << ", " << aTools; + theDumper << ", fuzzyParam = " << aFuzzy; + if (!aBase->data()->version().empty()) theDumper << ", keepSubResults = True"; @@ -95,10 +108,11 @@ void FeaturesAPI_BooleanFill::dump(ModelHighAPI_Dumper& theDumper) const BooleanFillPtr addSplit(const std::shared_ptr& thePart, const std::list& theMainObjects, const std::list& theToolObjects, + const ModelHighAPI_Double& fuzzyParam, const bool keepSubResults) { std::shared_ptr aFeature = thePart->addFeature(FeaturesAPI_BooleanFill::ID()); if (!keepSubResults) aFeature->data()->setVersion(""); - return BooleanFillPtr(new FeaturesAPI_BooleanFill(aFeature, theMainObjects, theToolObjects)); + return BooleanFillPtr(new FeaturesAPI_BooleanFill(aFeature, theMainObjects, theToolObjects, fuzzyParam)); } diff --git a/src/FeaturesAPI/FeaturesAPI_BooleanFill.h b/src/FeaturesAPI/FeaturesAPI_BooleanFill.h index 9a80cbce4..35743ffc9 100644 --- a/src/FeaturesAPI/FeaturesAPI_BooleanFill.h +++ b/src/FeaturesAPI/FeaturesAPI_BooleanFill.h @@ -26,6 +26,7 @@ #include #include +#include class ModelHighAPI_Integer; class ModelHighAPI_Selection; @@ -44,17 +45,20 @@ public: FEATURESAPI_EXPORT FeaturesAPI_BooleanFill(const std::shared_ptr& theFeature, const std::list& theMainObjects, - const std::list& theToolObjects); + const std::list& theToolObjects, + const ModelHighAPI_Double& theFuzzy = ModelHighAPI_Double(1.e-8)); /// Destructor. FEATURESAPI_EXPORT virtual ~FeaturesAPI_BooleanFill(); - INTERFACE_2(FeaturesPlugin_BooleanFill::ID(), + INTERFACE_3(FeaturesPlugin_BooleanFill::ID(), mainObjects, FeaturesPlugin_BooleanFill::OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList, /** Main objects */, toolObjects, FeaturesPlugin_BooleanFill::TOOL_LIST_ID(), - ModelAPI_AttributeSelectionList, /** Tool objects*/) + ModelAPI_AttributeSelectionList, /** Tool objects*/, + fuzzyParam, FeaturesPlugin_BooleanFill::FUZZY_PARAM_ID(), + ModelAPI_AttributeDouble, /** Fuzzy parameter */) /// Set main objects. FEATURESAPI_EXPORT @@ -64,6 +68,10 @@ public: FEATURESAPI_EXPORT void setToolObjects(const std::list& theToolObjects); + /// Set fuzzy parameter. + FEATURESAPI_EXPORT + void setFuzzyValue(const ModelHighAPI_Double& theFuzzy); + /// Dump wrapped feature FEATURESAPI_EXPORT virtual void dump(ModelHighAPI_Dumper& theDumper) const; @@ -78,6 +86,7 @@ FEATURESAPI_EXPORT BooleanFillPtr addSplit(const std::shared_ptr& thePart, const std::list& theMainObjects, const std::list& theToolObjects, + const ModelHighAPI_Double& fuzzyParam = ModelHighAPI_Double(1.e-8), const bool keepSubResults = false); #endif // FeaturesAPI_BooleanFill_H_ diff --git a/src/FeaturesAPI/FeaturesAPI_BooleanFuse.cpp b/src/FeaturesAPI/FeaturesAPI_BooleanFuse.cpp index 5d3ceffed..2fd8df093 100644 --- a/src/FeaturesAPI/FeaturesAPI_BooleanFuse.cpp +++ b/src/FeaturesAPI/FeaturesAPI_BooleanFuse.cpp @@ -35,13 +35,15 @@ FeaturesAPI_BooleanFuse::FeaturesAPI_BooleanFuse( FeaturesAPI_BooleanFuse::FeaturesAPI_BooleanFuse( const std::shared_ptr& theFeature, const std::list& theMainObjects, - const bool theRemoveEdges) + const bool theRemoveEdges, + const ModelHighAPI_Double& theFuzzy) : ModelHighAPI_Interface(theFeature) { if (initialize()) { fillAttribute(FeaturesPlugin_BooleanFuse::CREATION_METHOD_SIMPLE(), mycreationMethod); fillAttribute(theMainObjects, mymainObjects); fillAttribute(theRemoveEdges, myremoveEdges); + fillAttribute(theFuzzy, myfuzzyParam); execute(false); } @@ -52,7 +54,8 @@ FeaturesAPI_BooleanFuse::FeaturesAPI_BooleanFuse( const std::shared_ptr& theFeature, const std::list& theMainObjects, const std::list& theToolObjects, - const bool theRemoveEdges) + const bool theRemoveEdges, + const ModelHighAPI_Double& theFuzzy) : ModelHighAPI_Interface(theFeature) { if(initialize()) { @@ -60,6 +63,7 @@ FeaturesAPI_BooleanFuse::FeaturesAPI_BooleanFuse( fillAttribute(theMainObjects, mymainObjects); fillAttribute(theToolObjects, mytoolObjects); fillAttribute(theRemoveEdges, myremoveEdges); + fillAttribute(theFuzzy, myfuzzyParam); execute(false); } @@ -98,6 +102,14 @@ void FeaturesAPI_BooleanFuse::setRemoveEdges(const bool theRemoveEdges) execute(); } +//================================================================================================== +void FeaturesAPI_BooleanFuse::setFuzzyValue(const ModelHighAPI_Double& theFuzzy) +{ + fillAttribute(theFuzzy, myfuzzyParam); + + execute(); +} + //================================================================================================== void FeaturesAPI_BooleanFuse::setAdvancedMode(const bool theMode) { @@ -125,6 +137,7 @@ void FeaturesAPI_BooleanFuse::dump(ModelHighAPI_Dumper& theDumper) const aBase->selectionList(FeaturesPlugin_BooleanFuse::TOOL_LIST_ID()); AttributeBooleanPtr aRemoveEdges = aBase->boolean(FeaturesPlugin_BooleanFuse::REMOVE_INTERSECTION_EDGES_ID()); + double aFuzzy = aBase->real(FeaturesPlugin_BooleanFuse::FUZZY_PARAM_ID())->value(); theDumper << "(" << aDocName << ", " << anObjects; @@ -136,6 +149,10 @@ void FeaturesAPI_BooleanFuse::dump(ModelHighAPI_Dumper& theDumper) const theDumper << ", removeEdges = True"; } + if (aFuzzy != 1.e-8) { + theDumper << ", fuzzyParam = " << aFuzzy; + } + if (!aBase->data()->version().empty()) theDumper << ", keepSubResults = True"; @@ -147,6 +164,7 @@ BooleanFusePtr addFuse(const std::shared_ptr& thePart, const std::list& theMainObjects, const std::pair, bool>& theToolObjects, const bool theRemoveEdges, + const ModelHighAPI_Double& fuzzyParam, const bool keepSubResults) { std::shared_ptr aFeature = thePart->addFeature(FeaturesAPI_BooleanFuse::ID()); @@ -159,10 +177,10 @@ BooleanFusePtr addFuse(const std::shared_ptr& thePart, BooleanFusePtr aFuse; if (theToolObjects.first.empty()) - aFuse.reset(new FeaturesAPI_BooleanFuse(aFeature, theMainObjects, aRemoveEdges)); + aFuse.reset(new FeaturesAPI_BooleanFuse(aFeature, theMainObjects, aRemoveEdges, fuzzyParam)); else { aFuse.reset(new FeaturesAPI_BooleanFuse(aFeature, theMainObjects, theToolObjects.first, - aRemoveEdges)); + aRemoveEdges, fuzzyParam)); } return aFuse; } diff --git a/src/FeaturesAPI/FeaturesAPI_BooleanFuse.h b/src/FeaturesAPI/FeaturesAPI_BooleanFuse.h index 3c4fdccdf..04da890e6 100644 --- a/src/FeaturesAPI/FeaturesAPI_BooleanFuse.h +++ b/src/FeaturesAPI/FeaturesAPI_BooleanFuse.h @@ -26,6 +26,7 @@ #include #include +#include class ModelHighAPI_Integer; class ModelHighAPI_Selection; @@ -44,20 +45,22 @@ public: FEATURESAPI_EXPORT FeaturesAPI_BooleanFuse(const std::shared_ptr& theFeature, const std::list& theMainObjects, - const bool theRemoveEdges = false); + const bool theRemoveEdges = false, + const ModelHighAPI_Double& theFuzzy = ModelHighAPI_Double(1.e-8)); /// Constructor with values. FEATURESAPI_EXPORT FeaturesAPI_BooleanFuse(const std::shared_ptr& theFeature, const std::list& theMainObjects, const std::list& theToolObjects, - const bool theRemoveEdges = false); + const bool theRemoveEdges = false, + const ModelHighAPI_Double& theFuzzy = ModelHighAPI_Double(1.e-8)); /// Destructor. FEATURESAPI_EXPORT virtual ~FeaturesAPI_BooleanFuse(); - INTERFACE_4(FeaturesPlugin_BooleanFuse::ID(), + INTERFACE_5(FeaturesPlugin_BooleanFuse::ID(), creationMethod, FeaturesPlugin_BooleanFuse::CREATION_METHOD(), ModelAPI_AttributeString, /** Creation method */, mainObjects, FeaturesPlugin_BooleanFuse::OBJECT_LIST_ID(), @@ -65,7 +68,9 @@ public: toolObjects, FeaturesPlugin_BooleanFuse::TOOL_LIST_ID(), ModelAPI_AttributeSelectionList, /** Tool objects*/, removeEdges, FeaturesPlugin_BooleanFuse::REMOVE_INTERSECTION_EDGES_ID(), - ModelAPI_AttributeBoolean, /** Remove edges */) + ModelAPI_AttributeBoolean, /** Remove edges */, + fuzzyParam, FeaturesPlugin_BooleanFuse::FUZZY_PARAM_ID(), + ModelAPI_AttributeDouble, /** Fuzzy parameter */) /// Set main objects. FEATURESAPI_EXPORT @@ -79,6 +84,10 @@ public: FEATURESAPI_EXPORT void setRemoveEdges(const bool theRemoveEdges); + /// Set fuzzy parameter. + FEATURESAPI_EXPORT + void setFuzzyValue(const ModelHighAPI_Double& theFuzzy); + /// Set mode. FEATURESAPI_EXPORT void setAdvancedMode(const bool theMode); @@ -101,6 +110,7 @@ FEATURESAPI_EXPORT BooleanFusePtr addFuse( const std::list& objects, const std::pair, bool>& tools = DUMMY_TOOLS, const bool removeEdges = false, + const ModelHighAPI_Double& fuzzyParam = ModelHighAPI_Double(1.e-8), const bool keepSubResults = false); #endif // FeaturesAPI_BooleanFuse_H_ diff --git a/src/FeaturesAPI/FeaturesAPI_BooleanSmash.cpp b/src/FeaturesAPI/FeaturesAPI_BooleanSmash.cpp index 4a4d0330f..7c5ce1722 100644 --- a/src/FeaturesAPI/FeaturesAPI_BooleanSmash.cpp +++ b/src/FeaturesAPI/FeaturesAPI_BooleanSmash.cpp @@ -35,12 +35,14 @@ FeaturesAPI_BooleanSmash::FeaturesAPI_BooleanSmash( FeaturesAPI_BooleanSmash::FeaturesAPI_BooleanSmash( const std::shared_ptr& theFeature, const std::list& theMainObjects, - const std::list& theToolObjects) + const std::list& theToolObjects, + const ModelHighAPI_Double& theFuzzy) : ModelHighAPI_Interface(theFeature) { if(initialize()) { fillAttribute(theMainObjects, mymainObjects); fillAttribute(theToolObjects, mytoolObjects); + fillAttribute(theFuzzy, myfuzzyParam); execute(false); } @@ -70,6 +72,14 @@ void FeaturesAPI_BooleanSmash::setToolObjects( execute(); } +//================================================================================================== +void FeaturesAPI_BooleanSmash::setFuzzyValue(const ModelHighAPI_Double& theFuzzy) +{ + fillAttribute(theFuzzy, myfuzzyParam); + + execute(); +} + //================================================================================================== void FeaturesAPI_BooleanSmash::dump(ModelHighAPI_Dumper& theDumper) const { @@ -82,9 +92,12 @@ void FeaturesAPI_BooleanSmash::dump(ModelHighAPI_Dumper& theDumper) const aBase->selectionList(FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID()); AttributeSelectionListPtr aTools = aBase->selectionList(FeaturesPlugin_BooleanSmash::TOOL_LIST_ID()); + double aFuzzy = aBase->real(FeaturesPlugin_BooleanSmash::FUZZY_PARAM_ID())->value(); theDumper << "(" << aDocName << ", " << anObjects << ", " << aTools; + theDumper << ", fuzzyParam = " << aFuzzy; + if (!aBase->data()->version().empty()) theDumper << ", keepSubResults = True"; @@ -95,10 +108,11 @@ void FeaturesAPI_BooleanSmash::dump(ModelHighAPI_Dumper& theDumper) const BooleanSmashPtr addSmash(const std::shared_ptr& thePart, const std::list& theMainObjects, const std::list& theToolObjects, + const ModelHighAPI_Double& fuzzyParam, const bool keepSubResults) { std::shared_ptr aFeature = thePart->addFeature(FeaturesAPI_BooleanSmash::ID()); if (!keepSubResults) aFeature->data()->setVersion(""); - return BooleanSmashPtr(new FeaturesAPI_BooleanSmash(aFeature, theMainObjects, theToolObjects)); + return BooleanSmashPtr(new FeaturesAPI_BooleanSmash(aFeature, theMainObjects, theToolObjects, fuzzyParam)); } diff --git a/src/FeaturesAPI/FeaturesAPI_BooleanSmash.h b/src/FeaturesAPI/FeaturesAPI_BooleanSmash.h index a59db43d0..188079af7 100644 --- a/src/FeaturesAPI/FeaturesAPI_BooleanSmash.h +++ b/src/FeaturesAPI/FeaturesAPI_BooleanSmash.h @@ -26,6 +26,7 @@ #include #include +#include class ModelHighAPI_Integer; class ModelHighAPI_Selection; @@ -44,17 +45,20 @@ public: FEATURESAPI_EXPORT FeaturesAPI_BooleanSmash(const std::shared_ptr& theFeature, const std::list& theMainObjects, - const std::list& theToolObjects); + const std::list& theToolObjects, + const ModelHighAPI_Double& theFuzzy = ModelHighAPI_Double(1.e-8)); /// Destructor. FEATURESAPI_EXPORT virtual ~FeaturesAPI_BooleanSmash(); - INTERFACE_2(FeaturesPlugin_BooleanSmash::ID(), + INTERFACE_3(FeaturesPlugin_BooleanSmash::ID(), mainObjects, FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList, /** Main objects */, toolObjects, FeaturesPlugin_BooleanSmash::TOOL_LIST_ID(), - ModelAPI_AttributeSelectionList, /** Tool objects*/) + ModelAPI_AttributeSelectionList, /** Tool objects*/, + fuzzyParam, FeaturesPlugin_BooleanSmash::FUZZY_PARAM_ID(), + ModelAPI_AttributeDouble, /** Fuzzy parameter */) /// Set main objects. FEATURESAPI_EXPORT @@ -64,6 +68,10 @@ public: FEATURESAPI_EXPORT void setToolObjects(const std::list& theToolObjects); + /// Set fuzzy parameter. + FEATURESAPI_EXPORT + void setFuzzyValue(const ModelHighAPI_Double& theFuzzy); + /// Dump wrapped feature FEATURESAPI_EXPORT virtual void dump(ModelHighAPI_Dumper& theDumper) const; @@ -78,6 +86,7 @@ FEATURESAPI_EXPORT BooleanSmashPtr addSmash(const std::shared_ptr& thePart, const std::list& theMainObjects, const std::list& theToolObjects, + const ModelHighAPI_Double& fuzzyParam = ModelHighAPI_Double(1.e-8), const bool keepSubResults = false); #endif // FeaturesAPI_BooleanSmash_H_ diff --git a/src/FeaturesAPI/FeaturesAPI_Intersection.cpp b/src/FeaturesAPI/FeaturesAPI_Intersection.cpp index 6ac09629c..6ceafb170 100644 --- a/src/FeaturesAPI/FeaturesAPI_Intersection.cpp +++ b/src/FeaturesAPI/FeaturesAPI_Intersection.cpp @@ -33,11 +33,13 @@ FeaturesAPI_Intersection::FeaturesAPI_Intersection( //================================================================================================== FeaturesAPI_Intersection::FeaturesAPI_Intersection( const std::shared_ptr& theFeature, - const std::list& theObjects) + const std::list& theObjects, + const ModelHighAPI_Double& theFuzzy) : ModelHighAPI_Interface(theFeature) { if(initialize()) { fillAttribute(theObjects, myobjects); + fillAttribute(theFuzzy, myfuzzyParam); execute(); } @@ -57,6 +59,14 @@ void FeaturesAPI_Intersection::setObjects(const std::listselectionList(FeaturesPlugin_Intersection::OBJECT_LIST_ID()); + double aFuzzy = aBase->real(FeaturesPlugin_Intersection::FUZZY_PARAM_ID())->value(); theDumper << aBase << " = model.addIntersection(" << aDocName << ", " << anAttrObjects; + theDumper << ", fuzzyParam = " << aFuzzy; + if (!aBase->data()->version().empty()) theDumper << ", keepSubResults = True"; @@ -77,10 +90,11 @@ void FeaturesAPI_Intersection::dump(ModelHighAPI_Dumper& theDumper) const //================================================================================================== IntersectionPtr addIntersection(const std::shared_ptr& thePart, const std::list& theObjects, + const ModelHighAPI_Double& fuzzyParam, const bool keepSubResults) { std::shared_ptr aFeature = thePart->addFeature(FeaturesAPI_Intersection::ID()); if (!keepSubResults) aFeature->data()->setVersion(""); - return IntersectionPtr(new FeaturesAPI_Intersection(aFeature, theObjects)); + return IntersectionPtr(new FeaturesAPI_Intersection(aFeature, theObjects, fuzzyParam)); } diff --git a/src/FeaturesAPI/FeaturesAPI_Intersection.h b/src/FeaturesAPI/FeaturesAPI_Intersection.h index acaff95bc..f69daaff6 100644 --- a/src/FeaturesAPI/FeaturesAPI_Intersection.h +++ b/src/FeaturesAPI/FeaturesAPI_Intersection.h @@ -26,6 +26,7 @@ #include #include +#include class ModelHighAPI_Dumper; class ModelHighAPI_Selection; @@ -43,20 +44,27 @@ public: /// Constructor with values. FEATURESAPI_EXPORT explicit FeaturesAPI_Intersection(const std::shared_ptr& theFeature, - const std::list& theObjects); + const std::list& theObjects, + const ModelHighAPI_Double& aFuzzy = ModelHighAPI_Double(1.e-8)); /// Destructor. FEATURESAPI_EXPORT virtual ~FeaturesAPI_Intersection(); - INTERFACE_1(FeaturesPlugin_Intersection::ID(), + INTERFACE_2(FeaturesPlugin_Intersection::ID(), objects, FeaturesPlugin_Intersection::OBJECT_LIST_ID(), - ModelAPI_AttributeSelectionList, /** Objects */) + ModelAPI_AttributeSelectionList, /** Objects */, + fuzzyParam, FeaturesPlugin_Intersection::FUZZY_PARAM_ID(), + ModelAPI_AttributeDouble, /** Fuzzy parameter */) /// Modify objects attribute of the feature. FEATURESAPI_EXPORT void setObjects(const std::list& theObjects); + /// Set fuzzy parameter. + FEATURESAPI_EXPORT + void setFuzzyValue(const ModelHighAPI_Double& theFuzzy); + /// Dump wrapped feature FEATURESAPI_EXPORT virtual void dump(ModelHighAPI_Dumper& theDumper) const; @@ -70,6 +78,7 @@ typedef std::shared_ptr IntersectionPtr; FEATURESAPI_EXPORT IntersectionPtr addIntersection(const std::shared_ptr& part, const std::list& objects, + const ModelHighAPI_Double& fuzzyParam = ModelHighAPI_Double(1.e-8), const bool keepSubResults = false); #endif // FeaturesAPI_Intersection_H_ diff --git a/src/FeaturesAPI/FeaturesAPI_Partition.cpp b/src/FeaturesAPI/FeaturesAPI_Partition.cpp index 54ff44bb3..c7ca9aa40 100644 --- a/src/FeaturesAPI/FeaturesAPI_Partition.cpp +++ b/src/FeaturesAPI/FeaturesAPI_Partition.cpp @@ -32,11 +32,14 @@ FeaturesAPI_Partition::FeaturesAPI_Partition(const std::shared_ptr& theFeature, - const std::list& theBaseObjects) + const std::list& theBaseObjects, + const ModelHighAPI_Double& theFuzzy) : ModelHighAPI_Interface(theFeature) { if(initialize()) { - setBase(theBaseObjects); + fillAttribute(theBaseObjects, mybaseObjects); + fillAttribute(theFuzzy, myfuzzyParam); + execute(); } } @@ -54,6 +57,14 @@ void FeaturesAPI_Partition::setBase(const std::list& the execute(); } +//================================================================================================== +void FeaturesAPI_Partition::setFuzzy(const ModelHighAPI_Double& theFuzzy) +{ + fillAttribute(theFuzzy, myfuzzyParam); + + execute(); +} + //================================================================================================== void FeaturesAPI_Partition::dump(ModelHighAPI_Dumper& theDumper) const { @@ -62,9 +73,12 @@ void FeaturesAPI_Partition::dump(ModelHighAPI_Dumper& theDumper) const AttributeSelectionListPtr anAttrObjects = aBase->selectionList(FeaturesPlugin_Partition::BASE_OBJECTS_ID()); + double aFuzzy = aBase->real(FeaturesPlugin_Partition::FUZZY_PARAM_ID())->value(); theDumper << aBase << " = model.addPartition(" << aDocName << ", " << anAttrObjects; + theDumper << ", fuzzyParam = " << aFuzzy; + if (!aBase->data()->version().empty()) theDumper << ", keepSubResults = True"; @@ -74,10 +88,11 @@ void FeaturesAPI_Partition::dump(ModelHighAPI_Dumper& theDumper) const //================================================================================================== PartitionPtr addPartition(const std::shared_ptr& thePart, const std::list& theBaseObjects, + const ModelHighAPI_Double& fuzzyParam, const bool keepSubResults) { std::shared_ptr aFeature = thePart->addFeature(FeaturesAPI_Partition::ID()); if (!keepSubResults) aFeature->data()->setVersion(""); - return PartitionPtr(new FeaturesAPI_Partition(aFeature, theBaseObjects)); + return PartitionPtr(new FeaturesAPI_Partition(aFeature, theBaseObjects, fuzzyParam)); } diff --git a/src/FeaturesAPI/FeaturesAPI_Partition.h b/src/FeaturesAPI/FeaturesAPI_Partition.h index eb125b78f..3e533ff93 100644 --- a/src/FeaturesAPI/FeaturesAPI_Partition.h +++ b/src/FeaturesAPI/FeaturesAPI_Partition.h @@ -26,6 +26,7 @@ #include #include +#include class ModelHighAPI_Dumper; class ModelHighAPI_Selection; @@ -43,20 +44,27 @@ public: /// Constructor with values. FEATURESAPI_EXPORT explicit FeaturesAPI_Partition(const std::shared_ptr& theFeature, - const std::list& theBaseObjects); + const std::list& theBaseObjects, + const ModelHighAPI_Double& theFuzzy = ModelHighAPI_Double(1.e-8)); /// Destructor. FEATURESAPI_EXPORT virtual ~FeaturesAPI_Partition(); - INTERFACE_1(FeaturesPlugin_Partition::ID(), + INTERFACE_2(FeaturesPlugin_Partition::ID(), baseObjects, FeaturesPlugin_Partition::BASE_OBJECTS_ID(), - ModelAPI_AttributeSelectionList, /** Base objects */) + ModelAPI_AttributeSelectionList, /** Base objects */, + fuzzyParam, FeaturesPlugin_Partition::FUZZY_PARAM_ID(), + ModelAPI_AttributeDouble, /** Fuzzy parameter */) /// Modify base attribute of the feature. FEATURESAPI_EXPORT void setBase(const std::list& theBaseObjects); + /// Modify fuzzy parameter attribute of the feature. + FEATURESAPI_EXPORT + void setFuzzy(const ModelHighAPI_Double& theFuzzy); + /// Dump wrapped feature FEATURESAPI_EXPORT virtual void dump(ModelHighAPI_Dumper& theDumper) const; @@ -70,6 +78,7 @@ typedef std::shared_ptr PartitionPtr; FEATURESAPI_EXPORT PartitionPtr addPartition(const std::shared_ptr& thePart, const std::list& theBaseObjects, + const ModelHighAPI_Double& fuzzyParam = ModelHighAPI_Double(1.e-8), const bool keepSubResults = false); #endif // FeaturesAPI_Partition_H_ diff --git a/src/FeaturesAPI/FeaturesAPI_Union.cpp b/src/FeaturesAPI/FeaturesAPI_Union.cpp index 082016c98..30e4234b2 100644 --- a/src/FeaturesAPI/FeaturesAPI_Union.cpp +++ b/src/FeaturesAPI/FeaturesAPI_Union.cpp @@ -31,11 +31,15 @@ FeaturesAPI_Union::FeaturesAPI_Union(const std::shared_ptr& th //================================================================================================ FeaturesAPI_Union::FeaturesAPI_Union(const std::shared_ptr& theFeature, - const std::list& theBaseObjects) + const std::list& theBaseObjects, + const ModelHighAPI_Double& theFuzzy) : ModelHighAPI_Interface(theFeature) { if(initialize()) { - setBase(theBaseObjects); + fillAttribute(theBaseObjects, mybaseObjects); + fillAttribute(theFuzzy, myfuzzyParam); + + execute(); } } @@ -53,6 +57,14 @@ void FeaturesAPI_Union::setBase(const std::list& theBase execute(); } +//================================================================================================== +void FeaturesAPI_Union::setFuzzyValue(const ModelHighAPI_Double& theFuzzy) +{ + fillAttribute(theFuzzy, myfuzzyParam); + + execute(); +} + //================================================================================================== void FeaturesAPI_Union::dump(ModelHighAPI_Dumper& theDumper) const { @@ -61,9 +73,12 @@ void FeaturesAPI_Union::dump(ModelHighAPI_Dumper& theDumper) const AttributeSelectionListPtr anAttrObjects = aBase->selectionList(FeaturesPlugin_Union::BASE_OBJECTS_ID()); + double aFuzzy = aBase->real(FeaturesPlugin_Union::FUZZY_PARAM_ID())->value(); theDumper << aBase << " = model.addUnion(" << aDocName << ", " << anAttrObjects; + theDumper << ", fuzzyParam = " << aFuzzy; + if (!aBase->data()->version().empty()) theDumper << ", keepSubResults = True"; @@ -73,10 +88,11 @@ void FeaturesAPI_Union::dump(ModelHighAPI_Dumper& theDumper) const //================================================================================================== UnionPtr addUnion(const std::shared_ptr& thePart, const std::list& theBaseObjects, + const ModelHighAPI_Double& fuzzyParam, const bool keepSubResults) { std::shared_ptr aFeature = thePart->addFeature(FeaturesAPI_Union::ID()); if (!keepSubResults) aFeature->data()->setVersion(""); - return UnionPtr(new FeaturesAPI_Union(aFeature, theBaseObjects)); + return UnionPtr(new FeaturesAPI_Union(aFeature, theBaseObjects, fuzzyParam)); } diff --git a/src/FeaturesAPI/FeaturesAPI_Union.h b/src/FeaturesAPI/FeaturesAPI_Union.h index af6de9746..022d14130 100644 --- a/src/FeaturesAPI/FeaturesAPI_Union.h +++ b/src/FeaturesAPI/FeaturesAPI_Union.h @@ -26,6 +26,7 @@ #include #include +#include class ModelHighAPI_Dumper; class ModelHighAPI_Selection; @@ -43,20 +44,27 @@ public: /// Constructor with values. FEATURESAPI_EXPORT explicit FeaturesAPI_Union(const std::shared_ptr& theFeature, - const std::list& theBaseObjects); + const std::list& theBaseObjects, + const ModelHighAPI_Double& theFuzzy = ModelHighAPI_Double(1.e-8)); /// Destructor. FEATURESAPI_EXPORT virtual ~FeaturesAPI_Union(); - INTERFACE_1(FeaturesPlugin_Union::ID(), + INTERFACE_2(FeaturesPlugin_Union::ID(), baseObjects, FeaturesPlugin_Union::BASE_OBJECTS_ID(), - ModelAPI_AttributeSelectionList, /** Base objects */) + ModelAPI_AttributeSelectionList, /** Base objects */, + fuzzyParam, FeaturesPlugin_Union::FUZZY_PARAM_ID(), + ModelAPI_AttributeDouble, /** Fuzzy parameter */) /// Modify base attribute of the feature. FEATURESAPI_EXPORT void setBase(const std::list& theBaseObjects); + /// Set fuzzy parameter. + FEATURESAPI_EXPORT + void setFuzzyValue(const ModelHighAPI_Double& theFuzzy); + /// Dump wrapped feature FEATURESAPI_EXPORT virtual void dump(ModelHighAPI_Dumper& theDumper) const; @@ -70,6 +78,7 @@ typedef std::shared_ptr UnionPtr; FEATURESAPI_EXPORT UnionPtr addUnion(const std::shared_ptr& thePart, const std::list& theBaseObjects, + const ModelHighAPI_Double& fuzzyParam = ModelHighAPI_Double(1.e-8), const bool keepSubResults = false); #endif // FeaturesAPI_Union_H_ diff --git a/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp b/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp index bb277c382..82f08f182 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -54,12 +55,14 @@ FeaturesPlugin_Boolean::FeaturesPlugin_Boolean(const OperationType theOperationT //================================================================================================= void FeaturesPlugin_Boolean::initAttributes() { - AttributeSelectionListPtr aSelection = - std::dynamic_pointer_cast(data()->addAttribute( - FeaturesPlugin_Boolean::OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId())); + data()->addAttribute(FeaturesPlugin_Boolean::OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()); + data()->addAttribute(FeaturesPlugin_Boolean::TOOL_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()); - aSelection = std::dynamic_pointer_cast(data()->addAttribute( - FeaturesPlugin_Boolean::TOOL_LIST_ID(), ModelAPI_AttributeSelectionList::typeId())); + data()->addAttribute(FeaturesPlugin_Boolean::FUZZY_PARAM_ID(), ModelAPI_AttributeDouble::typeId()); + // Initialize the fuzzy parameter with a value below Precision::Confusion() to indicate, + // that the internal algorithms should use their default fuzzy value, if none was specified + // by the user. + real(FUZZY_PARAM_ID())->setValue(1.e-8); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), OBJECT_LIST_ID()); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), TOOL_LIST_ID()); @@ -120,10 +123,10 @@ void FeaturesPlugin_Boolean::storeResult( document()->createBody(data(), theResultIndex); ModelAPI_Tools::loadModifiedShapes(aResultBody, - theObjects, - theTools, - theMakeShapeList, - theResultShape); + theObjects, + theTools, + theMakeShapeList, + theResultShape); setResult(aResultBody, theResultIndex++); // merge algorithms diff --git a/src/FeaturesPlugin/FeaturesPlugin_Boolean.h b/src/FeaturesPlugin/FeaturesPlugin_Boolean.h index 960edb584..fc88bcbab 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Boolean.h +++ b/src/FeaturesPlugin/FeaturesPlugin_Boolean.h @@ -51,6 +51,13 @@ public: return MY_TOOL_LIST_ID; } + /// Attribute name of fuzzy parameter. + inline static const std::string& FUZZY_PARAM_ID() + { + static const std::string MY_FUZZY_PARAM_ID("fuzzy_param"); + return MY_FUZZY_PARAM_ID; + } + /// \return boolean operation type. FEATURESPLUGIN_EXPORT OperationType operationType(); diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.cpp index e3023859e..b3d4e4c53 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.cpp @@ -20,6 +20,7 @@ #include "FeaturesPlugin_BooleanCommon.h" #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include + //================================================================================================== FeaturesPlugin_BooleanCommon::FeaturesPlugin_BooleanCommon() : FeaturesPlugin_Boolean(FeaturesPlugin_Boolean::BOOL_COMMON) @@ -52,6 +54,13 @@ void FeaturesPlugin_BooleanCommon::initAttributes() data()->addAttribute(OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()); data()->addAttribute(TOOL_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()); + data()->addAttribute(FUZZY_PARAM_ID(), ModelAPI_AttributeDouble::typeId()); + + // Initialize the fuzzy parameter with a value below Precision::Confusion() to indicate, + // that the internal algorithms should use their default fuzzy value, if none was specified + // by the user. + real(FUZZY_PARAM_ID())->setValue(1.e-8); + initVersion(BOP_VERSION_9_4(), selectionList(OBJECT_LIST_ID()), selectionList(TOOL_LIST_ID())); } @@ -86,6 +95,10 @@ void FeaturesPlugin_BooleanCommon::execute() return; } + // Getting fuzzy parameter. + // Used as additional tolerance to eliminate tiny results. + double aFuzzy = real(FUZZY_PARAM_ID())->value(); + // version of COMMON feature const std::string aCommonVersion = data()->version(); @@ -104,7 +117,8 @@ void FeaturesPlugin_BooleanCommon::execute() std::shared_ptr aCommonAlgo( new GeomAlgoAPI_Boolean(aShape, *anObjectsIt, - GeomAlgoAPI_Tools::BOOL_COMMON)); + GeomAlgoAPI_Tools::BOOL_COMMON, + aFuzzy)); if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCommonAlgo, getKind(), anError)) { setError(anError); @@ -129,10 +143,10 @@ void FeaturesPlugin_BooleanCommon::execute() ListOfShape anObjectList = anObjects.objects(); ListOfShape aToolsList; ModelAPI_Tools::loadModifiedShapes(aResultBody, - anObjectList, - aToolsList, - aMakeShapeList, - aShape); + anObjectList, + aToolsList, + aMakeShapeList, + aShape); GeomShapePtr aBaseShape = anObjectList.front(); anObjectList.pop_front(); setResult(aResultBody, aResultIndex); @@ -167,6 +181,7 @@ void FeaturesPlugin_BooleanCommon::execute() // Compound handling isOk = processCompound(GeomAlgoAPI_Tools::BOOL_COMMON, anObjects, aParent, aTools.objects(), + aFuzzy, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } @@ -174,6 +189,7 @@ void FeaturesPlugin_BooleanCommon::execute() // Compsolid handling isOk = processCompsolid(GeomAlgoAPI_Tools::BOOL_COMMON, anObjects, aParent, aTools.objects(), ListOfShape(), + aFuzzy, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } @@ -181,6 +197,7 @@ void FeaturesPlugin_BooleanCommon::execute() // process object as is isOk = processObject(GeomAlgoAPI_Tools::BOOL_COMMON, anObject, aTools.objects(), aPlanes, + aFuzzy, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } @@ -195,8 +212,8 @@ void FeaturesPlugin_BooleanCommon::execute() if (!aResultCompound) aResultCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList); ModelAPI_Tools::loadDeletedShapes(aResultBaseAlgoList, - aTools.objects(), - aResultCompound); + aTools.objects(), + aResultCompound); // remove the rest results if there were produced in the previous pass removeResults(aResultIndex); diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.h b/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.h index 7e46caf23..8817a5748 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.h +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.h @@ -66,20 +66,6 @@ public: return MY_CREATION_METHOD_ID; } - /// Attribute name of main objects. - inline static const std::string& OBJECT_LIST_ID() - { - static const std::string MY_OBJECT_LIST_ID("main_objects"); - return MY_OBJECT_LIST_ID; - } - - /// Attribute name of tool objects. - inline static const std::string& TOOL_LIST_ID() - { - static const std::string MY_TOOL_LIST_ID("tool_objects"); - return MY_TOOL_LIST_ID; - } - /// Request for initialization of data model of the feature: adding all attributes. FEATURESPLUGIN_EXPORT virtual void initAttributes(); diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp index 3095f40fd..50de25d0c 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp @@ -20,6 +20,7 @@ #include "FeaturesPlugin_BooleanCut.h" #include +#include #include #include @@ -33,6 +34,7 @@ #include #include + //================================================================================================== FeaturesPlugin_BooleanCut::FeaturesPlugin_BooleanCut() : FeaturesPlugin_Boolean(FeaturesPlugin_Boolean::BOOL_CUT) @@ -78,6 +80,10 @@ void FeaturesPlugin_BooleanCut::execute() keepUnusedSubsOfCompound(GeomShapePtr(), anObjects, aTools, aMakeShapeList); } + // Getting fuzzy parameter. + // Used as additional tolerance to eliminate tiny results. + double aFuzzy = real(FUZZY_PARAM_ID())->value(); + // For solids cut each object with all tools. bool isOk = true; for (GeomAPI_ShapeHierarchy::iterator anObjectsIt = anObjects.begin(); @@ -92,6 +98,7 @@ void FeaturesPlugin_BooleanCut::execute() // Compound handling isOk = processCompound(GeomAlgoAPI_Tools::BOOL_CUT, anObjects, aParent, aTools.objects(), + aFuzzy, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } @@ -99,6 +106,7 @@ void FeaturesPlugin_BooleanCut::execute() // Compsolid handling isOk = processCompsolid(GeomAlgoAPI_Tools::BOOL_CUT, anObjects, aParent, aTools.objects(), ListOfShape(), + aFuzzy, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } @@ -106,6 +114,7 @@ void FeaturesPlugin_BooleanCut::execute() // process object as is isOk = processObject(GeomAlgoAPI_Tools::BOOL_CUT, anObject, aTools.objects(), aPlanes, + aFuzzy, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } @@ -119,8 +128,8 @@ void FeaturesPlugin_BooleanCut::execute() if (!aResultCompound) aResultCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList); ModelAPI_Tools::loadDeletedShapes(aResultBaseAlgoList, - aTools.objects(), - aResultCompound); + aTools.objects(), + aResultCompound); // remove the rest results if there were produced in the previous pass removeResults(aResultIndex); diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanFill.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanFill.cpp index e0e2c6ed1..247fd3561 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanFill.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanFill.cpp @@ -20,6 +20,7 @@ #include "FeaturesPlugin_BooleanFill.h" #include +#include #include #include @@ -39,6 +40,7 @@ #include #include + //================================================================================================= FeaturesPlugin_BooleanFill::FeaturesPlugin_BooleanFill() : FeaturesPlugin_Boolean(FeaturesPlugin_Boolean::BOOL_FILL) @@ -89,6 +91,10 @@ void FeaturesPlugin_BooleanFill::execute() keepUnusedSubsOfCompound(GeomShapePtr(), anObjects, aTools, aMakeShapeList); } + // Getting fuzzy parameter. + // Used as additional tolerance to eliminate tiny results. + double aFuzzy = real(FUZZY_PARAM_ID())->value(); + // For solids cut each object with all tools. bool isOk = true; for (GeomAPI_ShapeHierarchy::iterator anObjectsIt = anObjects.begin(); @@ -103,12 +109,14 @@ void FeaturesPlugin_BooleanFill::execute() // compsolid handling isOk = processCompsolid(GeomAlgoAPI_Tools::BOOL_PARTITION, anObjects, aParent, aTools.objects(), aPlanes, + aFuzzy, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } else { // process object as is isOk = processObject(GeomAlgoAPI_Tools::BOOL_PARTITION, anObject, aTools.objects(), aPlanes, + aFuzzy, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } @@ -122,8 +130,8 @@ void FeaturesPlugin_BooleanFill::execute() if (!aResultCompound) aResultCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList); ModelAPI_Tools::loadDeletedShapes(aResultBaseAlgoList, - aTools.objects(), - aResultCompound); + aTools.objects(), + aResultCompound); // remove the rest results if there were produced in the previous pass removeResults(aResultIndex); diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp index 764a7752f..a10fead97 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -39,6 +40,8 @@ #include #include + +//================================================================================================== static void explodeCompound(const GeomShapePtr& theShape, ListOfShape& theResult) { if (theShape->shapeType() == GeomAPI_Shape::COMPOUND) { @@ -69,6 +72,12 @@ void FeaturesPlugin_BooleanFuse::initAttributes() data()->addAttribute(OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()); data()->addAttribute(TOOL_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()); + data()->addAttribute(FUZZY_PARAM_ID(), ModelAPI_AttributeDouble::typeId()); + // Initialize the fuzzy parameter with a value below Precision::Confusion() to indicate, + // that the internal algorithms should use their default fuzzy value, if none was specified + // by the user. + real(FUZZY_PARAM_ID())->setValue(1.e-8); + data()->addAttribute(REMOVE_INTERSECTION_EDGES_ID(), ModelAPI_AttributeBoolean::typeId()); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), OBJECT_LIST_ID()); @@ -115,6 +124,10 @@ void FeaturesPlugin_BooleanFuse::execute() return; } + // Getting fuzzy parameter. + // Used as additional tolerance to eliminate tiny results. + double aFuzzy = real(FUZZY_PARAM_ID())->value(); + // version of FUSE feature const std::string aFuseVersion = data()->version(); @@ -161,7 +174,7 @@ void FeaturesPlugin_BooleanFuse::execute() GeomShapePtr aCuttedEdgesAndFaces; if (!anEdgesAndFaces.empty()) { std::shared_ptr aCutAlgo(new GeomAlgoAPI_Boolean(anEdgesAndFaces, - anOriginalShapes, GeomAlgoAPI_Tools::BOOL_CUT)); + anOriginalShapes, GeomAlgoAPI_Tools::BOOL_CUT, aFuzzy)); if (aCutAlgo->isDone()) { aCuttedEdgesAndFaces = aCutAlgo->shape(); aMakeShapeList->appendAlgo(aCutAlgo); @@ -181,7 +194,7 @@ void FeaturesPlugin_BooleanFuse::execute() ListOfShape aOneObjectList; aOneObjectList.push_back(*anIt); std::shared_ptr aCutAlgo( - new GeomAlgoAPI_Boolean(aOneObjectList, aShapesToAdd, GeomAlgoAPI_Tools::BOOL_CUT)); + new GeomAlgoAPI_Boolean(aOneObjectList, aShapesToAdd, GeomAlgoAPI_Tools::BOOL_CUT, aFuzzy)); if (GeomAlgoAPI_ShapeTools::area(aCutAlgo->shape()) > 1.e-27) { aSolidsToFuse.push_back(aCutAlgo->shape()); @@ -206,7 +219,8 @@ void FeaturesPlugin_BooleanFuse::execute() } else if ((anObjects.size() + aTools.size()) > 1) { std::shared_ptr aFuseAlgo(new GeomAlgoAPI_Boolean(anObjects, aTools, - GeomAlgoAPI_Tools::BOOL_FUSE)); + GeomAlgoAPI_Tools::BOOL_FUSE, + aFuzzy)); // Checking that the algorithm worked properly. if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aFuseAlgo, getKind(), anError)) { @@ -229,7 +243,7 @@ void FeaturesPlugin_BooleanFuse::execute() aShapesToAdd.push_back(aShape); } std::shared_ptr aFillerAlgo( - new GeomAlgoAPI_PaveFiller(aShapesToAdd, true)); + new GeomAlgoAPI_PaveFiller(aShapesToAdd, true, aFuzzy)); if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aFillerAlgo, getKind(), anError)) { setError(anError); return; diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp index 019d27a31..9f1aca998 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp @@ -20,6 +20,7 @@ #include "FeaturesPlugin_BooleanSmash.h" #include +#include #include #include @@ -33,6 +34,7 @@ #include #include + //================================================================================================== FeaturesPlugin_BooleanSmash::FeaturesPlugin_BooleanSmash() : FeaturesPlugin_Boolean(FeaturesPlugin_Boolean::BOOL_SMASH) @@ -45,6 +47,12 @@ void FeaturesPlugin_BooleanSmash::initAttributes() data()->addAttribute(OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()); data()->addAttribute(TOOL_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()); + data()->addAttribute(FUZZY_PARAM_ID(), ModelAPI_AttributeDouble::typeId()); + // Initialize the fuzzy parameter with a value below Precision::Confusion() to indicate, + // that the internal algorithms should use their default fuzzy value, if none was specified + // by the user. + real(FUZZY_PARAM_ID())->setValue(1.e-8); + initVersion(BOP_VERSION_9_4(), selectionList(OBJECT_LIST_ID()), selectionList(TOOL_LIST_ID())); } @@ -100,13 +108,18 @@ void FeaturesPlugin_BooleanSmash::execute() } } + // Getting fuzzy parameter. + // Used as additional tolerance to eliminate tiny results. + double aFuzzy = real(FUZZY_PARAM_ID())->value(); + std::shared_ptr aMakeShapeList(new GeomAlgoAPI_MakeShapeList()); if (!aShapesToAdd.empty()) { // Cut objects with not used solids. std::shared_ptr anObjectsCutAlgo( new GeomAlgoAPI_Boolean(aShapesToSmash, aShapesToAdd, - GeomAlgoAPI_Tools::BOOL_CUT)); + GeomAlgoAPI_Tools::BOOL_CUT, + aFuzzy)); if (GeomAlgoAPI_ShapeTools::area(anObjectsCutAlgo->shape()) > 1.e-27) { aShapesToSmash.clear(); @@ -118,7 +131,8 @@ void FeaturesPlugin_BooleanSmash::execute() std::shared_ptr aToolsCutAlgo( new GeomAlgoAPI_Boolean(aTools, aShapesToAdd, - GeomAlgoAPI_Tools::BOOL_CUT)); + GeomAlgoAPI_Tools::BOOL_CUT, + aFuzzy)); if (GeomAlgoAPI_ShapeTools::area(aToolsCutAlgo->shape()) > 1.e-27) { aTools.clear(); @@ -131,7 +145,8 @@ void FeaturesPlugin_BooleanSmash::execute() std::shared_ptr aBoolAlgo( new GeomAlgoAPI_Boolean(aShapesToSmash, aTools, - GeomAlgoAPI_Tools::BOOL_CUT)); + GeomAlgoAPI_Tools::BOOL_CUT, + aFuzzy)); // Checking that the algorithm worked properly. if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aBoolAlgo, getKind(), anError)) { @@ -154,7 +169,7 @@ void FeaturesPlugin_BooleanSmash::execute() } else { std::shared_ptr aFillerAlgo( - new GeomAlgoAPI_PaveFiller(aShapesToAdd, true)); + new GeomAlgoAPI_PaveFiller(aShapesToAdd, true, aFuzzy)); if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aFillerAlgo, getKind(), anError)) { setError(anError); return; diff --git a/src/FeaturesPlugin/FeaturesPlugin_Intersection.cpp b/src/FeaturesPlugin/FeaturesPlugin_Intersection.cpp index 4d8705ab5..42dff80df 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Intersection.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Intersection.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,7 @@ #include + static const std::string INTERSECTION_VERSION_1("v9.5"); //================================================================================================= @@ -46,6 +48,12 @@ void FeaturesPlugin_Intersection::initAttributes() AttributePtr anObjectsAttr = data()->addAttribute(OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()); + data()->addAttribute(FUZZY_PARAM_ID(), ModelAPI_AttributeDouble::typeId()); + // Initialize the fuzzy parameter with a value below Precision::Confusion() to indicate, + // that the internal algorithms should use their default fuzzy value, if none was specified + // by the user. + real(FUZZY_PARAM_ID())->setValue(1.e-8); + initVersion(INTERSECTION_VERSION_1, anObjectsAttr, AttributePtr()); } @@ -60,11 +68,15 @@ void FeaturesPlugin_Intersection::execute() return; } + // Getting fuzzy parameter. + // Used as additional tolerance to eliminate tiny results. + double aFuzzy = real(FUZZY_PARAM_ID())->value(); + int aResultIndex = 0; // Create result. const ListOfShape& anObjects = anObjectsHierarchy.objects(); - GeomMakeShapePtr anIntersectionAlgo(new GeomAlgoAPI_Intersection(anObjects)); + GeomMakeShapePtr anIntersectionAlgo(new GeomAlgoAPI_Intersection(anObjects, aFuzzy)); // Checking that the algorithm worked properly. std::string anError; diff --git a/src/FeaturesPlugin/FeaturesPlugin_Intersection.h b/src/FeaturesPlugin/FeaturesPlugin_Intersection.h index 0b0dc9d1c..08e3e7a72 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Intersection.h +++ b/src/FeaturesPlugin/FeaturesPlugin_Intersection.h @@ -48,6 +48,13 @@ public: return MY_OBJECT_LIST_ID; } + /// Attribute name of fuzzy parameter. + inline static const std::string& FUZZY_PARAM_ID() + { + static const std::string MY_FUZZY_PARAM_ID("fuzzy_param"); + return MY_FUZZY_PARAM_ID; + } + /// Returns the kind of a feature. FEATURESPLUGIN_EXPORT virtual const std::string& getKind() { diff --git a/src/FeaturesPlugin/FeaturesPlugin_Partition.cpp b/src/FeaturesPlugin/FeaturesPlugin_Partition.cpp index 46a16c54c..7e1a77c7a 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Partition.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Partition.cpp @@ -20,6 +20,7 @@ #include "FeaturesPlugin_Partition.h" #include +#include #include #include #include @@ -58,6 +59,13 @@ FeaturesPlugin_Partition::FeaturesPlugin_Partition() void FeaturesPlugin_Partition::initAttributes() { data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId()); + + data()->addAttribute(FUZZY_PARAM_ID(), ModelAPI_AttributeDouble::typeId()); + // Initialize the fuzzy parameter with a value below Precision::Confusion() to indicate, + // that the internal algorithms should use their default fuzzy value, if none was specified + // by the user. + real(FUZZY_PARAM_ID())->setValue(1.e-8); + initVersion(BOP_VERSION_9_4(), selectionList(BASE_OBJECTS_ID())); } @@ -75,6 +83,10 @@ void FeaturesPlugin_Partition::execute() return; } + // Getting fuzzy parameter. + // Used as additional tolerance to eliminate tiny results. + double aFuzzy = real(FUZZY_PARAM_ID())->value(); + ListOfShape aBaseObjects = anObjects.objects(); aBaseObjects.insert(aBaseObjects.end(), aPlanes.begin(), aPlanes.end()); @@ -85,7 +97,7 @@ void FeaturesPlugin_Partition::execute() // cut unused solids of composolids from the objects of partition ListOfShape aTargetObjects, anUnusedSubs; std::string aError; - if (!cutSubs(anObjects, aTargetObjects, anUnusedSubs, aMakeShapeList, aError)) { + if (!cutSubs(anObjects, aTargetObjects, anUnusedSubs, aFuzzy, aMakeShapeList, aError)) { setError(aError); return; } @@ -93,7 +105,7 @@ void FeaturesPlugin_Partition::execute() // perform partition first time to split target solids by planes std::shared_ptr aPartitionAlgo( - new GeomAlgoAPI_Partition(aTargetObjects, aPlanes)); + new GeomAlgoAPI_Partition(aTargetObjects, aPlanes, aFuzzy)); // Checking that the algorithm worked properly. if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPartitionAlgo, getKind(), aError)) { @@ -209,9 +221,9 @@ void FeaturesPlugin_Partition::storeResult( //================================================================================================= - static bool cutSubs(ListOfShape& theSubsToCut, const ListOfShape& theTools, + const double theFuzzy, std::shared_ptr& theMakeShapeList, std::string& theError) { @@ -220,7 +232,7 @@ static bool cutSubs(ListOfShape& theSubsToCut, // cut from current list of solids std::shared_ptr aCutAlgo( - new GeomAlgoAPI_Boolean(theSubsToCut, theTools, GeomAlgoAPI_Tools::BOOL_CUT)); + new GeomAlgoAPI_Boolean(theSubsToCut, theTools, GeomAlgoAPI_Tools::BOOL_CUT, theFuzzy)); if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCutAlgo, "", theError)) return false; theMakeShapeList->appendAlgo(aCutAlgo); @@ -233,10 +245,12 @@ static bool cutSubs(ListOfShape& theSubsToCut, return true; } +//================================================================================================= bool FeaturesPlugin_Partition::cutSubs( GeomAPI_ShapeHierarchy& theHierarchy, ListOfShape& theUsed, ListOfShape& theNotUsed, + const double theFuzzy, std::shared_ptr& theMakeShapeList, std::string& theError) { @@ -272,8 +286,8 @@ bool FeaturesPlugin_Partition::cutSubs( else aUsed.push_back(*anIt); - isOk = ::cutSubs(aUsed, aToolsForUsed, theMakeShapeList, theError) - && ::cutSubs(aNotUsed, aToolsForUnused, theMakeShapeList, theError); + isOk = ::cutSubs(aUsed, aToolsForUsed, theFuzzy, theMakeShapeList, theError) + && ::cutSubs(aNotUsed, aToolsForUnused, theFuzzy, theMakeShapeList, theError); if (isOk) { theUsed.insert(theUsed.end(), aUsed.begin(), aUsed.end()); theNotUsed.insert(theNotUsed.end(), aNotUsed.begin(), aNotUsed.end()); diff --git a/src/FeaturesPlugin/FeaturesPlugin_Partition.h b/src/FeaturesPlugin/FeaturesPlugin_Partition.h index 59cd77421..1448ff724 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Partition.h +++ b/src/FeaturesPlugin/FeaturesPlugin_Partition.h @@ -46,6 +46,13 @@ public: return MY_BASE_OBJECTS_ID; } + /// Attribute name of fuzzy parameter. + inline static const std::string& FUZZY_PARAM_ID() + { + static const std::string MY_FUZZY_PARAM_ID("fuzzy_param"); + return MY_FUZZY_PARAM_ID; + } + /// \return the kind of a feature. FEATURESPLUGIN_EXPORT virtual const std::string& getKind() { @@ -76,6 +83,7 @@ private: bool cutSubs(GeomAPI_ShapeHierarchy& theHierarchy, ListOfShape& theUsed, ListOfShape& theNotUsed, + const double theFuzzy, std::shared_ptr& theMakeShapeList, std::string& theError); }; diff --git a/src/FeaturesPlugin/FeaturesPlugin_Union.cpp b/src/FeaturesPlugin/FeaturesPlugin_Union.cpp index 192e15e75..9627e7bf0 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Union.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Union.cpp @@ -29,10 +29,12 @@ #include #include +#include #include #include #include + //================================================================================================= FeaturesPlugin_Union::FeaturesPlugin_Union() { @@ -42,6 +44,13 @@ FeaturesPlugin_Union::FeaturesPlugin_Union() void FeaturesPlugin_Union::initAttributes() { data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId()); + + data()->addAttribute(FUZZY_PARAM_ID(), ModelAPI_AttributeDouble::typeId()); + // Initialize the fuzzy parameter with a value below Precision::Confusion() to indicate, + // that the internal algorithms should use their default fuzzy value, if none was specified + // by the user. + real(FUZZY_PARAM_ID())->setValue(1.e-8); + initVersion(BOP_VERSION_9_4(), selectionList(BASE_OBJECTS_ID())); } @@ -60,6 +69,10 @@ void FeaturesPlugin_Union::execute() return; } + // Getting fuzzy parameter. + // Used as additional tolerance to eliminate tiny results. + double aFuzzy = real(FUZZY_PARAM_ID())->value(); + std::string anError; int aResultIndex = 0; std::vector aResultBaseAlgoList; @@ -81,12 +94,14 @@ void FeaturesPlugin_Union::execute() // compsolid handling isOk = processCompsolid(GeomAlgoAPI_Tools::BOOL_FUSE, anObjects, aParent, anEmptyList, anEmptyList, + aFuzzy, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } else { // process object as is isOk = processObject(GeomAlgoAPI_Tools::BOOL_FUSE, anObject, anEmptyList, anEmptyList, + aFuzzy, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } diff --git a/src/FeaturesPlugin/FeaturesPlugin_Union.h b/src/FeaturesPlugin/FeaturesPlugin_Union.h index 99b7369a5..52688310a 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Union.h +++ b/src/FeaturesPlugin/FeaturesPlugin_Union.h @@ -43,6 +43,13 @@ public: return MY_BASE_OBJECTS_ID; } + /// Attribute name of fuzzy parameter. + inline static const std::string& FUZZY_PARAM_ID() + { + static const std::string MY_FUZZY_PARAM_ID("fuzzy_param"); + return MY_FUZZY_PARAM_ID; + } + /// \return the kind of a feature. FEATURESPLUGIN_EXPORT virtual const std::string& getKind() { diff --git a/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.cpp b/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.cpp index 3270605e8..e748063bb 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.cpp @@ -46,10 +46,13 @@ #include #include + +//================================================================================================= static void performBoolean(const GeomAlgoAPI_Tools::BOPType theBooleanType, GeomMakeShapePtr& theBooleanAlgo, const ListOfShape& theObjects, - const ListOfShape& theTools) + const ListOfShape& theTools, + const double theFuzzy) { if (theBooleanType == GeomAlgoAPI_Tools::BOOL_PARTITION) theBooleanAlgo.reset(new GeomAlgoAPI_Partition(theObjects, theTools)); @@ -62,11 +65,11 @@ static void performBoolean(const GeomAlgoAPI_Tools::BOPType theBooleanType, ListOfShape anObjects = theObjects; ListOfShape aTools; aTools.splice(aTools.begin(), anObjects, anObjects.begin()); - theBooleanAlgo.reset(new GeomAlgoAPI_Boolean(anObjects, aTools, theBooleanType)); + theBooleanAlgo.reset(new GeomAlgoAPI_Boolean(anObjects, aTools, theBooleanType, theFuzzy)); } } else - theBooleanAlgo.reset(new GeomAlgoAPI_Boolean(theObjects, theTools, theBooleanType)); + theBooleanAlgo.reset(new GeomAlgoAPI_Boolean(theObjects, theTools, theBooleanType, theFuzzy)); } } @@ -122,6 +125,7 @@ bool FeaturesPlugin_VersionedBoolean::processObject( const GeomShapePtr& theObject, const ListOfShape& theTools, const ListOfShape& thePlanes, + const double theFuzzy, int& theResultIndex, std::vector& theResultBaseAlgoList, ListOfShape& theResultShapesList, @@ -140,11 +144,12 @@ bool FeaturesPlugin_VersionedBoolean::processObject( aToolsWithPlanes.insert(aToolsWithPlanes.end(), aPlanesCopy.begin(), aPlanesCopy.end()); if (theBooleanType == GeomAlgoAPI_Tools::BOOL_PARTITION) - aBoolAlgo.reset(new GeomAlgoAPI_Partition(aListWithObject, aToolsWithPlanes)); + aBoolAlgo.reset(new GeomAlgoAPI_Partition(aListWithObject, aToolsWithPlanes, theFuzzy)); else aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aListWithObject, aToolsWithPlanes, - theBooleanType)); + theBooleanType, + theFuzzy)); // Checking that the algorithm worked properly. std::string anError; @@ -214,6 +219,7 @@ bool FeaturesPlugin_VersionedBoolean::processCompsolid( const GeomShapePtr& theCompsolid, const ListOfShape& theTools, const ListOfShape& thePlanes, + const double theFuzzy, int& theResultIndex, std::vector& theResultBaseAlgoList, ListOfShape& theResultShapesList, @@ -232,7 +238,7 @@ bool FeaturesPlugin_VersionedBoolean::processCompsolid( aToolsWithPlanes.insert(aToolsWithPlanes.end(), aPlanesCopy.begin(), aPlanesCopy.end()); std::shared_ptr aBoolAlgo; - performBoolean(theBooleanType, aBoolAlgo, aUsedInOperationSolids, aToolsWithPlanes); + performBoolean(theBooleanType, aBoolAlgo, aUsedInOperationSolids, aToolsWithPlanes, theFuzzy); // Checking that the algorithm worked properly. std::string anError; @@ -251,7 +257,7 @@ bool FeaturesPlugin_VersionedBoolean::processCompsolid( ListOfShape aShapesToAdd = aNotUsedSolids; aShapesToAdd.push_back(aBoolAlgo->shape()); std::shared_ptr aFillerAlgo( - new GeomAlgoAPI_PaveFiller(aShapesToAdd, true)); + new GeomAlgoAPI_PaveFiller(aShapesToAdd, true, theFuzzy)); if (!aFillerAlgo->isDone()) { std::string aFeatureError = "Error: PaveFiller algorithm failed."; setError(aFeatureError); @@ -308,6 +314,7 @@ bool FeaturesPlugin_VersionedBoolean::processCompound( GeomAPI_ShapeHierarchy& theCompoundHierarchy, const GeomShapePtr& theCompound, const ListOfShape& theTools, + const double theFuzzy, int& theResultIndex, std::vector& theResultBaseAlgoList, ListOfShape& theResultShapesList, @@ -324,7 +331,7 @@ bool FeaturesPlugin_VersionedBoolean::processCompound( std::shared_ptr aMakeShapeList(new GeomAlgoAPI_MakeShapeList()); std::shared_ptr aBoolAlgo; - performBoolean(theBooleanType, aBoolAlgo, aUsedInOperationShapes, theTools); + performBoolean(theBooleanType, aBoolAlgo, aUsedInOperationShapes, theTools, theFuzzy); // Checking that the algorithm worked properly. std::string anError; diff --git a/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.h b/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.h index eb5336fa1..e58945733 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.h +++ b/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.h @@ -70,6 +70,7 @@ protected: const GeomShapePtr& theObject, const ListOfShape& theTools, const ListOfShape& thePlanes, + const double theFuzzy, int& theResultIndex, std::vector& theResultBaseAlgoList, ListOfShape& theResultShapesList, @@ -84,6 +85,7 @@ protected: const GeomShapePtr& theCompsolid, const ListOfShape& theTools, const ListOfShape& thePlanes, + const double theFuzzy, int& theResultIndex, std::vector& theResultBaseAlgoList, ListOfShape& theResultShapesList, @@ -97,6 +99,7 @@ protected: GeomAPI_ShapeHierarchy& theCompoundHierarchy, const GeomShapePtr& theCompound, const ListOfShape& theTools, + const double theFuzzy, int& theResultIndex, std::vector& theResultBaseAlgoList, ListOfShape& theResultShapesList, diff --git a/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts b/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts index e2e2f20bb..9fa48e57f 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts +++ b/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts @@ -332,6 +332,17 @@ Objets outils + + Common:fuzzy_param + + Fuzzy parameter + Paramètre flou + + + Additional tolerance to eliminate tiny result. + Tolérance supplémentaire pour éliminer les petits résultats. + + Model_Data @@ -385,6 +396,17 @@ Objets outils + + Cut:fuzzy_param + + Fuzzy parameter + Paramètre flou + + + Additional tolerance to eliminate tiny result. + Tolérance supplémentaire pour éliminer les petits résultats. + + @@ -1219,6 +1241,17 @@ Objets outils + + Fuse:fuzzy_param + + Fuzzy Parameter + Paramètre flou + + + Additional tolerance to eliminate tiny result. + Tolérance supplémentaire pour éliminer les petits résultats. + + @@ -1282,6 +1315,17 @@ Sélectionner des objets. + + Intersection:fuzzy_param + + Fuzzy parameter + Paramètre flou + + + Additional tolerance to eliminate tiny result. + Tolérance supplémentaire pour éliminer les petits résultats. + + @@ -1325,6 +1369,17 @@ Sélectionner des objets pour le partitionnement. + + Partition:fuzzy_param + + Fuzzy parameter + Paramètre flou + + + Additional tolerance to eliminate tiny result. + Tolérance supplémentaire pour éliminer les petits résultats. + + @@ -2305,6 +2360,17 @@ Objets outils + + Smash:fuzzy_param + + Fuzzy parameter + Paramètre flou + + + Additional tolerance to eliminate tiny result. + Tolérance supplémentaire pour éliminer les petits résultats. + + @@ -2347,6 +2413,17 @@ Objets outils + + Split:fuzzy_param + + Fuzzy parameter + Paramètre flou + + + Additional tolerance to eliminate tiny result. + Tolérance supplémentaire pour éliminer les petits résultats. + + @@ -2371,6 +2448,17 @@ Sélectionner les solides pour la réunion. + + Union:fuzzy_param + + Fuzzy parameter + Paramètre flou + + + Additional tolerance to eliminate tiny result. + Tolérance supplémentaire pour éliminer les petits résultats. + + @@ -3845,6 +3933,17 @@ La forme sélectionnée est du mauvais type. + + Boolean:fuzzy_param + + Fuzzy parameter + Paramètre flou + + + Additional tolerance to eliminate tiny result. + Tolérance supplémentaire pour éliminer les petits résultats. + + Boolean:GeomValidators_BooleanArguments diff --git a/src/FeaturesPlugin/FeaturesPlugin_msg_ru.ts b/src/FeaturesPlugin/FeaturesPlugin_msg_ru.ts index e27770699..ee42e757c 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_msg_ru.ts +++ b/src/FeaturesPlugin/FeaturesPlugin_msg_ru.ts @@ -109,7 +109,7 @@ Error: Empty shape. Выбранные вспомогательные объекты невалидны. - + Error: Local selection not allowed. Локальная селекция запрещена. @@ -119,6 +119,17 @@ Выбраныне вспомогательные объекты имеют недопустимый тип. + + Boolean:fuzzy_param + + Fuzzy parameter + Нечеткий параметр + + + Additional tolerance to eliminate tiny result. + Дополнительный допуск для устранения крошечного результата. + + Boolean:GeomValidators_BooleanArguments diff --git a/src/FeaturesPlugin/Test/TestBooleanCommon_Fuzzy.py b/src/FeaturesPlugin/Test/TestBooleanCommon_Fuzzy.py new file mode 100644 index 000000000..9d01e2482 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestBooleanCommon_Fuzzy.py @@ -0,0 +1,80 @@ +# Copyright (C) 2014-2022 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from salome.shaper import model +from GeomAPI import GeomAPI_Shape + +aShapeTypes = { + GeomAPI_Shape.SOLID: "GeomAPI_Shape.SOLID", + GeomAPI_Shape.FACE: "GeomAPI_Shape.FACE", + GeomAPI_Shape.EDGE: "GeomAPI_Shape.EDGE", + GeomAPI_Shape.VERTEX: "GeomAPI_Shape.VERTEX"} + +def testNbUniqueSubShapes(theFeature, theShapeType, theExpectedNbSubShapes): + """ Tests number of unique feature sub-shapes of passed type for each result. + :param theFeature: feature to test. + :param theShapeType: shape type of sub-shapes to test. + :param theExpectedNbSubShapes: list of sub-shapes numbers. Size of list should be equal to len(theFeature.results()). + """ + aResults = theFeature.feature().results() + aNbResults = len(aResults) + aListSize = len(theExpectedNbSubShapes) + assert (aNbResults == aListSize), "Number of results: {} not equal to list size: {}.".format(aNbResults, aListSize) + for anIndex in range(0, aNbResults): + aNbResultSubShapes = 0 + anExpectedNbSubShapes = theExpectedNbSubShapes[anIndex] + aNbResultSubShapes = aResults[anIndex].shape().subShapes(theShapeType, True).size() + assert (aNbResultSubShapes == anExpectedNbSubShapes), "Number of sub-shapes of type {} for result[{}]: {}. Expected: {}.".format(aShapeTypes[theShapeType], anIndex, aNbResultSubShapes, anExpectedNbSubShapes) + + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Param_fuzzy = model.addParameter(Part_1_doc, "fuzzy", '1e-06') + +### Create Sphere +Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), 5) + +### Create Point +Point_2 = model.addPoint(Part_1_doc, 9.999995, 0, 0) + +### Create Sphere +Sphere_2 = model.addSphere(Part_1_doc, model.selection("VERTEX", "Point_1"), 5) + +### Create Common +Common_1 = model.addCommon(Part_1_doc, [model.selection("SOLID", "Sphere_2_1"), model.selection("SOLID", "Sphere_1_1")], fuzzyParam = "fuzzy", keepSubResults = True) +model.do() + +model.testNbResults(Common_1, 1) +model.testNbSubResults(Common_1, [0]) +testNbUniqueSubShapes(Common_1, GeomAPI_Shape.SOLID, [1]) +testNbUniqueSubShapes(Common_1, GeomAPI_Shape.FACE, [3]) +testNbUniqueSubShapes(Common_1, GeomAPI_Shape.EDGE, [3]) +testNbUniqueSubShapes(Common_1, GeomAPI_Shape.VERTEX, [2]) + +### Set a higher fuzzy value +Param_fuzzy.setValue(1.e-5) +model.do() + +model.end() + +model.testNbResults(Common_1, 0) + +model.end() diff --git a/src/FeaturesPlugin/Test/TestBooleanCut_Fuzzy_1.py b/src/FeaturesPlugin/Test/TestBooleanCut_Fuzzy_1.py new file mode 100644 index 000000000..d880a3280 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestBooleanCut_Fuzzy_1.py @@ -0,0 +1,89 @@ +# Copyright (C) 2014-2022 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from salome.shaper import model +from GeomAPI import GeomAPI_Shape + +aShapeTypes = { + GeomAPI_Shape.SOLID: "GeomAPI_Shape.SOLID", + GeomAPI_Shape.FACE: "GeomAPI_Shape.FACE", + GeomAPI_Shape.EDGE: "GeomAPI_Shape.EDGE", + GeomAPI_Shape.VERTEX: "GeomAPI_Shape.VERTEX"} + +def testNbUniqueSubShapes(theFeature, theShapeType, theExpectedNbSubShapes): + """ Tests number of unique feature sub-shapes of passed type for each result. + :param theFeature: feature to test. + :param theShapeType: shape type of sub-shapes to test. + :param theExpectedNbSubShapes: list of sub-shapes numbers. Size of list should be equal to len(theFeature.results()). + """ + aResults = theFeature.feature().results() + aNbResults = len(aResults) + aListSize = len(theExpectedNbSubShapes) + assert (aNbResults == aListSize), "Number of results: {} not equal to list size: {}.".format(aNbResults, aListSize) + for anIndex in range(0, aNbResults): + aNbResultSubShapes = 0 + anExpectedNbSubShapes = theExpectedNbSubShapes[anIndex] + aNbResultSubShapes = aResults[anIndex].shape().subShapes(theShapeType, True).size() + assert (aNbResultSubShapes == anExpectedNbSubShapes), "Number of sub-shapes of type {} for result[{}]: {}. Expected: {}.".format(aShapeTypes[theShapeType], anIndex, aNbResultSubShapes, anExpectedNbSubShapes) + + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Param_offset = model.addParameter(Part_1_doc, "offset", '5e-5') +Param_fuzzy = model.addParameter(Part_1_doc, "fuzzy", '1e-05') + +### Create Point +Point_2 = model.addPoint(Part_1_doc, "offset", "5", "5") + +### Create Box +Box_1 = model.addBox(Part_1_doc, 10, 10, 10) +Box_1.result().setColor(255, 0, 0) + +### Create Cylinder +Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "Point_1"), model.selection("EDGE", "PartSet/OX"), 6, 13) +Cylinder_1.result().setColor(255, 255, 0) +Cylinder_1.result().setTransparency(0.6) + +### Create Cut +Cut_1 = model.addCut(Part_1_doc, [model.selection("SOLID", "Box_1_1")], [model.selection("SOLID", "Cylinder_1_1")], fuzzyParam = "fuzzy", keepSubResults = True) +model.do() + +model.testNbResults(Cut_1, 1) +model.testNbSubResults(Cut_1, [0]) +testNbUniqueSubShapes(Cut_1, GeomAPI_Shape.SOLID, [1]) +testNbUniqueSubShapes(Cut_1, GeomAPI_Shape.FACE, [14]) +testNbUniqueSubShapes(Cut_1, GeomAPI_Shape.EDGE, [36]) +testNbUniqueSubShapes(Cut_1, GeomAPI_Shape.VERTEX, [24]) +model.testResultsVolumes(Cut_1, [49.093623770546]) + +### Set a higher fuzzy value +Param_fuzzy.setValue(5.e-5) +model.do() + +model.end() + +model.testNbResults(Cut_1, 1) +model.testNbSubResults(Cut_1, [4]) +testNbUniqueSubShapes(Cut_1, GeomAPI_Shape.SOLID, [4]) +testNbUniqueSubShapes(Cut_1, GeomAPI_Shape.FACE, [20]) +testNbUniqueSubShapes(Cut_1, GeomAPI_Shape.EDGE, [36]) +testNbUniqueSubShapes(Cut_1, GeomAPI_Shape.VERTEX, [24]) +model.testResultsVolumes(Cut_1, [49.088834629314]) diff --git a/src/FeaturesPlugin/Test/TestBooleanCut_Fuzzy_2.py b/src/FeaturesPlugin/Test/TestBooleanCut_Fuzzy_2.py new file mode 100644 index 000000000..61a26425a --- /dev/null +++ b/src/FeaturesPlugin/Test/TestBooleanCut_Fuzzy_2.py @@ -0,0 +1,132 @@ +# Copyright (C) 2014-2022 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from salome.shaper import model +from GeomAPI import GeomAPI_Shape + +aShapeTypes = { + GeomAPI_Shape.SOLID: "GeomAPI_Shape.SOLID", + GeomAPI_Shape.FACE: "GeomAPI_Shape.FACE", + GeomAPI_Shape.EDGE: "GeomAPI_Shape.EDGE", + GeomAPI_Shape.VERTEX: "GeomAPI_Shape.VERTEX"} + +def testNbUniqueSubShapes(theFeature, theShapeType, theExpectedNbSubShapes): + """ Tests number of unique feature sub-shapes of passed type for each result. + :param theFeature: feature to test. + :param theShapeType: shape type of sub-shapes to test. + :param theExpectedNbSubShapes: list of sub-shapes numbers. Size of list should be equal to len(theFeature.results()). + """ + aResults = theFeature.feature().results() + aNbResults = len(aResults) + aListSize = len(theExpectedNbSubShapes) + assert (aNbResults == aListSize), "Number of results: {} not equal to list size: {}.".format(aNbResults, aListSize) + for anIndex in range(0, aNbResults): + aNbResultSubShapes = 0 + anExpectedNbSubShapes = theExpectedNbSubShapes[anIndex] + aNbResultSubShapes = aResults[anIndex].shape().subShapes(theShapeType, True).size() + assert (aNbResultSubShapes == anExpectedNbSubShapes), "Number of sub-shapes of type {} for result[{}]: {}. Expected: {}.".format(aShapeTypes[theShapeType], anIndex, aNbResultSubShapes, anExpectedNbSubShapes) + + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Param_fuzzy = model.addParameter(Part_1_doc, "fuzzy", '1e-07') + +### Create Point +Point_2 = model.addPoint(Part_1_doc, 5, 9.9999, 0) + +### Create Point +Point_3 = model.addPoint(Part_1_doc, 10, 10, 0) + +### Create Sketch +Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY")) +SketchLine_1 = Sketch_1.addLine(5, 0, 0, 0) +SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False) +SketchPoint_1 = SketchProjection_1.createdFeature() +Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchPoint_1.result()) +SketchLine_2 = Sketch_1.addLine(0, 0, 0, 9.9999) +SketchLine_3 = Sketch_1.addLine(0, 9.9999, 5, 9.9999) +SketchLine_4 = Sketch_1.addLine(5, 9.9999, 5, 0) +Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint()) +Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint()) +Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint()) +Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint()) +Sketch_1.setHorizontal(SketchLine_1.result()) +Sketch_1.setVertical(SketchLine_2.result()) +Sketch_1.setHorizontal(SketchLine_3.result()) +Sketch_1.setVertical(SketchLine_4.result()) +SketchProjection_2 = Sketch_1.addProjection(model.selection("VERTEX", "Point_1"), False) +SketchPoint_2 = SketchProjection_2.createdFeature() +Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchPoint_2.result()) +SketchProjection_3 = Sketch_1.addProjection(model.selection("VERTEX", "Point_2"), False) +SketchPoint_3 = SketchProjection_3.createdFeature() +model.do() + +### Create Sketch +Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY")) +SketchLine_5 = Sketch_2.addLine(10, 0, 0, 0) +SketchProjection_4 = Sketch_2.addProjection(model.selection("VERTEX", "PartSet/Origin"), False) +SketchPoint_4 = SketchProjection_4.createdFeature() +Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchPoint_4.result()) +SketchLine_6 = Sketch_2.addLine(0, 0, 0, 10) +SketchLine_7 = Sketch_2.addLine(0, 10, 10, 10) +SketchLine_8 = Sketch_2.addLine(10, 10, 10, 0) +Sketch_2.setCoincident(SketchLine_8.endPoint(), SketchLine_5.startPoint()) +Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint()) +Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint()) +Sketch_2.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint()) +Sketch_2.setHorizontal(SketchLine_5.result()) +Sketch_2.setVertical(SketchLine_6.result()) +Sketch_2.setHorizontal(SketchLine_7.result()) +Sketch_2.setVertical(SketchLine_8.result()) +SketchProjection_5 = Sketch_2.addProjection(model.selection("VERTEX", "Point_2"), False) +SketchPoint_5 = SketchProjection_5.createdFeature() +Sketch_2.setCoincident(SketchLine_7.endPoint(), SketchPoint_5.result()) +model.do() + +### Create Face +Face_1 = model.addFace(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")]) +Face_1.result().setColor(255, 0, 0) + +### Create Face +Face_2 = model.addFace(Part_1_doc, [model.selection("COMPOUND", "Sketch_2")]) +Face_2.result().setColor(0, 255, 0) + +### Create Cut +Cut_1 = model.addCut(Part_1_doc, [model.selection("FACE", "Face_2_1")], [model.selection("FACE", "Face_1_1")], fuzzyParam = "fuzzy", keepSubResults = True) +model.do() + +model.testNbResults(Cut_1, 1) +model.testNbSubResults(Cut_1, [0]) +testNbUniqueSubShapes(Cut_1, GeomAPI_Shape.FACE, [1]) +testNbUniqueSubShapes(Cut_1, GeomAPI_Shape.EDGE, [6]) +testNbUniqueSubShapes(Cut_1, GeomAPI_Shape.VERTEX, [6]) + +### Set a higher fuzzy value +Param_fuzzy.setValue(1.e-4) +model.do() + +model.end() + +model.testNbResults(Cut_1, 1) +model.testNbSubResults(Cut_1, [0]) +testNbUniqueSubShapes(Cut_1, GeomAPI_Shape.FACE, [1]) +testNbUniqueSubShapes(Cut_1, GeomAPI_Shape.EDGE, [4]) +testNbUniqueSubShapes(Cut_1, GeomAPI_Shape.VERTEX, [4]) diff --git a/src/FeaturesPlugin/Test/TestBooleanFuse_Fuzzy.py b/src/FeaturesPlugin/Test/TestBooleanFuse_Fuzzy.py new file mode 100644 index 000000000..6a8535664 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestBooleanFuse_Fuzzy.py @@ -0,0 +1,85 @@ +# Copyright (C) 2014-2022 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from salome.shaper import model +from GeomAPI import GeomAPI_Shape + +aShapeTypes = { + GeomAPI_Shape.SOLID: "GeomAPI_Shape.SOLID", + GeomAPI_Shape.FACE: "GeomAPI_Shape.FACE", + GeomAPI_Shape.EDGE: "GeomAPI_Shape.EDGE", + GeomAPI_Shape.VERTEX: "GeomAPI_Shape.VERTEX"} + +def testNbUniqueSubShapes(theFeature, theShapeType, theExpectedNbSubShapes): + """ Tests number of unique feature sub-shapes of passed type for each result. + :param theFeature: feature to test. + :param theShapeType: shape type of sub-shapes to test. + :param theExpectedNbSubShapes: list of sub-shapes numbers. Size of list should be equal to len(theFeature.results()). + """ + aResults = theFeature.feature().results() + aNbResults = len(aResults) + aListSize = len(theExpectedNbSubShapes) + assert (aNbResults == aListSize), "Number of results: {} not equal to list size: {}.".format(aNbResults, aListSize) + for anIndex in range(0, aNbResults): + aNbResultSubShapes = 0 + anExpectedNbSubShapes = theExpectedNbSubShapes[anIndex] + aNbResultSubShapes = aResults[anIndex].shape().subShapes(theShapeType, True).size() + assert (aNbResultSubShapes == anExpectedNbSubShapes), "Number of sub-shapes of type {} for result[{}]: {}. Expected: {}.".format(aShapeTypes[theShapeType], anIndex, aNbResultSubShapes, anExpectedNbSubShapes) + + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Param_fuzzy = model.addParameter(Part_1_doc, "fuzzy", '1e-07') + +Point_2 = model.addPoint(Part_1_doc, 10, 0, 0) +Point_3 = model.addPoint(Part_1_doc, 20, 10.0001, 10.0001) + +### Create Box +Box_1 = model.addBox(Part_1_doc, 10, 10, 10) + +### Create Box +Box_2 = model.addBox(Part_1_doc, model.selection("VERTEX", "Point_1"), model.selection("VERTEX", "Point_2")) + +### Create Fuse +Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Box_1_1"), model.selection("SOLID", "Box_2_1")], fuzzyParam = "fuzzy", keepSubResults = True) +model.do() + +model.testNbResults(Fuse_1, 1) +model.testNbSubResults(Fuse_1, [0]) +testNbUniqueSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [1]) +testNbUniqueSubShapes(Fuse_1, GeomAPI_Shape.FACE, [11]) +testNbUniqueSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [24]) +testNbUniqueSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [15]) +model.testResultsVolumes(Fuse_1, [2000.02000010]) + +### Set a higher fuzzy value +Param_fuzzy.setValue(1.e-4) +model.do() + +model.end() + +model.testNbResults(Fuse_1, 1) +model.testNbSubResults(Fuse_1, [0]) +testNbUniqueSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [1]) +testNbUniqueSubShapes(Fuse_1, GeomAPI_Shape.FACE, [10]) +testNbUniqueSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [20]) +testNbUniqueSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [12]) +model.testResultsVolumes(Fuse_1, [2000.02166677]) diff --git a/src/FeaturesPlugin/boolean_common_widget.xml b/src/FeaturesPlugin/boolean_common_widget.xml index ebf6cf1b1..c34682a3d 100644 --- a/src/FeaturesPlugin/boolean_common_widget.xml +++ b/src/FeaturesPlugin/boolean_common_widget.xml @@ -38,6 +38,17 @@ + + + + + diff --git a/src/FeaturesPlugin/boolean_fuse_widget.xml b/src/FeaturesPlugin/boolean_fuse_widget.xml index 8617460db..1e9635a60 100644 --- a/src/FeaturesPlugin/boolean_fuse_widget.xml +++ b/src/FeaturesPlugin/boolean_fuse_widget.xml @@ -38,6 +38,17 @@ + + + + + + + + + + diff --git a/src/FeaturesPlugin/boolean_split_widget.xml b/src/FeaturesPlugin/boolean_split_widget.xml index 2131c8dda..7db9399c1 100644 --- a/src/FeaturesPlugin/boolean_split_widget.xml +++ b/src/FeaturesPlugin/boolean_split_widget.xml @@ -19,5 +19,16 @@ + + + + + diff --git a/src/FeaturesPlugin/boolean_widget.xml b/src/FeaturesPlugin/boolean_widget.xml index dca9d22a9..222e8007e 100644 --- a/src/FeaturesPlugin/boolean_widget.xml +++ b/src/FeaturesPlugin/boolean_widget.xml @@ -19,6 +19,17 @@ + + + + + diff --git a/src/FeaturesPlugin/doc/booleanArguments.rst b/src/FeaturesPlugin/doc/booleanArguments.rst index ad2f3c307..1de32398b 100644 --- a/src/FeaturesPlugin/doc/booleanArguments.rst +++ b/src/FeaturesPlugin/doc/booleanArguments.rst @@ -68,3 +68,8 @@ Construction planes (mentioned PLANE) can be used in several operations, but not | |union.icon| | 3 (SOLIDs from COMPSOLID) | --- | | :ref:`featureUnion` | | | +-------------------------+---------------------------+-------------------------+ + +The fuzzy parameter of each boolean operation is used as an additional tolerance to eliminate tiny results. + +*Note*: If a value is given, which is smaller than the lowest meaningful tolerance of 1.e-7, the boolean operation +will use the default internal fuzzy parameter. diff --git a/src/FeaturesPlugin/doc/commonFeature.rst b/src/FeaturesPlugin/doc/commonFeature.rst index a63df77cd..e96f00124 100644 --- a/src/FeaturesPlugin/doc/commonFeature.rst +++ b/src/FeaturesPlugin/doc/commonFeature.rst @@ -39,14 +39,16 @@ Simple - **Objects** contains a list of objects selected in the Object Browser or in the Viewer. If a subshape that belongs to a compsolid/compound was selected, other shapes of this compsolid/compound will be ignored. +- **Fuzzy Parameter** defines the additional tolerance value used to eliminate tiny results. - **See preview** button shows a result of the operation. **TUI Command**: -.. py:function:: model.addCommon(Part_doc, objects) +.. py:function:: model.addCommon(Part_doc, objects, fuzzy) :param part: The current part object :param list: A list of objects. + :param real: Additional tolerance used to eliminate tiny results (optional). :return: Created object Result @@ -74,17 +76,19 @@ Advanced other objects (to avoid self-intersection) and added to the result. - **Tools** contains a list of objects selected in the Object Browser or in the Viewer, which will be intersected with tool objects. If a subshape that belongs to a compsolid/compound was selected, other shapes of this compsolid/compound will be ignored. +- **Fuzzy Parameter** defines the additional tolerance value used to eliminate tiny results. - **See preview** button shows a result of the operation. Any kind of shape is supported as an object or a tool of Common. Moreover, constructions planes can be selected as tools. **TUI Command**: -.. py:function:: model.addCommon(Part_doc, objects, tools) +.. py:function:: model.addCommon(Part_doc, objects, tools, fuzzy) :param part: The current part object :param list: A list of objects. :param list: A list of tools. + :param real: Additional tolerance used to eliminate tiny results (optional). :return: Created object Result diff --git a/src/FeaturesPlugin/doc/cutFeature.rst b/src/FeaturesPlugin/doc/cutFeature.rst index 9ce390dbe..6fe34e58e 100644 --- a/src/FeaturesPlugin/doc/cutFeature.rst +++ b/src/FeaturesPlugin/doc/cutFeature.rst @@ -26,17 +26,19 @@ The following property panel will be opened: - **Tool Objects** contains a list of objects selected in the Object Browser or in the Viewer, which will cut main objects. Any kind of shape can be selected, including subshapes of compsolids/compounds. Non-selected subshapes from compsolids/compounds will be ignored. +- **Fuzzy Parameter** defines the additional tolerance value used to eliminate tiny results. - **See preview** button shows a result of the operation. The minimal dimension of Tool Objects should be not less than the maximal dimension of Main Objects. **TUI Command**: -.. py:function:: model.addCut(Part_doc, mainObjects, toolObjects) +.. py:function:: model.addCut(Part_doc, mainObjects, toolObjects, fuzzy) :param part: The current part object :param list: A list of main objects. :param list: A list of tool objects. + :param real: Additional tolerance used to eliminate tiny results (optional). :return: Created object Result diff --git a/src/FeaturesPlugin/doc/fuseFeature.rst b/src/FeaturesPlugin/doc/fuseFeature.rst index e9fb69620..e3bed7114 100644 --- a/src/FeaturesPlugin/doc/fuseFeature.rst +++ b/src/FeaturesPlugin/doc/fuseFeature.rst @@ -40,15 +40,17 @@ Simple - **Objects** - contains a list of objects selected in the Object Browser or in the Viewer, which will be fused to a single result. If a subshape that belongs to a compsolid/compound was selected, other shapes of this compsolid/compound will cut the fuse shape then will be joined to the result. - **Remove intersection edges** - if enabled, edges that lie on the same surface will be removed. +- **Fuzzy Parameter** - defines the additional tolerance value used to eliminate tiny results. - **See preview** - button shows a result of the operation. **TUI Command**: -.. py:function:: model.addFuse(Part_doc, objects, isRemoveEdges) +.. py:function:: model.addFuse(Part_doc, objects, isRemoveEdges, fuzzyParam) :param part: The current part object. :param list: A list of objects. :param boolean: Remove edges flag (optional). + :param real: Additional tolerance used to eliminate tiny results (optional). :return: Created object. Result @@ -77,16 +79,18 @@ Advanced - **Tools** - contains a list of objects selected in the Object Browser or in the Viewer, which will be fused with tool objects. If a subshape that belongs to a compsolid/compound was selected, other shapes of this compsolid/compound will be ignored. - **Remove intersection edges** - if enabled, edges that lie on the same surface will be removed. +- **Fuzzy Parameter** - defines the additional tolerance value used to eliminate tiny results. - **See preview** - button shows a result of the operation. **TUI Command**: -.. py:function:: model.addFuse(Part_doc, objects, tools, isRemoveEdges) +.. py:function:: model.addFuse(Part_doc, objects, tools, isRemoveEdges, fuzzyParam) :param part: The current part object. :param list: A list of objects. :param list: A list of tools. :param boolean: Remove edges flag (optional). + :param real: Additional tolerance used to eliminate tiny results (optional). :return: Created object. Result diff --git a/src/FeaturesPlugin/doc/images/Partition.png b/src/FeaturesPlugin/doc/images/Partition.png index 70fb721a2fcd00a43c577092d2af54d887be3174..02499b2b9c4bd333f1dac95d40af5d5c15e86d56 100644 GIT binary patch literal 10116 zcmeHtXH-ZM#R#uJ;|yfwH5yxvi6>owKPPG5iT9UR6Ic=Ks8qEWo=83uNfEP_mpZw+-1M?O zHMpub;-1@2z9&h!_I%1WDsPj*)lkRt8-4yrdS3L3WfF&a?6*V-r+`@Pgjhw6BoUWS zc5kV%X)zLfBh5S@LClV?HG(NlA%tAD(6pA_dw+AinGUmCz?9Vb>f#2OpVlGLudkG^ zYhc`6*ARDiRByd!YxF>wsbib>t0T@s;0~fE{l<%igPhwRWT$83ZARL>cgDDypVLIKCyqw#Ursl>(9mxFz%~~w6hQ$wpZpI79i`tH6 zrxp1edT<+-W^XPH@fYzSnSGBAKG}?XZV;-cm9u2>!;mzb2lyRa+@D`1>gBd$v)|sZ zeX<>sB=e8M_}pzb0RtcJ-Zr{uFqo~)mSa-=^qy~Ymaqvy_+kg{NV0ar_I#nw5)7{W za>SVg4t3h^Z`eXe8D=La{jb_)s>L8Ti2YW^s)_QWC=ddUvnt=?_)`cYF8j`ei@m?s z7$CWfytlWG^b5-W`uS{$W!HCOzqTW3E#kJKmZqoVm!8 zjcIlXzPzIu^1IwLkspzW-(K#o^Mg~__C1Qrg}z`-dvQ!Mo>9ij?H*$~muwcOn0Y1j z;0a=~@5>1CoTT%@4PHP9G&HKt{LarVe%p$%sBkaWs6pLpkL7jz&JnkO>0qN!i@ic` z20ofp-;vteUKu-YKx-(Gr(al*6k^L5yp4F+9;<;)Cd+(}k96LvP;%=RBy1{B%8m5$XXwZDF2A71e%@ zLjya6K#^-!dS^6aX_D%_(|ngdx$H@o(=vzAr_H?E6Nypv-H4{Aa6kF!Bsix>PT#!P z)zii_w0sUkGsGg~a_-arUmK#A05OZzyB>KjzB2%KEmPR$J4hWUA_Zz>=W#&X{de@s z<9q(XOIHneuHgf&?c(S%&FhC|Ya?W~O;U97lCQbwjGJDQQ}Pi~e0A~IBDALIEGAsm zaTCY?b&tLf{QT@0F*;I{bgd`%Ma?yHf6`;OBvO+iL&@;B9IhgEzAU7YZ7YXF-sPDC z34!yjahlfe)FTRyczIinH^>HmRypsTanJdFwQuq5=TF`{vX~UK%Z%8BTF8Fq`=KbZ z*}%#Tuc0s}z^r%l<5O)Zlgtg;74ck}dfSP#^@rX1<~{iKhmD_^W+%S3sAKQ&o2pdT z6Jg&E~1{HN*;_RlZs zRM#ce=DaT$!RG|m@%oDsHN1C!@m{BT<&)*S;G*Cfiu-n9Ch6PNWKvJNtZ3^^yG5a= zpJSzaa-(YMH*ZgPYdvnZXc>wgdg?mVHsR?cwJ1{(j`Mi4`z1)t_vm^iIUVx6s7-7^ za$7|GGT+CUi`?z>^T4v#HFOkzQ`t&(TAEw$L#0>MO1s>zFM8J4E>0T}knC;ta+87n zF!fY)mbt8fn8xsx96E8ltVnLa1!piC=7hl)?KT$_PTGxq^)Og z__ZVIy_+QfZQ;?)@kAj7$vVM<>jX@6y4&laf;xF4fXuH|awkp@hsXG8B@B=Gx)olK zSx>T~SG2$!3hE(a>N}@Dn0L+h9vj|b-w%?*S82RoqTWKrF!}aUHDLWFWbV~SA`bru z{W0P0UzKpjy|_5cZSY>n`Fxe4AVc(y9V0n7dvBA#BB7jh?o6;=PtK_MWXFr0z@?qfF!XGL! z#&vD3CTh2FU$^9rSq zQwMPzWrlF++KmQm7&8><8q($Jw7~A@?7?vq5?q$SEy5T@DF{ z^=CMrX`X^*OqJH2iJffM!MKdSeK~P0rvaE8oEUjg|5~P>wv9UJ=!jQFt-s2;&V;Yi zVvzV*!{revwHFQ|{H26PmGj3PA!QHu=5ExDwCcI$b&pI9EnhETsxp7`OfG<+VN7F0 zrSZ4R0A0wdRg;ju(uIz0PL+2-E=ZcX)~vxkUkk1z#)^^`r73+quGJOKt?@nMKDq}k z=f!f0Py3%D0mitDU+6UnQ15a{Bahrpv4Lvc!qIOMhwg-KB$HC2usz@P;vo2;L ze})dpFKkCs%488hAoqr0Yc`EsI#Xw)z|rW?!fPl^n0Lh8Lw#{e122cg)nrw^G+YnH zRXJ=mOnnuqXoy1Y@!$lEKR!*IP!%4YG4^}}FY(@9-X9z#~_OuPnvsx<=$0FQJX!p)*z z)bVSOz^V}p0iVn?e(sA;pVL#RUpr%r6E0NOOHbKLOzO|kq#VmKY>mYGz!}g|yPa|Z zjqU$nqzy=Yt&{M1Yj7_Wq(%=%{?ADJZ$S9p+!ECwXxLor=fKo?)tRsEuFafKrMvY$ zwRRGjgD(X^u5M0x3}M!-6w~#&&dW)XE`1p0H6vMxaBi@g7(z-)`g}H&_s@rJJ=n*Ll-u#E$MKO3%VvJJ z`iQ#MpQRDWrc6$MlG5o7QPr-v*eI@BZFpQgzrL|U&=pLbar-!=QTauX{tWFwQrSj_ z@k;Br9x8}=Nq@ENy=v4f9LxzBs%<(aW@~(J!nAk4;$XeqeDLF4!?zY4@htR04_`;f z9vQS#g6wFG1mRw_dT;#GN*J`V>9lLY;DN_M%w_%GGig*z5{`;>$48!TWqs>n_sT#z z9&MF}0|XP$Y;sWg(J?;IEvef{gf1sW$$XXM4~1sry3``*pJ0#xPo}{xyQ)iLN9mqUG*II?#Jq7@eg!Ge9Kp zh!cv?Ex=(DOc3cK*GNnGjjn_(|Gw_%x68;*Bh4X2` z9Otw_YM-3(@ywIw)?Utp=@)1+G?OG5kl6OPp^~+k2w6sAzhbjiwJ<7<(sa0@HQuc) zJaNJ+XDUVE6RZo~z;`j^=Z9N~_7a)~Up*Ck-q}}d+|5iYgaz5)Ne3cAu6jAUA|7~n zJtK>q8sy@mv%lkNzVM_;Xq2UaL;mLRWhsP}+SL}IqMptK5R+eC=qx3i@qY)J7vq8Gt-!zJr{ z4R{^Pen$8Wp;-hTG(iQeN=tPO2>j+JBwm{-tUu~=SQ9WTqn-C;_g$l{VUh`$g3rhD`UZX5? zpb+{4iX>%P9=+UXa$2g>^>CkmL^Tv!_OkxQ|bg07BpuRfaAdPtH{5F0S@qKzHz^^iT8K?0QRy?9%%`QwAV4aop>GWt3( zGoVm9SIH$R08}2c%cJgfCWv@2<3`H)ABV|y%iy1+#`vj)YI_J6qC?q1PwQj@akZrj z(0veX)*(y8!ya1+tNd5?!{p=bD+;ErL-#>f)9AFoToaF_64yfL>pflmc2fcUQ z<~rzkU$6s#f;v>7+oZBMKoTdtGOfd}NR71+03R;EhG!*C-0h8okYpu+1hNmQjQ;8< z6#?u;ZGU|-A21fEIC^?dpabgCh3u+xr2UjBz@8Ue6C*MtF_=SwL*#-R2@w*^>^IZG zScSuRuBZku@I8#{P~&PC5vI8!dYoQ$$tAuiPG*xqfR*}VpF3;ioTld4@?qOo~$VpYw^ zd;&RQRiAU<*|}hZT#8f5UoX)1u9D z>o<)a)zvlnfxy=TH`7na<=x5Or1su5SjyGQ+oX0qN5m}HXhwEXQdf4+sLFZKfI!ZR zaEqB;BA3O<1z@Z`ycG5 zzGyq8ce?2wOgFz!k6@Hek5wW^`Mv(85)CYeOLKfO$R;|B%59UP`7tsAN^-|Xhh=*> zf{BH%Ljf0wLq3_eKYl%F{kb>@A*b>X;?c8hL~0-}be1H;Y2_LN2m%ek@m{xYfFVE; zkq?yk#_;Gl+jsr^0+`u_s5ro=2_PK}^A{D+nqMxTD8MeDz9manlQIaagdo1|tZMIJ z+_5ygttKc^y3g(#k1qC||LVfR%!=?nlidXQPQSw`f$(`sYGSsJ=i}t1iB&t{5K^h+ zjgQS5!VSwFTUn%<&9sC|I-+6zlAXlHVFrsD{8&yBFl``ehJ=;Eex8}Lh=1p&CaD|) z^}nVyfC#X#Z#A62Zw@E0*KZ`tqU0fD4u7>v`dePbFqrp$gY!Qq{htPm)qjHUpCJ5A zTK+#<32Wp)&Fc4Hp{-N~8Eg&z8};~aZizkt2Rrr0F`e(k+RG<=E<;iEAv){2wy$=C zcFN&z_n%;Qf2q(MGTrsVor!j|>;bd#s|#t-S*+T2+P*u>BOkVY6()y}0d}IN_R~$L z)vS1Ex6b|RnlKZz9kYD?)fFU^kDg7Cb7$r#510{xOeJ%m_1FM5g8#?HmJ1X+pS<=Q z--=k%YBWzvLovqhJz@3@q|$}8)jP~6Nw}}GYur!QIo=w=6gxthcwfN}A;(W;K^7?_ z4-#d4Wd?or7eCbDL{NUF?Bqg`LXDnIE2EVLFP0C+tqDP`3ZYyZOcT^5@RI=7`K!c& z-*NlTuUriML(mgy4&EEDjvwsJr^u&Ii#_?N)$DBP9!V$%QJ%x3%31zs33I$|64x?D zfAx_H?AE(|+PVV7i`pcNI(17!c}we!p$?d7jZj}6E<4f8koTkVq#_ z9v$K{28#&B-(9unI@MH@chJ@2LV;9e04L(opD@YFeKU1-e}ak?e39O8I&6*O_ z$ttN{khgotO?Nn9WAxP^IW+H0zu~_QEqJv$uf6w>CFy*6s5(Xz%jUjjY|nXF=Y41m zWaIuee}9ZW&PXAW3Sa zLLur()+b2aRD#aXAhFO`c@3))-vbCpknJ_B;0SkobPKvE*&F95C}XUkts!~bDK_!# z*=g$8o-_r?$2?t1;>?tymy|ia9QVQ)H^{K?;Gjyz{wy~0xcIc0M*mx1rg~WifgF_G zTWe4M{7j=Mf`mxOvWHp1Yqw}c3|2cBu zgT$#-C5aP89Et)%&!EduG3tAKNGBbP`2}UqNd>IGgmq4v(jj)scAf^|$NAp%F4SZ1 zmBJb1+iRvt55IGzEC};Z9@X0)*KhPHGsQrKvsg+3=p>6^sbYBFena3^^0i^-ug;MD zWI|mmkM+iH|KPlu1r3TU8&>ZX2Qoh@4z+L4-^!RfA}st0MIWOGT?ce#Hg{J8?&lWU zT`)@}9Dk>F<5)V$7X;L~XkSg?mp8OPUeW8ufV}T`K zD_*IDny9vX^fD53`rcToFfk8%LWj8e)G!@3TTwjEqdepgzY}L< zTgg#G#z$aSZkrG7sa1xGE&S$U1}{`A)l*#(ghC}_k+Ji-GHM4on|%u6)P_7JqKHa zple*hX>Ne?y%DV{eF9FrNWZ{1hlqvovhzhQWUBLGpM1O4lnDvIR#;Ds5%JLQptIKK zXhvfy&E0IFkwtbT&$PB`g{0r%G}z>xe7VBA^IS|Ax);MOxJo?z5RkKEy~NhMg-G3+ zYrsCoFf~A!;zD0rl^aMjfj|ebzL<*T^&bRqSWP3M?}sMZU>7SLsIXOPeN%0_&0s>` z$4)b`eL{qKzx1eug zDXZv(1Sw-J8(*&Nv#xr;daR+${sJ3s>z2$H+o1vz|7Ek`6B%|ZI!z+%mC}Li3PZoY zrse^9cm4D}u%BzRF1F}S&KBV#jN`IwoN{ouIq9Ov6a;IQdpGb@6q|#Mo`FNC>3Ek` z>+DNTODv~!6v1ReqYHmm!-7?-G=>g{n@#VZwGb&3f1PpJ3GcI*8Mm401u+uUexR7C zs4~fi@MxpFfFdL%j?RdjHZ0N2(b1{%a+f|wa`qC14VZMl=PSNjOg0WmFHKVeiX=*7=0Q+8}=SKf6S%NS>*BGY$G^{1T`$f<|zddMV_oM4ty<;J% zU;Ih#f|!>+jo0&u&q9HVVHNYHutuAz9$+s79>gMEJHlR|W^Pe4CVc-3q@LzSF=GRE zS_(ClxC{}bfT8#T;G^I@3FgjUp0;|37S&F~kz0#u&^n;g&ORd=UHs<533o4Z$vB||N z|AJ>MG9jn&cY!EW&^-?!r+2T+dI%QX@6LWm@j3I6n#a@$hV-ce#k8Ly2k|`2vsYZl z-9Nz0t&LvqS%*YH4XS!2qudUY)VlG}pg8^7@xg|q z@8*IwZ{eN%gkWTB+80)0Sc$)pq-3uL?I6R?Pjax3aP&X_GZ?Zn;ah)lNaKSEsQ3is zyecGvTRY;byO0q6Rnh2{J^nazfPtpGWQW*bE%c@{Eql}VeIL|e>U|i_*Di60u%FxU(L#{(mA#8g=bD0xYhqvt!g`~TP^n$oR`nuLyqR_){sWCrz z-@!vQ+w%8@2^t{DL}IBqZ}tHD4T^l)Q)F4%4sfWKVeMmZ5Ar`%NI}Y|%zTax_836C zk}ueS^~cRWlMTPbau3x7ab^A{{qVx>L;}h zMwB-l4Gqlj2D#Gih&a=6~D7WGTn!a<1!%P4M-5Ner!!ZbJXCE zIynpDZ422r<|p6m(hi@P z&I@j4oL=ebDe(I9v)E8|tR`hwk5PEcb!9XsjvaDi^5`il1j26-9&A}W>MfjXQ)sqP zc%}~hveNGn=H;V~FE;=Dx>}U7&}7{OQok3F0AYv2Yi_HljI)>Z3kJ@FwIhVRwdG|G zRuxR<;W3_mqde6`ARreEt^FjLLtm6+kK)wm zW7=)Hc9h=iKPSs4QbgK~-nb>R_wb(V6hxM@EacY{-)P-GX!`Z}ZpkB^8aD@<;c37R zUCi;Tu1l#pY-f8^gB=rddIwsDOxWP)Vrb(?#Y^U(Dc4;Jk0bq<4{$t12{ZGpRof7E z=kY0W!1zHijLO4m(!>H*l&W~Q=S^0S4V^QB@JLK5ZxGy**2nU&z*st6?LxusX1jYV z5aDy?&-sX{!P8v-Y{!?+0>v}Mz4x8TK>epu*1xaQgYRsAPh`64Z~a)~DzJK4{qjG1 zp-ZJ=UNcJb?==VcwJuua<_x2hhS!?mj7Y0B&YS-n5dPjg8NK^QlKdu){yAr|TmD+u z^_uPRod5`c&09-DOTUOUbP{%_%gFN&UjLuSfA^T{82u$Gj5U)(?>amr2UKrpDi&P7 H7x2FT5wAPr literal 8393 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 diff --git a/src/FeaturesPlugin/doc/images/Smash.png b/src/FeaturesPlugin/doc/images/Smash.png index 2104b03818bda68478f2f2733112736fdb565468..1bcebe21624c5659412b6027cf0766101d210d5d 100644 GIT binary patch literal 11143 zcmeI2XH=BU)~2gzpaID$AQ{Q87{)hiGwm zcOSk;>3QR>r-91@PoI14HbB+g#>Uyh&c)OGHUa#|A7|>y3b%aC*V0f4m%h_J*zOPW=9pq^WQ~!&%C4E%uTp2zo+#Bu0V+k3rTt3w$z{(Dt(}Hm{&Bnas3nFesl=vT zBSp+fdi2q5kE;7rBcjT8>rF?RlwmxlF5k5~`Q0UY*(&POU!TnXh-0m;b(xg?z170B zCx*kU9?w?Izv_b-D4-=6$`}^U-MZZ;|4nKqr9ow}WVrdgNgWyqNCYJ$?xy?B5IQYM z?2s}XZIt2SWGX%(O1BYNX?k|Cz5l&|3`XTSJvX~X!Y0qLakdJ{6#+~11fyI~t=P)% zoyGRyQro%}7C=tbDI7Ff?o_5aov&*Ds9)r!t&*3?M$uT+!(B5MXB0iq=}MJk%~p*W zz?XFz5itt~n+%tIS9(eu*TNKR3WxnRnnC6%DZ_QUD>(PN zGZl=VpWZ4k{`C=sK6)Vc$#JkyKTn6D$Sa{)RU7H$Sg8^`-#J=e{VVbopxK#k=dAPJ z>m8*a0U}nWlPM}B7XHiZ<1t2Jj57YWj6d6D)sgWC!^j%I-e&X@d7p9 z4>%RM)-BJk<3AR{2iiYg~J#l>mT_AVkm5g!Ry%X$Ga9< zujY&&DAQC1k}|&;y|GM*)~6MI6E~x^raRfpG`vOw5{!9}X#GeVaMPif7-;Y&BIMtH z7Xn;mcd?rha~XuihH0y*sSP2fOy4GO@Lc)FC!*bfX|1QaV!b(6QN4`TAGK$1r3VXB zJ~N7#)}QQ44IU+otbEs`w&{;&5!ydKm>cukPd{ugu*Bq%2R%Kmpww14N z&5xoq8~CZ(mNvxNBAz(r9yb|n-~Xsn@h$Tsy@Y#*mx+dx$54oDZ(!gxKg^={wz1k= z!~5!o-~U+ttwFau@iuf-()C9f=~zi%o~QHnhuxydTlMMUlVv(NNbr99Ax5XyewVt$ zZo|mwFdF}P>`~xkQkF+j``7Wj-0>C`{i?ukkHA1)`YQJNM#8{;um#*q3}y>irL?nP`4pM2MU zZ_Q*>yOCNey64C}P+3+hKCk)vu>F<(2R|vobP<#Gwu%itkE8<6aa3;k5Jyfqv0S$* z-8tHcA-AhT%C?%QU))9f$fSa50!fSIF1xOh+ofXGwS(L z$GSd2m9{+oC0+1#03|P4wtsmU+%4Hh{a%W^(!2Mqr-JVA zeo;w~HHSvpgpvp_UlF{^(dpH2mMKynFgM2{>9-K(c%{kG;>EMu($R8u>d056EUOk6 zLgfnbrT(SM%eO0v^R{OB{c$SkT}M$-z08>@UzlQESp6JnOOjjvrSRpEXv&Xi>lQPN zK5Yg=b!Nrq?Y@N*Aa-$GC8x@x`|K{D-|tYjT1OkVM`e(<4%x`r z&t_CSeCcSWaWSMo(V?vcg>N^@=wTTvl4g2?l=1u^Z{0lYBtEaUYr*?SEYst7iF|Os zvRQmQsPAIqy!>4k3fgR5@OqE#YT(--);=+YSj9c#ANd<6=g!QzgkMfu_SH&b9nytQ zB9MW(TVWsE7sl*=Kl+)sz3|#ldb->95qp*ERtP5O>b1hPfC=Z52cMa2gBFv~4HX1w zDkfm6pg~VFD4`;cH@qyVceArboSJ9`uP1OQ+nx#B2%!?)6*;UZ zuV)E8@ERQ5Sig{{V z_eNRBs)?Xz4{|~8UTZx2jxkeWM&SOdheMyfl<{0A<_C#JW z*w^X{X=bC1Q&0sFb7{z5a8&L?Nd_jVS3=9<^}rytcPUNhABaQh>N z>T~)yEF0u%yv(us{%5*7E})(G^YXR1uTL)c4~GbhKtfEELQX+mioa&ax7?c>InjKU z9 zI|&A~)Fcw1++~vQVB9A|j7p@*ZMJ!w0@Tl}K38!_9EXwpD?v9!OnZCbC&tLT+Pa0b zAm-_Vfmdz>eU9>As`#~ggn8rU^tZioVZfpNItMY8U*kTnu_igSA4YhQ4U#D>TjzC^ zNzgc}1RfnN=Z$E(4&;gy(z=2vvCi1>8lR-y<-YdizPt?rv{C5;dvQkFPI^iAAEyVC z8=~G*RAA|8%C_Img1yfukCa)-{byqyT{0sz0vOjj&9bf!nuTy056qsf{Q8J7Vys9* zbQf93smEP?V($MJn_UsQ-z^+8Ssyt6J}-THB*~yc5M5M%q|uhd&(Ce}Heu#_q+_OJ zJ9o6B3KtOgGe#xCSuimTf#&m!XH)-7VOr~}H&}Nt5ir8#MyJ9Kw8$Ebg5i?Its|z0 zV^lWsF_-3PS_IA`iy&a{N)bf3ktIz3wsb)^+rVI#n0*sxB|zHV3FMJCB&PTiDF`6t zKPw05F4^OJ(vd8^d-RzOzdq<^DdOo$u3s1}GA`4gvOjSQ)h03XfFuo zgXwr7O{ryi=`sP{_LKE>iL=4yaEo}!vSgBQV{(DxHzItr&VY@L;=V7YyC6!Ru8ae?s-q{gy3%FL+PTa09C1MQ@zU3nEtuVG zl0bsK%fBZzu@2CNEFI8e|A26vZI13XSzn!~GvP!TH3S8QAwd_DqGd<2ATgl4rW^n)-{@+Q zt~A5hW1Ve@8Qhqb`r@;6ky9sM`0%M0;U-iccEeChd98z89)W2T$DBZBmbDP+qeVvH zqp+|rUp&D0ZK&8f*LC{q(fA2xy02m)zeS-9@W8RW+N%;xyX>Dtt^RM4W6vwnG>qk25u&WU-(6$|7J*)PAh8 zcmkgQw_mjjnM9u)N;aAd8aHq(KR9bK`eO!o)5vjSP%OCQfFS$VM?;KzrT|cT#Ab}N z9Iy8BXSS{``qY^E_-zteB|=>>PdB5m{V^_RrXk*0>>4yj$+N0RKDa29sbG~x2zF_^ zuepZUH_0AOA?u=nz`aWpG=NRkeJ}t_EoKA{Jmwd%I}t$PUnsI@D71lJvv4eIxx%Y8 zj7Kg{(?mGl3}2o8W*SU@!@97K8Lz2GWCfeYNQx&2`59I?Xka@F!#kYMFBIc~ zeDE_(!tG7x^ua=k%hSSWW01@U7*oD<5I@8Lvp6)qJ1CsY8rZN=GIGh%FW&J=41(6I;veo}n} z;}1_PBX&FhP0lwi=?5KNl)peD|HbKw!_83E!(S{XigCiA+mb>yM)v64qWIC~EVJ)N zN+{ws?|url__kt0(;;=K{&kCnn$|^D1UZ+)Mb!2%P*m$6cSN8ix7-%$z1NJFXcb{J z-@yTL?9XF5XJig5NrR$r<(Ajp`eAyRzI^#oII6Hyg;cb9aTkLiSF~dK=N_X0VRwm< zX!6K=fZPfOvm(z^gnYzz0YFep^WPW!KQaY+q(H;|WT3!_?i(aQ`>+2hzyC`p_#ZA3 zyMu%EA>t)H9t@Vq6B7}|!(3C9_~qSthQ0~0FrZ}Dxb)U}6xT`%)rifI(4fNNAGD|v zkM=M%iF&k?B*FliWoyNdsknw}g3^{%nqFBOFhqXp}r$e~JdHlMrBo2tlyZ7y>@pFF&Ne2nX z>*s?O!7shnM$|h~CD{XycCmGCxZEiv59_P+)&~ZR>wdWPKIdkZ;$I+ijy|1ZB$Sc4_U>ovL>FaKbt<~QG6je+=@gJTI@xp*EUp;w}giDCm+gdeE&=BStT z;OaA)gWdIU6S~p2+9`7#uY_swp`{WJ9T|H`9A>wfCZPu%G)}&nNqjG%QMYoMHRf}^ zR408f=1~GIGs%Gcd{4}P_P1q-bH?V-&;XMm1=`TPJ7eO7ZEGv<9tQbA;I=av^1nGA?Gm( zGZm1)rT5i<6f*8d5{8PjW7X^y-zPg!F{dm7a7EYy_E&q{!=kx;R;U0(tC!IF`q7yt zRX1QjI~jEgB=B39`|qzV-<~LQG<**yPJVtGPaXo%eQ5rfV>FWZcmt33e~m6sHX6y^ z|3S`eRFX5{y?%bY(J+W_o+*#u@5xS<^mx0kv0k;v*kI;c0U)u5P6R(Cz9K?=bg;2; zTgU#9V6O~V^ac4Q6@`Xm%=z2${s8KbeIC_Zlx62;z`^?72N#j~6mb`C-VMmOlM3>l z#}oof+RR#GD>rGAqHlpm$7>bw(thr*qFD-9BAW`b1unw@7yyNBOFaGdN}3w?Ev9W03M*+KyvYz2BC=UG2it zu=(}E_3jAwNkKFWHv6IEEgaLG7zU|32ao3qOe!37En&1(YuP^%(nkPJ$i3O~H1olS z)8RJIQ2s{o*Zt?_P*7oV;EDCWaRH$<&yGTiX|ntg4*4mSlLQ`3zFZUO|6F| zpEg&t3qC#AYK7LQqqX<7?1VGN5Mn^wmNhtaM}_-z5SJRj$~_qOdo$?rOa0gK0U)8b z@&3O#c0&S4z`C5!dstvHD)y8PI(LT`{w4oop~xcb`@teheY|5m$pM6-uz`pxg{D}HaHWDR{90TqNh)p84ucCUQ^N}P#J7Lb38hy%W}(c+3pXJnm)1bE2K%490y z$*h*SbeD$Ha{Okv5LkuO3ng9m>#G^TXH`1;k2h9PL~l`%YJi6PDlxFSD98ws1(0Tr zT3I9l*`&0)jgOJ@BV~?Iw-H!&%A$>e1na0dh`)H6+V|$T)n$CL1mu)7kRq|_fXArB zPN`*2;=zKTHAp^Z@;H)g!4*his(<4sFV0AEo)yj*Uoqi-&C_WL)<(i88bUOTtrdRc zw5pJp^B9*+TS6Q}635?DUqZ`{H*k0MXMGUF1gMVEaOSE*wmN0gWZh zflr_b3_La@13+?Z-!Re_%Cf!Hm}l1oyDXLeaqWT`8g?OmK(hC$KgTK<$!17Y930EF zL8sL^Ez!;Aol+Zik`tnh%2|h5q#d6ktB%RZAEO2FM66CO8D_`^?us$0`Z7n|q^={u z1wj`;J52%`8w*4Uv8AGVnciM&)UzP#K5DhN*u>0T#Bi#=odt8%&wud2Wq2 zZR|Y33nFN8l9GVAy4yHx2o><(wDJELa3yo0K(0s-W}rM88dkX?_x=M&{2!4d2swqV z-cF&rF5KO#6%Y9e(&2O3VcBk8Yus_CR%XNL+SQP{Tgrp9cXU4>mk zI2qHx{^~&IDL#ltN>#c}Y&TG;gKwkW-Q#j0UtRqk) z>1+OnuEqa4km_ptJ`ST|t0x_=MI)Q7w`k8`^(ZV7ybrpilxHVPY$BmO5Z5f&^X~lj zVg^B#-_C;umPU~26H$u)EQJ|3k5^y5XIN;ud}J&PmKbK3S=}zyiUpsa`hjR2Z9gB0fc=NR3W%Xa)+hvK_RT>KyU(fFk<>IgdYm44#oQH(o?J3PvA7x{r(PPG_dLUoCiL6S96FkO z!wODhyn_*+?zd8sJQlQWwquPV{cxw?4`>m_m)dr!wR@516<-N&M5a##_74 zyl$l!_CL4#4RoI*j-brxq&Zy|I$rg{E~TN~gOyjAt^ozsY{0n8!K>v6rfwrLTHFvL z@q1r!xo^FTonVBWKgRB6XblCd9AA@in+dz$m2L(NrnzCxhfuYO*mXBLrWHdB*@nQR zxi(Uk>$^3x4V$6u0ULFT+>>RFNsO@)J2~nvR5TK}SR$$U_Y;DlKNc@+tFt^&S96J5 zU-{tio|?HdRch-t?BcPiKHq)l0o!nawb?4s@v!@*R&u{}*Y9i72L%O%qjLxb>MBt* z)5G|1MlGv@YI$}O<6)D3&}fK>dB55ve7WAbj`9&Gr(;OKHFh3`fL}+XRW9#@)jCu znC<C#m^Cgob~ zTHsdxUA+yLjfuJu0IjZTa1~!d+jS)fcB?-i!kh;3jaa$$bGlnXN@vOBPMEPY1BdNU zWkSYW>jVSEf|U+Sas$GLu=efME#h6EvWu7zbwg%(ZPXn&xYDGyJma@JBmngN<&^w5 zz*eI6W;1`oiO>{i6unnqT$W>6 zecxQ~7WI1@>Kur^W{OFxxJ5r-UNgMPrZ`oIFAt+-SIeR43ST#nw{E&lPtdt{?xp}vYxHxnr=Zs@;vFuKt%+`VViR>^>bH4~cL7#57(d4ZhK-+{9?Oh|S7_ft zf($MtA4+8OVQ`1&TSRE;A=Bpk#VEv7N9f`Vgtsiwb=)M*r7zP#Zdy}*O*Btl$ekT3 zwNR4pmWK}FccGdD9iJOoz`VwSJEIJy8ozk)cQ(@4w*=I~Av8Dbad$fCxG{&{ey~4Y zYO5>5wb+@4F%>Un3%dJiGU`g_C4ckJ)a_SdI3Z~NVc0X-;C$3GE{f4zcW=8aTjk!*7 zr_mye>xa)maY-(t5=^QnqI-QZqx>=aKy5X2aG_!{XonKvLM!KdoS01=n~4OrL)e29 zsGYGk*xLD;gdq2Ey8t4dZVVjW3n2x>Y%?+kf874yYesqa0zqC+jIO+3p3 z&o%@yd-(qv;4mS5>^IKycbH7(7SYTP2wv8 zU9|>3)*RgPyeEBpq-qj0@)Rb&rn~5BiCR*D=n;cOkK|mswc&!aV-nCY{M>IOj($lN zzLjD3ciI?p0XH=+*8ku3=j`%-Sg=>u%v4Rlo)<$A67qpp&*4^0ScUWW8y~%$S}BVQ z_@E9m^Ki}^-J49^Rku@S3A$_es&gPzh)3gXjs4>a=32iUj%Yl1Kxse}>r<2XQ`>-U z2^LaC`q;rDi##7a=|wot7$I=B0R;rMX;x?>$bv*S6S|SlpliL?UR(IA4zcjp?Z)5l zNY=xi0Kyst(DA4qh%T}!>D-!asY(1E=G%$=jqeH($Zgny3Hq7DpCRHrc9)b<`rYWm z@#@=8N$3`g#l>KamYavU$DKFwdeG(T#Ym+-s~_Ka2LXsTSWdBuCfqV&&BqXU>A4xQ9@2caz$uG5NjxB@mq zeDGYB`+OTaESO2K{kC$ZC+4xB)%t=nCeInGl(rsD)|(~4N#lQSke4_abo|qx#qe*l zH^bb7c&0MdrOFg|3u}r%N9kASSjD5J2#W2gP_i~S_&L}Qjm3&{q1FN1brXu96&FI4yuUd5t0K%QmqOJ%_dodRdx;e$HOEZQW#hl}j z4Dt+qxUE?dv(8~AfjPYlI-kXa+t*wVi!v#QWHNFDwLle zY)7yLiM4`c2mu1!#VJwoO$dKulN7AyS$+xex1Y)v_TRM|r#kj16h~Mlx-ntZO1dK4 z44x;MklaQ#wHa^;8R^dCc&t-#j++CMub(w}bb`!cK2pWhI9KwP%h)~?V(L!f&A-2n zWcG%F4V(Hr)yLbcG%o^Y8^Rm^+`v}|H>&z-IMY4gVtXY)V-UsWJS*c(yE9YO?D2eY z;bFR65>%VsR69cVt zXSmKVFfg3ceym~4z`!WPz;NQx-%bF(Bm@ok10Rfj###>{WYKZgS?&n1MMJA3_f{ zweEnHB&bIM*(}ZEhW1(BJT^fufHrofzyA2k6O1?Z_hLv6PXhAFHw#m9GJF^qfVcZIwTw*I- zsT<)(i|^&FLAnMtsr&hTa&iO@%c!{xYoSq+C=WP+rZ=4SB4GFZne)#tq)EfjI!QfXVMq1au$=e znD=zZK8oa=HA?H^e?>3n*M2san_~~ViX8n>2og-$sEAhe7{$kP64=er&Rsuq*Wze; z-*W^E-xA#%VQ-k(9+zdJ3KwOACw|%Z>^Ujc1?8|$_e6O_xo+sCO1LtqeZK;g%|PE z-b(yvbK0mJA@8#P!b|10qpkgfxhLtwmGNr*^xfG)!xON;>7e1I9K0zZ(cr4QS^9+i z&BoD+P}lp%q2;kaxVXEuA6UB}212cKFm~X_QMUIG-PzHq)02}=a&_Vjc$9wewr>_2 zY;!ArdHD8BcXxLkY^T5+Q)-fU^_sY$mnqsTet)n89C=pl2BCm8qPk!0;92ue%>?c2 zS(kkp{;*i=8;{_$C;AV5B~!B%B;i=+pTD?i=J)au zd|vBZi$n7(nGcTGaX9XdW*()g1|oK%jh-%K=p1T$3Ksnb59ewh?4j1~jw)(`_q#J= z5z@_S8y50w`AUj`fUdXAMB2FPm=+(r&d=fLbf#gVvf6VE9s5-B<)-Pi#ex_w0$o9V zTBR>!1DlYo5UeWVRRP1OU6a`>vum7MtrMH#QH8WEUD=)Bl8HNYNhuJ!9CWI{YZ&is z$;wlspiEwo98?>toET`fh2!B)Sl*L$?E7uA{cp5F>!9er8gY*p4dK3P7Ml{}zwmVJ zK|*%*-aDWPE}1s2@z0H~vX6BP=n4aMiR5eWE1CGvHTe3hJO8^bi~VPb_4T2l&JZMK z&7lsQNI9)%bRw) z`8x=3;DFn_@0^|-;!e}GC8leScD6$cX`6_W9V>eU8M}}3fA&trrjFTBZB1TcvVXbr zjZ2=pmi+3LkW%`Xneg8&Z|^)sN(joFCk%0jP|}?wtl#DdJVcm z(I-ETdTxErKTkabdi#s@iV3qfoYsBZzMvns?%0a7(kDozye(dhfL`N* zuB?UJb6bsSj2*+5pe8hU%DxT<`lcB23+h<<-4ujc9l{;`3s7s=f=U!0?0Ik4wOWrQ zme0!7?OQ3;Wir2wbEXY3w>&f(3K@erH2nIacqa?on(i*=S;nm?rkWmgX0?9y6gFQ! z`s#fBWQKP5T|$UUT^TM>yDx-}Eo^^#tScD|fh}P$Pdg-BU@e4$A!a!i3mYI#)J7re zX~Yz8@RldxM$_~hJ=^Nw1x|KKUsWM%A}fHz?m|CBa$m9?zf$qNT=h7);ntUseMh~p z(yU;VZV+&T;b3*%=lz;+zY&)N_4m!a7^>v@;i@TUWc0iGI18W18<8n+V*>1{*_>@K z1bh4;cbomf)$4Pd;2UTplR|abW%+&Q(Eg`Q_N&`#EwKF^`6*5k2Tqy8s_i&-18zLF zZVr1ID;*{_RoCZ|xgzFp1C1tjAK5mxR>DKJCzQch?uTMkQI5(vbyn8guTe>%BxrC+@EqPv3Ld~bV4;>;Fb|IpK!+4q|;YKr9 zSl=~-?d&OUg&AKN$z@^J4l19qh?VY`{ZgtT6tGAq$xm3aUMa^vN~6iFDJ_?cr|*EL zv@T9|IYNF8b6#tWwvwLJ(>sVB6wWH2X)noh`sr+`^AKYH>DZ7@Lkw>cRv=Ei;ie0H zKjLhg)_HS!r+;t+fmYYx`QMV=|4}i*{O|BUkWXl_8skQz%`sl>u>$H*hr3pua_%D) z8sTiP5WhndR6=5RWdxj)v4aFb-+qNux|v4or97xLm@~5>;h~S}_TL3_20cS`amms# z{)^T{qWB>nOtzv})tnirX~Vk)|24-6UPHCRoDYU|T2)b!WxQ_D(re+f-sjiGQTsFe zo=UMzTdPeQY@XE+vSNjI;^mAkLn}45h2w2C%eE81#2&%XEsumu|A}jDi_CUt2CLu& zS~H}#szk%Wc-$wd^mBEhc1eM2v)XG(*+S}XY`uo4UPAd?=atvV9ZpjHRZ!9W70x^Z zl$bP_U#qQ|+%&FIBh>OJ<^vcEfXLo0{L)q5_|&?EnX?e8(`BsJ(Nn#Pef!%>R#`g zbL1-O^Cy{STcWxTU6bcJej@twqN!^`LWw@hllrlUS=FZr1L^*sc6YA<>_;GqbYN6s%w4}kK@VURaCx{)TmM? z&BlgI2c4!8Lux`x6b@R}?W)*3R>!KU?VHbtFr%zcT0;`)Z~76NF{xiY+HXo%Pe%wC z7jveFu8r2IcT2sE;6vQYbx-V$b>H74W4-dJ#FYswNNxo{Ku@iU-kHHB90<9hO_klY zlFVx63R5AgR1eu)-3iy#X*~xjahSKqu^~1^QM#%cG8}ubvos9uNM@D9CB8}(rp2P- zY#(z;JNS_SPUygx7MT<(t$xjRY>$=l+897ei8PpEJHZ4$(wK#G#&dcQHcy{Cq;oH@ zMJ~F)o0r&r-)nrMEUIw>l0( zkD9wgMuf*{)lW5oah?2b$$?O6G6g`*xmlCN-Un*?7aEj&YnK&Hl^CqDk;dH4!$KY( z_>s)fJlx!!iH@^PEgyMf!|)Cd!W{36xaU}Smx@LEM5`XOO}@gUsd930hE8J*^Fy}3 z)7U<*R2%UA%`*_I&n2HM>xb7ip*Awlv~;LD>p2Fc3`(9`nCK~fP*8 zWi??n6+%e6*4McL!!cb$=A9ztE*<)LWA6>pq!jMTS@KFcWyDSREtyFsV=s8eDVUiT z7lZ3Y=qgI$$oKMv@(-X8T=0-hV46b6PpRl2q~#cTv_9AY7-Y4NqP}$UkJpZK2PVD8 z#r`iDhLo^Y|DY+$U4)S207aa*-`9&?rPJ2b{1=|gMZl%)oBk##iRt8E!2O|F(%srR zU)IX&=i^ggS?Sgq#bcPJ7$1C{rHXPU&bANjK2&ORa7=%a)%23_q*OlS`mreEhlihv zQq&NkZ_iv|7q^T9j@a1EogrJ;ixc4KA9C%_LupsH4HSZ|$$10;=_3W@@mWz=6=*Yr zMs4r<6)$QoWqYg%fk04FPTd)5k`Bz;Hx=M}Um~$3t0ONKU zW?Fp;ZPgGOGFJ^ylvj?-x%8xyur7w2ZJKi4;~s*3uPB*&J}bM5c8%}O=_kv4dNp>_ z043F|=WJ#3{Q2{i?`lH&$&RW^OM@lS^ISQMpfqbxr~=Kqe|;I-(@|?Z`>V`>)7|e4 zaFr)}lup02YVnHoQSS!rvng_(_^oaw2M32PM^!Ykt`tJ=hT*q8Y*7l`N|}SIFw6_`xLYi*r{p@KU&UuPwg;ly6YgfMH=_L8g4m z)lE!Je5i`PKbMGRJ_s;O7_+zBWb3nkHVA7u!oil3TJ2zkFBF$RmBP9xj>Z&uEGtSb^A^>+a=6 zbt-#k(ald-pD!hVnHZ|?Lm5V%@Vt~WVahy5WPGmv@8Z9EK#S(={)~B3=CtXi%$X!TcoF zXi9Y)-4Q2(bs3_12s!xGjF6ymG)jMu7-K-**^6Vtf`Z-cUlC3v6*G$25gds3)jEYg(^b41aV zjt*)RzyDjiD}7q_Q0L(sc($)HVt(?~utCRlcc?;193?^A!cov1UY6rUQgrqx{o=jL zs-XKp7WvO8hn((7)=v40=K6`v0*6gTqee~k_KZbV)gIbM2Rj~Njv&f9ga+J8OeH?m zOb1#niE6K_U;KzFtNu|$)+I-knG_laj`?Z!C9Oqh0S4WvWGA_@XwR-+~(vwuME^Av7APi~=oUi&%_Yh^h#)NMP zuRrg-!5JCq9{1Zl$=t`!`?Z+Pb6p6PlDT=<)M=Qne>52qzCIO};=kpiCeQ=bI&u0O zyesu*j`mECvw?hgsdc^ok3C%D!#COdfXd}6J6TD0K9?1hkh$E2#n&`Y_bCr`vhGg4 zw2fdF??@0`o13e8Mjx{lw6V4c^qO#Mk;B?pqTOl?oJLKy<(7l zZ?J4eG+vZY@;u&)mp9)qEv9`&>x~u8%e1|{(5z&{w$#$j0O+V`HzGQ*HhUlpG#;(S zakMtoh&DrmKW90h%_LFS3&c)=+GRA-&sbU+F;l!cUGCB&LAW*Dl{Je51r3`B>5~79 zoApN`kxe<5JzTX?YyX4VdfHx+`5EBvc)2&kv~87 z@1*Ekb&RhZdSmV;1UK22E;b9F(uS2UI-TpWOuGeK_7EGc-N)Q+#QEr^y{b%Is`lfA zfSl{DhH`h9dyG+)ipbPdgp`DWj2!v7hmMbjPOpMSr&YMXt!yq=tuwJv-2!>uFA_S6 ziP~x9CI+e({6Y==DW%edN?FFZYyADBckeA^ppONWvW-J}a#lYYs9f~}Z?Z%iM(KB; z6}1gwgk}{;~&xv!~H8M&vB#ZaBy1Y}_IX7NC7W^4uf>mCg z9$A+Ozq7s^{CDGq$yJYXEkieXZnAfOyvT7&S=VWh;%K$aY=|VH)MlXFPr~NRB9OTW@{ZywrMQ zd)s56;1fzxQT^T7b{E}!TjnQvF;S{Y0j?lG$Mw1=xovDfWM*V!3>**6=hV{BsPGsr zhwpFhP>5SpY67aQtxYHXHje^CqlKB78DLlH&Q90U6crOD+?}6&k=cn2AB8QU0Qc}H z`WK8jcI@p=ATYKK^tMm@k~a8?;H|lGC&KAdr`iwaGY}FN>FbT>C2QAzyuZl*v!{o% z=#ACY#pjmwMG<=X4VSv6sttS~kj>rQ#P)CB?rUka+9HmK#fzjGTuGUn=ZNy&-QfW#Oe3cb^>s0m2_x^6PJPpl=eU$5{pa$>(lzdLV=%U-3OOPao)haOIm+@7B%+= z@w<4W|F(7;`J864!RplzI2`DVD{O2xd!U<#a&7~{!KI_+PPzcdcXAjVY%lf$%K*;p zwTX$dkXL|tc?CpN82)Fj?hwWn0i--APpIH9i4XU2PUe) z4_8E`1}!<20*b5iz7q(dTld+2FIS!#`rnNCZ^Zt8wBX?931Nc-pCmFCd;&sGGp{=j z2tCIC+ko3I@q#&0QXNc~e9py0<-N703#t*joG>T9vd`Aw3kHIL3h~F7)djLQ|7MYw zmI(!31k^p&l8yq8C%Hg@Y|p{n@EFRVsil}4y!AA&N}^AYZ1YJ0c8$_ zWrGsm8u5ISy{~8)bU00IGx?ppS({RAFQq^F>%W#41AKQ;wM8sZ`omoDx6v2N7Q7eb>+vt zlewAuSkky_^Gk&4ln7EXNU(%yQ6__Yktm@;O zgq3dGw2YI<0XBqRd~%~c%IA$#K*-2x#wsNyITm(W+8FB?dpruV^A-7ACIU$w^V9h= zYx&jtq>{Xg;hJ%7IcZ4WcF25?++C5o3K)tpNUAYHTTc}k!yO+Jny2x6LuT3&BXGvZ z{$g(OLgY9wUn7+=Hr2wz2PqOcw>oZGB*%PC72Hi_`>Z)EbJ5#R+~_@9gfKB_-0>tb zIY;ET^%pi?{FaoBd9tehN&oq8i$f%J#?YDo51TD=$0%qY%g4NqL#P+9Vlc5|Q{PS^ z#>TnN-1GS*pggZVtxn2A$6vRJ$=qPiqk zaX_XH__n{3nBnb0=E+nX0I7OzmeI)b8RZll0uhm)ejAW;PM%kuB+F7BQi2Juuc3jX zAtS@7+^0k7KC~boJ~HdDyJe_mSqopBR@ohs4n6!jo0C(}_P!lCVO8Pt%Bf2{yY{3> z*o%&QeboT9qrErHF_V*Q0y@_CBxe*yPm4z2LhoneTpbAs36R?1^+atL+N4lwkrW7s zBQpyNzi@_pg(Gsu^x5`vl%YTfBsS3k!|zh*JuxoE9(I;jIjHwKXB&7PhsZcvo-TzL zuT2EQ`-(9Z*gS688Q5B#{NyB~bd~uyW0ATFxu4n}J#oC(Xd1y`49W=`vfVw)%zQ9K z6Ris7RHHt{zBLVkLXOvK3OvExD$vb8 zBe8W++z=n1$2vMOr_3?dkbr>kl^Wd^V-h_CR;~hQioIv9+=e4|HcpndJKO;SLYyjEm&WxlvrpO$V?iqT7$8_DxUy?x_Zk)>KN&JqR@F*~vVe}gy z5}hW-RTR>0jwUbvshcQ~FtN`ceW*_t+nVbRUd-j_l8V@5eZoT#$*AJ1Z@8^=UxHVO zYb>i7RAN;bTZY?ptKJebEgIkn95X6+)aE>%;S&csqv5qMRQs0m@*2>NlC$b$W&`KE zf7)WdYA}62L26-cYD(5E$3l#_Lc%KLgTNt`TXDNWyGujnyjo%BuTdBCrE^+#g&JJC zEC1dDoJ5;_dPnYs^b=`7&LF+Gn zx0WRRDUbv;-)p~9?X3(E{-%e=KZe#Tq-_p&8rr_tusz2$kcfp31_e@nZG@VeTXlZF86le+TEhk-w)$~+VABMCb9*6trq%IIK+WTUI^^&>npRah9v$p_RJp@{mb`@M4M`VvT?HJ{!0n) z*ZZoytgNiv-KL6xtCuf^c5r`C=8=#Tb?ME9;T8(srwXo=80T*OxiK>~=0>P<>ft5z z2nmhMk%v30#PXNms@|nzDh4lhc}8_O3cCaI&q5S6Lq~a6SDnXlw2=wo8PYSw|6{zC zf(>fmcXwWhLV4CFTu@?y|5;&;_Yqk++^NzbcQ74NEd?XO{}CZ_`-w-*EFwczh24l_ zFv0Pz(O;t}(1Ub~PicQQ#L{hZrSNc=%<~w*M}J}XJ1d2;F7J-ci}KY+B9;jAYXQ=l z^kv|I6h6fT7ufF;YF;r>2@Q)tW}=$Vm#OXH|1$yN(+v+1%Is*aN3Q~)z=J>x+L{I$ Jr4OII{tvKMHx>W@ diff --git a/src/FeaturesPlugin/doc/images/Split_panel.png b/src/FeaturesPlugin/doc/images/Split_panel.png index 7673ef4a3000d58972f4becabda5b5120d7b0b3a..7d80c5f846b2960c06cd85c374395e0323b9ceda 100644 GIT binary patch literal 10935 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 literal 6665 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 KTCV@sgZ~0`OAO8c diff --git a/src/FeaturesPlugin/doc/images/boolean_cut_property_panel.png b/src/FeaturesPlugin/doc/images/boolean_cut_property_panel.png index ba79dd1421209bc575bdd7c154dca6943a7fd6e6..696067fd43e90734135ff41b2108eae8c552417a 100644 GIT binary patch literal 10149 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 X-PA;f``5r*bdY;@)D?^5O@sa$q;=u~ literal 3946 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 diff --git a/src/FeaturesPlugin/doc/images/boolean_fuse_advanced_property_panel.png b/src/FeaturesPlugin/doc/images/boolean_fuse_advanced_property_panel.png index 6c218f94cd82db049ac568bb5a9a82e3cb74b664..4dd19cba08de6d6379e33857a9e8626618f5c52d 100644 GIT binary patch literal 14231 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 VQu{I%d~Ob+B(Ek{AY&5vKLBTL!+8Jz literal 7377 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 diff --git a/src/FeaturesPlugin/doc/images/boolean_fuse_simple_property_panel.png b/src/FeaturesPlugin/doc/images/boolean_fuse_simple_property_panel.png index 48b017ef297ff4e14f5b1fd3073b622d8bd62933..069eb59da67e89b618b6bb2225939039ff25eb83 100644 GIT binary patch literal 13063 zcmeIZWmwc*8!tLD3^9PjAc{yk2!eo8(hNwqbcc!{At6Y^5E6nk10o;@N_R;Qq9UM# z2uP1~hcJ}HUOdmc_qFT8Ip^Bv+x{>YGyhz1ulxSRB1%U~`2sm3IRpZ^psJ#v3xPnP z;8RFO0*<`Q4Gjc;pigy`egaz8%Cj8JRd6gcFbRj`094YX|V{a!_>U zJ(zE-JAp3$<|4FdpEa3^kghhJPM9Bg9?iEHl?=B|jeA|6y7wS3(N?*X7J*FnU2URtU;)>lh8~3ZHJbOH8?vr=+F{c~}b$5NBBf99BpInzAAXPT~fn9n< zl(s9&f@SV2JF`=VA;&L5XW+77ZkAM6*4^*po7E&(z7Q2v>!X=@-9`%mlfbp~-K@Rh zx#Ds2)+`AX;ey%}W7xqjIatj1lI#b+SYm14ok= z*7=$cX=j)>qd5sQTM?s9RP3p!2ICcVN!kod=gn+meo#D@l-b?NAbGEdz?6s5X;_84 zI*29^$k1Yisw2EXH`Sy z`q;Xbie@=hj<@mUvD_aK`x`<*vPBZ)LPtYMgNwapz3PzyLJw879}Dm6J>DARs(W#g zG%po!*(1J{RDv6dch5eYi}WIEoZ$)S6s29VA%pP2%o&aOilf{SyH_MtWt_&e7B;1M zXAMbJ7aT6w4m4_FcaSry{-TA+CzR9PT8g8A-nn{*!Fql}9@5kjBm;6wV%iUb$yzI- z@YDEiYBt!vjf}Z=k0labbgs{9av9a7?vp#bdqOM0&q|LsWgR&_LZa(Iw`qpg?`kHiWw&1r%^Rsv z6!cp}beZNR95=g{&ijXbx)l3HlH2Q~(B_27NbcXeNLHl8@YuCuu_i{i}p%a&wT4uZs-S-3wSq`4hOND(Btz$Ch zI^8*5<6!X4s}_E3J~Yg8aMlN}G1k`{UN?Kv;IA-H4`r5w`i=2JFayG6dX%F z+cfaz2;okFl%2UDAY0g`3|xx zWyrBKH$C=PI-NTOt<=`2+j^Jv#$;W@T=~dHcNY2kLKcg{sjYv<$BFwrquXMvPDU6k@ z;cJ?b1$Ic{TlDGP+Mk3tLqPtvHp#>6!DNv3iFmdrZzPVvTf)8mLt!&;Q|)fAZ=7{z&H{C(Xr+sMX=pq&GpQqrAAfwW*eIcQeGc z(oIepE-j|=4hKngj78J4uC}w&RRinSm?2TR8Rsyb;0s)vz87*-A$AtUYD*Wa$4ly7 z(YSQvb7B_utL^%lkxsAwxl#v~fdBDMy~=adut!i0b3iU55S*|5<_p6uaD@pmK*>`0GjTO5ZXT=Vl)}+BXzhsOmQ2Nm>TH0WFb64kRbJYGlaaHq@ zx1adTwSE|u*fwZsdLs`O-vr6Ko(x<4xR1N@$F2B@;Ld(-)d7z4aOgU$VhPXrs&?mt z|I+k59xql@vG!CVQ|&R|NUpdm9+Rh%@R1*K{3CkEAA@9TRY+E`Uif2>Sn1B(Wn7w2 zbMP#&<|Ht@=8E)WV%>vB1&@5TMWyGyC#KAo>INoGKD$(BT7I1axg`0d3dL)nsGCyG zext`AHQAQA;^iz7SKeuD;&vQfB7Ktj@T{b8-WS6KgCs+?IXU=(O=vJy7OGb7f+^G6 zOhqj|2$-GubDQx?leO3N#64Uj*a<$G*Xq(MPsuy1!RB#WO%7jldD!qo(-?_<=XZSI zM%EZ`$1wfE8#apl%%nrVzT?iUvs3}ak`{~mX3NW|UQ3er?vdV=R{LD1R&OiOj1x11-CDa06R*A4BS~Rn zh)ZhO{U+hG>#MyJ3HR%ILOc?d=s;(8m+p}@#xl&-!G}ld`20%WYxOjd2f<~nRH+n{rsbs%l#pSs47sq!?BW#aE?H)Nva>$N$yB5X|JnO`^}rcg|CK zq<tv{R$2fQD+!N-C`2+w3FDYZO}n14+Ti-=|m%cof~Q+7p}&6{0Lsn?~IVhwisGQQul0{RvF(}nZU$o$k{~?HPbL+U!3d5M z-||?}>G6>w{x?=($X^5|)YdD4Bk@i%3ZoY18F3xMJ5t_6Sid_m&kdbX_r4iSxW^s* za&c2_z|ewoJzs>+N}Uc1*I9O@=+iSN#+wHI?PacS3s`ErSr-KsyF464bCDB?i--uE z3NZa6YR|VB$heI~E1+(<;?cEQ<|O`SC;RN(?3nNXlE#zs_kg6U?#&;}oREq;st)3X z`u{joS2eAws$mlQ_NP|ZMir7mwf|@Go#t!NXV7nHx34K2zT-8LKHbY%m8j4JE1zB} z6}KsQjWbyDva?-Ri(Q_4YB_44lRnR_P0oG$hhopj4}}!?M>M4O+j`Tq=BvAmra~(iFRK5nhRMC@b>y$W`R$<0M>ZHL9B0I7@>-pvos851oT{MD4G+jF!Di!tN%$ue*dhq}Zs12-7B@72uG6 zp92b7>XtF=b!Z4`(M}UpzfPIfqI9>*rgM0LdV9a^cZP^_kfSKpbn<8v?%M0#Vnd6C z_aA>z4q|R_n+>;sMA2~>!dx@Cg#V{zrQzrhc%xvoRQ^(I`-App8xza=EG$`pe`)xr zMm+y{s}Caku(Wgg8XIfiK~DPFdi^wbQpPm1)ZyOmm#^>K9QjXDDn@~H|NBVxEex^| z_;>4wu!`*=Iv+_H0jO}B+f|)vr%}Pt$_EjHHA^J_M)|NR?&?1)cL#~H^62%Uiyc>r zte+i38dpDhDY0|^SCQZs_^(S&bamg|0Ol~1Pr=mN)Mm=b$(`c`gF~j*v$qj-wmn!r zhyUOUU05r81BNe&UZ}r=an6B&tgwS*3sV47O4E_^U+Llh>n|DHspzR@A6pRPSljHU zi@my~rXoFp@+!Nt32?(wQ_gp4DT!eSx^Bnvmg@~q7qOKOIwii-Wx);0E&0x~;LV-n z{plbprC6rNCQ4*()b*U07tt@K3-!20+k)CMBs|pu4}O!XCUYmiNl3;PDYRkt5S(b0 zIX5%d6~Tw`N-r6or^(oSg!?SNOMSRG)#AW}TpFt_zQ}KGj6|uhi9cP?ZzIlL^lD+k z^@Z0u45|IdQ@y5|h)NK&?f%*t@ON$gGQWBJaH*O4Sk2=h>gb2x(+v#E%x^%UP&GA| z76LX;`;Dc{$*!Kr+05r?PVFqIl{;k9-m@2O=oiGFK(oW*<3DghrG%)d|C+b@`$P&# znbW0gkGr%P%*Lau9(MgKhyIR`Q;uQC;o01t?KEg8h8O7UlXn= z>-*Tt-gv|btuY>}bLJ(bX7NbZBCGt8i-kPIo4z-Lbwp4b&BkM%(A)Fq7qBr)KGW}r zMWU6j4Zpsjcb%(0G3|~^mcw4#)<=pQ(Zy0!MZn)@wWoQiNj&Vk>*FJZ88kC7=gsOI zZBh=NE>;~f>bZQAg{dbw9(-xccNAs z*Vm`rjpZvIj@lNo>;3w(P|x5D@@3%ne%slJc1qJ8BD)Qu8PvkR3yryYN2`=*cBw=m znyu)GDiV1WL=c2Ilv5q6-*Wl^{xyX+HHJlc>@kZ9ZhHeA%Ow7=E0J^0-3Vdc?0s*n z-lg1>aS5%FDN*~g$Uwc!qUn8i-y2y0KGPZ<=0NT~EZ=L1j$Fz&;$JhwtC9Bx-YTZR z`@0SnUb_@sf^2Yuu5_N7f>`lJ1s6b4$qVKTZNuW1xJ)@QJw(DMOceH^cm$N9hnu zGXBQW44!}kB}3?n>70@FgYPxBeg(CgT)N-i{;J-4duFAu&6{H@)he(sZ+mT2h+qzr zYB9F^5_4sxtKGX5({zXrrIt#>P$|eGZdHok=71hkLDNU|-fP^O^(Lp`@jN>{nIFhi zUb#t0OUWp#l48~1uBiK7qmV^AyfgAQsb+~KSBVac@ms_CIp}%r2u_{PwA`Rsy-9;gwo7st{_H7XQPlsxAm*CQ(>V#3io7T*6+#*|Blk8wOj3@O zh(|E+ehJ7J4h-Y8mTahR(T1cb%(MtjOoHdiby3bS6y^oIpB2MO*{&BhAXiZBxBujZ zVM$t}B<3_2tU`GNkv38*g(t;9e9395*+doUb@3y`@H;EB9nf{s)NmH57ZaZ1xBT|j z@Zt>DpP@{FkQlQcejZYw@Zcs%g!fBvE|N>lu9BivKb4a^MVK zwhqGJTfbQ*aywHaX#AH*W%U^c@I=bStP+>5eA!ia4G#$k`2?13Krr`{i4TdK>X!)B za|gF{yxmf8n{8)hGVPZKq+AdR3&E&^Te=Axia#TADsFa2Z7M|nQ&h@Z_R`^S_}84f z5pw|lujIB%`|j#YUnLVLLqyX5?C?=!X#P;qo&8a1FlTT_0UQEhEOTWL?X zt^`Qga4W|$wd*;%>8l2y z#6f7Th?B%3aiZr5rOK|aEXzAtHYm`f=~*eyT?wy^n+C;(23F?XuY~ezoX15!pw<)? zdX#%o1@hr(_FYd?A%Uh$q(U;Atfo2%+a(z1@j7B{S_0)q-FIq*HeRT$QM)&zef{6l zMUomlSBq@my0~NeVEi8A<#J*oQt^nd@xdfkMjNBm`8*MDMp37NaA}a9 z4&<|%;4~R21idix*#ou&PyxC>MbW+UC9M1?)XT>gCM02=Agsqd`We9&FGFao^| zNXByc8z2b%*#|hF0bUTR6}i5{lfU~06zzl!i0{t}It7v2s9&$pVe4HCPDUNVwEkN^3p7VPzv-&649_UE}JUpt`+W_SBv?c2Q&B{8@cHSU$-IfAL zg@FZRBFg`J+5a7of2;mKx%dCi2+3OHfXYX@*chaix~jv%;(t+aq9cFnz`_`){ttWs z;;4Eme-}XIbNKd9_qngM@{!abN7249M@|NPas|kP**Mub0P_9-p|5+sCv_f3Sz$D+ zFv2CmK7d$7GG;?hX^P<1G$nIiUS0)fNC*ss(W0zS9Zt-9IB4N!=zpG-hD0ZQba)p= zGYuuA0pZvBe+60p^O2mYr;A!9^-nU7K@tBH(JnJl>zFz(Ly`=sgu{Nd_|;D|`y_c^ zDfo4E`nOyePE7oq2d0KG4yh)c%?yTTN&79_UL7f~pBOp6fs}DJv%S^lXt%J_TD&+w z6G5ZS4c)xJiGEA0hVu&z*qQ4}qWShl*2>0!1Q2D~WXwLv-vuBwyTMZ0)}whN2W>p)twUxK!mdQ9QEe_^VH2%x)23e zee>bM>mNCHNj>{ltkYMw;k_B+bW#x}ph?FEmCP}YPo$5kZtx`(onyiu`Pu^K7>l3YXLl(< z%KxBWYrM{RJ~vK=oL@xX*Bx(dT(i$kUf{_QHd~`F-`1wK{LO3l@yW?ujcLGnBwX2u zrJX;9AreI#4Mir(tz~j+Oce70Zl;Zl-zH|}wb0QcV9GrMf znW~mbBOpp2Iz6s>wmydc5#K(_wAx;oBLpZ9!P1x*sgf>SsPS5q&-;Z> zd#hXWTS+urh8?PWOS?UUIA!1?FTmZelezDGv<%!^Gw}g^wO#)4Ztrm{8g|aPZkp9; zyqsl^F3@?p@a^6#P+?O+k?lU*SsWTPb~F4ahxnb%M2|RAF1Ku1TZI?kI%AoW97oCu zSF1j_&331YIO@N`q5%aOT4k2@)i?M^c}4JRJp0`_fE^rK%3F_$5^1pK%-~b>Wo>7Q z-b66PNnmOAfUz)WFi>Y}wv``$X2ii0eEY$d0--|y(}r4>0o&qExc|nOc*gf|J~c(k zgDH+~B>T@@m{^78%RUu|oy6MB@84btO=2Nsw8i>`9G_p%Q*1LD+LBT+#T!}rC}uL> zj_r=DE}eA;{j}GT&;m`)JUBcQ*L(`MTLIXs&_*A19F%i%mJUKxZMrpJr~-?*M18Ia zI6Pl+i{~-m8H(v}%~g7t2Zmj19zY4B?{<`Cs-VFWlY5bBZ0gvXKpRNLSDuCJ+Z=5D zZhz4GN+zIDLWU_++4{kx*cWrX53V-LzbYSWrM&_RW(yyzjD`>J2LrHQAXG$RC*j43 zA&+`2#=w*xVPFVE0fWL@G1s}N{5##1*`Vg+Vp>-L#&@u=W}vS#seYt}DoD1MnRR;Z zXp@}F@q2CMgA~IpYs_44=6EY5KLwB_a=UBbTP#b5ZO4DqhXng)@h$sPNr0Rc+tfU9 zRSkKZ4w%ju@gvUQEi3{=T2ukNKe2sPj)c*igRnNLN07C?a>24A2@45C5e*K!5ES>G z-k5INq@|IoQOB*gLo{vI6wFCiAKQ~lszL0w>!$6YUO4y?#@ZdPS5Q7IWQZBpnF}Oud>3O#~VG115AP9^Rw|56D=Y;4r=!d z^tnRMf|F)S&~W^Tq5>zxO&+_Uw2#Q9&kt3sZI z2nZ8q$>hrxQ0MeX6G1TK4!p`M&t*mwQ{p9^gs9xn`*`stlQsy@YtXt3NcM*8Xu>Bd3klUYzQSuw~Cw8pP zq~ZQX%20GpwD=hj_|SXrN&k{;lHzU`#~B&vyk86@YgU4ZdAl;l2;KI@yJ;J%L+rH7 z%V*XW$fy=7x_27^;V+~5W)*n&S>`*rzD6X>i@HCQ$_H@Vua>bdUN{1Y{b_duYhVG@ zSFh=SI~oXU$qE^L$j#793|8?W3esO0{$A<`H3f7i&wSVkZ)3AfM|e?6$l2X}&am3^ zo~#BOvzDO)$KD*FqGLIc8Y(t2O4VLswV!Tn8C-=|S^XpE%%k&KDynSn z13f}%ke=Br$|^ALXEOgiP$)p+25q)~xk!B?;+0DZp_!4)o_c#avpikUXGmZQ+=hjWbJY{Kdf{jAj$1fymaKwTqL6 z_86B&)68Us@j|s9RKd%v+W0~JPXM-$DYo;H%mJS05X3cK&;1aP?bY6Eyt>(=a-dKQ zKNrb(5Rq5!lmRklaa|+LTD)8!WIF2XXtjJE)FSMB**V$(+R9^-g$wvD;a^4|MxUk2 z1RQycwgxl})})0YBbf&Hp+P}Go?oPbPMay2#B?nEw-w7Jvfm~Z#6z;!y>=Efd#b)7 z)8Wk*)Y#k=n&6;}JYwy9wUc6GnZO!!JRlSM=n-&}Q8pjL61lWlOls^C0!}d)NTFp* zqp*EHdZsf@;D&BqJdh8&!Y=@4VyYP_U@3L3V=&1EPPBdl2_f&%_w+xYlf0nRzsqU} z7i=~Jfv~m{LPSc%eS3YhTKT1bMWa4BJr4?8jRm-{r$6Uz=7QHJf;(i~tij#3(4whs z?%OLpV6SuC4X3zxT!caOS2OWrUAsOcr$TVe(0<>Oqxm7>WHl=}HO`tpz?CBrRr zi|pgU_bC8WblsWuzqZ->w+yA0tim@^Wvea{prR`I?r-oN{+ZX?lsh>h z%#YPN?)jLv*PV;je5oi^}R)3*KP>WWBKs(ni^LkbS`a;W!Qs$gUlbxME z{xtybfzf<{{<*MXN@Z6Fv|^qs$@~_knWg=W+@>`JHTDA^PZ{IoLG$K8eO_rVOsfY1 zY0(hoXutYBAUu$pq4J`T-03)-;(`plb9B+cDzztKDPNS8@W80ftO?PQ}7pQJl!V@!G@`mT4 zAplIN8K65KGx8$vLC-Qs?b1L+Dz@Q8WZQnRb2tK=$5t|6BL< zI5L-jrKEPzY*e2|Vsdv{(Lp00Bqzr{Mp{5tX(0-xR9 z`>W3Rb=67!n?MJF&fpj!zGsOfr1tq*nfl^9DUR>XQMN5%WoXZhX&0awgN|Q^0?k_? zgU|xrA{jkC^A9>AhpvW-gRCic@1zXe_ulz_C$o-}zDOm3V~-$ypA$N=?pcC1M4|^T zz4h?d6n+e#eNpdEQ&?GCe3pnKR$}(|3Aau*=3AEZcqxGZg!HLDZl9SEcoC4GHuR?& zp4v5)5auzC;tIdTG^-tkcnImS;}otpgj}YiJWYaUzqnobO1)#v@Rx~?uG8I|-zL)( z_M6#mDfi>vZ|M-4U0WR|P9*`-e*L?|3ZFlVQE5p#J^FceS)pT^?)8F&ORmVJ; z839~_aA(Qqs)$3LDUq*~lvD~1NLca!v_1+zo8@rg4`jtd7KHed`n%*29gSP2ziZ*Ee7JIum<;e_w?bmprF5JOIqjgrxBV& znipnB27f4`?Zl?U32}WN;(RaI)$c;b2c=HAC?VS3-o~U}Jp=|Q_r{(ta^$nEAm3#= z)yZiX7z%pB?dw)9!G3*k%XPSty?=!sHXeD2l8UEuUL;Em5h|i%4`rWIBuD{lW?bOhu{e9Jo^o> zq237-0HV>2dFW}#Dc1>$4-XW-xR@VHufjC@%f*+~nt_X|=B-Y+Ozi%YU!ST6kc+9R zwb@E$DbLOTwfMPeZE3FdRuQvrR4!XbI}0ZMZ)yFME-5{gPR8ecM3|+ShH{^)aSD$V z0w04BqB~;m&-;`Ko4DOS50PX{yI(qJ@D)b&aw}% z&JD>;%;sXCbxmDf1X|-4e@11+%MWx=+ND1g!=!8p+A@a<&ZNV^YI%Pz^#?}` zlh;u*d!#KK$u8|Pef%_esWWykQU!AM;P2l0P$oR`3ZKZX{C)VmzGN(~WoZLC%uC>Ba@X-`_4HmKDw z3X)>HCd_$rhoSpZoGi5iRNbY-gORaL9fJlFbszxy1@dxRLBD7lS=1;Bx&mlkI=7WmE7FkoJ|~QeH0YEd8Ff z$tI(4DrN_97Y*0VDd~owvsT+z_5XP@l>$>THH%cmIf+GrO?sn%2iS_EiJ3$kk{|Y9 zHIbZZC_r&iKy7KT*ysk!8>N{pjAUTo20?7tQ)@pU|75c9U3WRK|LPtCI_zL^u)IUZ zrS*@w8qH}^^)Qh`k-YXBVRd9k@Z4wv>_(!c7jWXCRqMZ4ev2Z0QjaTG3No^Iz}eJ* zs&Ou!IGk|52F@yQnx|x303ZLkw>I5o^%7uTgL4lXK<&!DS@Nl;Y8Y=~F&a0Ww;W+g zW#$cYq0}<*0F4w9P1gEd_*!(=u>>Q@zWR6sT%_2<*x_?|;-m3eff3*s> zDb9&*hA~BoaS!BCUC=K8p`{iKBi4U|2448wYnRr_RJ-nE)pMsm-&W>uj_!(-cZJz} zne}VS0D^&m4WR~%e~}D=(h*T&*)nD+Gt^l%?N-jw8IM6xUbk8@ zcaG@|UlZP~EIrsKURPyUEYR}wn70bh_Lm+o^4v@xDp+HTgnjq%>b7VX1)BgS9y6NK z7NmIx@Iftt<=O&I<_IHJUcMK0Z9%|*EU}|4qCHY(@eVjK4h*_?)zJc*+`+)qFCs{m zQQ!rMQhCxy`9g~fii->>cus)-#0gNm!#D^_F3D$W73Je#znu4lf9Cqt2BN_F!=>R4 zU_Bvj$6arBH>%K#r{pQm+8flCEyO~?2bf0e94urW|3DesBYdC-NlWkh!Gq4&!k#1q z-SuBRt_=``^})gRti#EYUH^O;9?Jng*UN^EJ8J-ZQ-329u(pbz_;*#+!22g^XU=J)#YbF!U|lIZQ;yLZ5Q^K$?GoRq z@!LA$`FL6srcXeOKf=vp>31*0k_(7FD}wEAS?6MvZKX`-vMJ1$seAw^q(k@5cR{Ua z7XZ>wbnMIW6+Rw*Mm@V!k89j!^v&wW`DuYhLCzZ`7T@w5Y&hXY7^i%`^lvO>!|#*) zJCy@cwLH-`YTzZ^_bI&lzy>mUJo?is#QvP>Zty>Ou^o`5pK?()6QNw^$=JJZdrESH z0*#2bC#7!wWH;&NDv?$Ab%$tEM8+rbKUrAmSHshM3EmtZwJcfh@=`eDzb_Cm3j&9- Zl6}+Z`***of&Wv1s48kHl*wC%{1=vwX#)TN literal 5921 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 P8(?K-XIg#n#=XA*<+-G# diff --git a/src/FeaturesPlugin/doc/images/intersection_property_panel.png b/src/FeaturesPlugin/doc/images/intersection_property_panel.png index d3fd35333e1cdcb208ba57c2c04fce90226b6f4a..b439ac3e49ab24bf91a6d0e2efb740d34561bf75 100644 GIT binary patch literal 8732 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 SLg3FEAcTyvbfwg*z<&dO9()P_ literal 7351 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 + + + + + diff --git a/src/FeaturesPlugin/partition_widget.xml b/src/FeaturesPlugin/partition_widget.xml index ad5e97ef5..6a2eda743 100644 --- a/src/FeaturesPlugin/partition_widget.xml +++ b/src/FeaturesPlugin/partition_widget.xml @@ -7,5 +7,16 @@ clear_in_neutral_point="false"> + + + + + diff --git a/src/FeaturesPlugin/tests.set b/src/FeaturesPlugin/tests.set index 302daa49b..76c999390 100644 --- a/src/FeaturesPlugin/tests.set +++ b/src/FeaturesPlugin/tests.set @@ -529,6 +529,10 @@ SET(TEST_NAMES_PARA Test23885.py TestNormalToFace.py TestLoft.py + TestBooleanCut_Fuzzy_1.py + TestBooleanCut_Fuzzy_2.py + TestBooleanFuse_Fuzzy.py + TestBooleanCommon_Fuzzy.py ) SET(TEST_NAMES_SEQ diff --git a/src/FeaturesPlugin/union_widget.xml b/src/FeaturesPlugin/union_widget.xml index 6bbc32395..f8676877b 100644 --- a/src/FeaturesPlugin/union_widget.xml +++ b/src/FeaturesPlugin/union_widget.xml @@ -7,6 +7,17 @@ concealment="true"> + + + + + diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Boolean.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Boolean.cpp index 2812b0ee1..6e3c60df1 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_Boolean.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Boolean.cpp @@ -27,42 +27,47 @@ #include #include + //================================================================================================= GeomAlgoAPI_Boolean::GeomAlgoAPI_Boolean(const GeomShapePtr theObject, const GeomShapePtr theTool, - const GeomAlgoAPI_Tools::BOPType theOperationType) + const GeomAlgoAPI_Tools::BOPType theOperationType, + const double theFuzzy/*= 1.e-8*/) { ListOfShape aListWithObject, aListWithTool; aListWithObject.push_back(theObject); aListWithTool.push_back(theTool); - build(aListWithObject, aListWithTool, theOperationType); + build(aListWithObject, aListWithTool, theOperationType, theFuzzy); } //================================================================================================= GeomAlgoAPI_Boolean::GeomAlgoAPI_Boolean(const GeomShapePtr theObject, const ListOfShape& theTools, - const GeomAlgoAPI_Tools::BOPType theOperationType) + const GeomAlgoAPI_Tools::BOPType theOperationType, + const double theFuzzy/*= 1.e-8*/) { ListOfShape aListWithObject; aListWithObject.push_back(theObject); - build(aListWithObject, theTools, theOperationType); + build(aListWithObject, theTools, theOperationType, theFuzzy); } //================================================================================================= GeomAlgoAPI_Boolean::GeomAlgoAPI_Boolean(const ListOfShape& theObjects, const ListOfShape& theTools, - const GeomAlgoAPI_Tools::BOPType theOperationType) + const GeomAlgoAPI_Tools::BOPType theOperationType, + const double theFuzzy/*= 1.e-8*/) { - build(theObjects, theTools, theOperationType); + build(theObjects, theTools, theOperationType, theFuzzy); } //================================================================================================= void GeomAlgoAPI_Boolean::build(const ListOfShape& theObjects, const ListOfShape& theTools, - const GeomAlgoAPI_Tools::BOPType theOperationType) + const GeomAlgoAPI_Tools::BOPType theOperationType, + const double theFuzzy) { - if(theObjects.empty() || theTools.empty()) { + if (theObjects.empty() || theTools.empty()) { return; } @@ -111,7 +116,9 @@ void GeomAlgoAPI_Boolean::build(const ListOfShape& theObjects, aBuilder->SetRunParallel(bRunParallel); // Set fuzzy value to eliminate thin results - static const Standard_Real aFuzzy = 1.e-5; + // => Either use the value set by the user (greater or equal than minimum valid value 1.e-7) + // => or use the old default value of 1.e-5 + Standard_Real aFuzzy = (theFuzzy >= 1.e-7 ? theFuzzy : 1.e-5); aBuilder->SetFuzzyValue(aFuzzy); // Building and getting result. @@ -139,11 +146,13 @@ void GeomAlgoAPI_Boolean::build(const ListOfShape& theObjects, this->setDone(true); } +//================================================================================================= static bool isHistoryType(TopAbs_ShapeEnum theType) { return theType == TopAbs_VERTEX || theType == TopAbs_EDGE || theType == TopAbs_FACE || theType == TopAbs_SOLID; } +//================================================================================================= /// searches the corresponding result for theOld static void searchResult(const TopoDS_Shape& theOld, const TopoDS_Shape& theResult, BOPAlgo_BOP* theBuilder, TopTools_MapOfShape& theNews) @@ -179,6 +188,7 @@ static void searchResult(const TopoDS_Shape& theOld, const TopoDS_Shape& theResu } } +//================================================================================================= // check the shape is on the higher level of compound or compsolid bool isInComp(const TopoDS_Shape& theComp, const TopoDS_Shape& theShape) { if (theComp.ShapeType() == TopAbs_COMPOUND || theComp.ShapeType() == TopAbs_COMPSOLID) { diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Boolean.h b/src/GeomAlgoAPI/GeomAlgoAPI_Boolean.h index f1c86be08..0182ff054 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_Boolean.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Boolean.h @@ -34,20 +34,41 @@ class GeomAlgoAPI_Boolean : public GeomAlgoAPI_MakeShape public: /// Constructor. + /// \param[in] theObject the main object. + /// \param[in] theTool the tool object. + /// \param[in] theOperationType type of boolean operation. + /// \param[in] theFuzzy additional tolerance value. + /// If the fuzzy value is below the minimum tolerance value (1.e-7), the + /// boolean operation will use a default additional tolerance value of 1.e-5. GEOMALGOAPI_EXPORT GeomAlgoAPI_Boolean(const GeomShapePtr theObject, const GeomShapePtr theTool, - const GeomAlgoAPI_Tools::BOPType theOperationType); + const GeomAlgoAPI_Tools::BOPType theOperationType, + const double theFuzzy = 1.e-8); /// Constructor. + /// \param[in] theObject the main object. + /// \param[in] theTools list of tools. + /// \param[in] theOperationType type of boolean operation. + /// \param[in] theFuzzy additional tolerance value. + /// If the fuzzy value is below the minimum tolerance value (1.e-7), the + /// boolean operation will use a default additional tolerance value of 1.e-5. GEOMALGOAPI_EXPORT GeomAlgoAPI_Boolean(const GeomShapePtr theObject, const ListOfShape& theTools, - const GeomAlgoAPI_Tools::BOPType theOperationType); + const GeomAlgoAPI_Tools::BOPType theOperationType, + const double theFuzzy = 1.e-8); /// Constructor. + /// \param[in] theObjects list of main objects. + /// \param[in] theTools list of tools. + /// \param[in] theOperationType type of boolean operation. + /// \param[in] theFuzzy additional tolerance value. + /// If the fuzzy value is below the minimum tolerance value (1.e-7), the + /// boolean operation will use a default additional tolerance value of 1.e-5. GEOMALGOAPI_EXPORT GeomAlgoAPI_Boolean(const ListOfShape& theObjects, const ListOfShape& theTools, - const GeomAlgoAPI_Tools::BOPType theOperationType); + const GeomAlgoAPI_Tools::BOPType theOperationType, + const double theFuzzy = 1.e-8); /// Redefinition of the generic method for the Fuse problem: OCCT 30481 GEOMALGOAPI_EXPORT virtual void modified(const GeomShapePtr theOldShape, @@ -57,7 +78,8 @@ private: /// Builds resulting shape. void build(const ListOfShape& theObjects, const ListOfShape& theTools, - const GeomAlgoAPI_Tools::BOPType theOperationType); + const GeomAlgoAPI_Tools::BOPType theOperationType, + const double theFuzzy); }; #endif diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Intersection.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Intersection.cpp index 4958c3248..8ab6a1b07 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_Intersection.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Intersection.cpp @@ -24,19 +24,22 @@ #include #include + //================================================================================================== -GeomAlgoAPI_Intersection::GeomAlgoAPI_Intersection(const ListOfShape& theObjects) +GeomAlgoAPI_Intersection::GeomAlgoAPI_Intersection(const ListOfShape& theObjects, const double theFuzzy) : myFiller(0) { - build(theObjects); + build(theObjects, theFuzzy); } +//================================================================================================== GeomAlgoAPI_Intersection::~GeomAlgoAPI_Intersection() { if (myFiller) delete (BOPAlgo_PaveFiller*)myFiller; } + //================================================================================================== -void GeomAlgoAPI_Intersection::build(const ListOfShape& theObjects) +void GeomAlgoAPI_Intersection::build(const ListOfShape& theObjects, const double theFuzzy) { if (theObjects.empty()) { return; @@ -64,6 +67,7 @@ void GeomAlgoAPI_Intersection::build(const ListOfShape& theObjects) aDSFiller->SetRunParallel(false); aDSFiller->SetNonDestructive(false); aDSFiller->SetGlue(BOPAlgo_GlueOff); + if (theFuzzy >= 1.e-7) aDSFiller->SetFuzzyValue(theFuzzy); // optimization for the issue #2399 BOPAlgo_SectionAttribute theSecAttr(Standard_True, @@ -79,6 +83,7 @@ void GeomAlgoAPI_Intersection::build(const ListOfShape& theObjects) anOperation->SetArguments(anObjects); anOperation->SetRunParallel(false); anOperation->SetCheckInverted(true); + if (theFuzzy >= 1.e-7) anOperation->SetFuzzyValue(theFuzzy); anOperation->PerformWithFiller(*aDSFiller); // it references a filler fields, so keep the filler myFiller = 0; diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Intersection.h b/src/GeomAlgoAPI/GeomAlgoAPI_Intersection.h index 8762e2c0a..39228ebc3 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_Intersection.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Intersection.h @@ -34,15 +34,18 @@ class GeomAlgoAPI_Intersection : public GeomAlgoAPI_MakeShape public: /// \brief Constructor. /// \param[in] theObjects list of objects. - /// \param[in] theTools list of tools. - GEOMALGOAPI_EXPORT GeomAlgoAPI_Intersection(const ListOfShape& theObjects); + /// \param[in] theFuzzy additional tolerance value. + /// If the fuzzy value is below the minimum tolerance value (1.e-7), the + /// algorithm will use the default internal fuzzy value from OCCT. + GEOMALGOAPI_EXPORT GeomAlgoAPI_Intersection(const ListOfShape& theObjects, + const double theFuzzy = 1.e-8); /// Destructor to erase the filler GEOMALGOAPI_EXPORT virtual ~GeomAlgoAPI_Intersection(); private: /// Builds resulting shape. - void build(const ListOfShape& theObjects); + void build(const ListOfShape& theObjects, const double theFuzzy); }; diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Partition.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Partition.cpp index cfd2c967f..fe49e167a 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_Partition.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Partition.cpp @@ -127,9 +127,10 @@ static void sortCompound(TopoDS_Shape& theCompound, GEOMAlgo_Splitter* theOperat //================================================================================================= GeomAlgoAPI_Partition::GeomAlgoAPI_Partition(const ListOfShape& theObjects, - const ListOfShape& theTools) + const ListOfShape& theTools, + const double theFuzzy) { - build(theObjects, theTools); + build(theObjects, theTools, theFuzzy); } static void prepareShapes(const TopoDS_Shape& theShape, @@ -150,7 +151,8 @@ static void prepareShapes(const TopoDS_Shape& theShape, //================================================================================================= void GeomAlgoAPI_Partition::build(const ListOfShape& theObjects, - const ListOfShape& theTools) + const ListOfShape& theTools, + const double theFuzzy) { if (theObjects.empty()) { return; @@ -200,6 +202,8 @@ void GeomAlgoAPI_Partition::build(const ListOfShape& theObjects, Standard_Boolean bRunParallel = Standard_True; anOperation->SetRunParallel(bRunParallel); + if (theFuzzy >= 1.e-7) anOperation->SetFuzzyValue(theFuzzy); + // Building and getting result. anOperation->Perform(); if (anOperation->HasErrors()) diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Partition.h b/src/GeomAlgoAPI/GeomAlgoAPI_Partition.h index 5676a660b..b04982ad2 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_Partition.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Partition.h @@ -32,13 +32,20 @@ class GeomAlgoAPI_Partition : public GeomAlgoAPI_MakeShape { public: /// Constructor. + /// \param[in] theObjects list of main objects. + /// \param[in] theTools list of tools. + /// \param[in] theFuzzy additional tolerance value. + /// If the fuzzy value is below the minimum tolerance value (1.e-7), the + /// algorithm will use the default internal fuzzy value from OCCT. GEOMALGOAPI_EXPORT GeomAlgoAPI_Partition(const ListOfShape& theObjects, - const ListOfShape& theTools); + const ListOfShape& theTools, + const double theFuzzy = 1.e-8); private: /// Builds resulting shape. void build(const ListOfShape& theObjects, - const ListOfShape& theTools); + const ListOfShape& theTools, + const double theFuzzy); }; #endif diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_PaveFiller.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_PaveFiller.cpp index 1ac8829a2..3801c8064 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_PaveFiller.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_PaveFiller.cpp @@ -27,17 +27,20 @@ #include #include + //================================================================================================= GeomAlgoAPI_PaveFiller::GeomAlgoAPI_PaveFiller(const ListOfShape& theListOfShape, - const bool theIsMakeCompSolids) + const bool theIsMakeCompSolids, + const double theFuzzy) { - build(theListOfShape, theIsMakeCompSolids); + build(theListOfShape, theIsMakeCompSolids, theFuzzy); } //================================================================================================= void GeomAlgoAPI_PaveFiller::build(const ListOfShape& theListOfShape, - const bool theIsMakeCompSolids) + const bool theIsMakeCompSolids, + const double theFuzzy) { BOPAlgo_PaveFiller* aPaveFiller = new BOPAlgo_PaveFiller; TopTools_ListOfShape aListOfShape; @@ -53,6 +56,7 @@ void GeomAlgoAPI_PaveFiller::build(const ListOfShape& theListOfShape, } } aPaveFiller->SetArguments(aListOfShape); + if (theFuzzy >= 1.e-7) aPaveFiller->SetFuzzyValue(theFuzzy); aPaveFiller->Perform(); if (aPaveFiller->HasErrors()) return; @@ -61,6 +65,7 @@ void GeomAlgoAPI_PaveFiller::build(const ListOfShape& theListOfShape, this->setImpl(aBuilder); this->setBuilderType(OCCT_BOPAlgo_Builder); aBuilder->SetArguments(aListOfShape); + if (theFuzzy >= 1.e-7) aBuilder->SetFuzzyValue(theFuzzy); aBuilder->PerformWithFiller(*aPaveFiller); if (aBuilder->HasErrors()) return; diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_PaveFiller.h b/src/GeomAlgoAPI/GeomAlgoAPI_PaveFiller.h index f068642d8..913c2960f 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_PaveFiller.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_PaveFiller.h @@ -35,12 +35,16 @@ public: /// \brief Constructor. /// \param[in] theListOfShape list of shape which should be splitted. /// \param[in] theIsMakeCompSolids if true gather shapes with shared faces to compsolids. + /// \param[in] theFuzzy additional tolerance value. + /// If the fuzzy value is below the minimum tolerance value (1.e-7), the + /// algorithm will use the default internal fuzzy value from OCCT. GEOMALGOAPI_EXPORT GeomAlgoAPI_PaveFiller(const ListOfShape& theListOfShape, - const bool theIsMakeCompSolids = false); + const bool theIsMakeCompSolids = false, + const double theFuzzy = 1.e-8); private: /// Builds resulting shape. - void build(const ListOfShape& theListOfShape, const bool theIsMakeCompSolids); + void build(const ListOfShape& theListOfShape, const bool theIsMakeCompSolids, const double theFuzzy); }; #endif -- 2.39.2