From 883ac186ac2c764c6209cb8ea8043e3bcadc3de9 Mon Sep 17 00:00:00 2001 From: jfa Date: Mon, 28 Oct 2019 14:51:31 +0300 Subject: [PATCH] Task #3015 3.1. To add a mode 'through all' for features ExtrusionCut and ExtrusionFuse --- .../FeaturesAPI_ExtrusionBoolean.cpp | 108 ++++++++++++ .../FeaturesAPI_ExtrusionBoolean.h | 56 +++++++ src/FeaturesPlugin/CMakeLists.txt | 2 + .../FeaturesPlugin_Extrusion.cpp | 84 ++++++---- src/FeaturesPlugin/FeaturesPlugin_Extrusion.h | 13 ++ .../FeaturesPlugin_ExtrusionBoolean.cpp | 37 +++++ .../FeaturesPlugin_ExtrusionBoolean.h | 4 + .../FeaturesPlugin_ExtrusionFuse.cpp | 132 ++++++++++++++- .../FeaturesPlugin_ExtrusionFuse.h | 5 +- .../Test/TestExtrusionCut_ThroughAll.py | 71 ++++++++ .../Test/TestExtrusionFuse_ThroughAll.py | 56 +++++++ .../doc/extrusionFuseFeature.rst | 49 +++++- .../extrusion_fuse_through_all_result.png | Bin 0 -> 18397 bytes src/FeaturesPlugin/extrusioncut_widget.xml | 2 + src/FeaturesPlugin/extrusionfuse_widget.xml | 2 + src/GeomAlgoAPI/CMakeLists.txt | 2 + src/GeomAlgoAPI/GeomAlgoAPI_Boolean.h | 2 +- src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp | 156 ++++++++++++++++-- src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h | 11 ++ src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.cpp | 88 ++++++++++ src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.h | 46 ++++++ 21 files changed, 874 insertions(+), 52 deletions(-) create mode 100644 src/FeaturesPlugin/Test/TestExtrusionCut_ThroughAll.py create mode 100644 src/FeaturesPlugin/Test/TestExtrusionFuse_ThroughAll.py create mode 100644 src/FeaturesPlugin/doc/images/extrusion_fuse_through_all_result.png create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.cpp create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.h diff --git a/src/FeaturesAPI/FeaturesAPI_ExtrusionBoolean.cpp b/src/FeaturesAPI/FeaturesAPI_ExtrusionBoolean.cpp index 934a9ae02..af4102734 100644 --- a/src/FeaturesAPI/FeaturesAPI_ExtrusionBoolean.cpp +++ b/src/FeaturesAPI/FeaturesAPI_ExtrusionBoolean.cpp @@ -155,6 +155,8 @@ void FeaturesAPI_ExtrusionBoolean::dump(ModelHighAPI_Dumper& theDumper) const theDumper << ", " << anAttrToObject << ", " << anAttrToOffset << ", " << anAttrFromObject << ", " << anAttrFromOffset; + } else { + // Through all } AttributeSelectionListPtr anAttrBoolObjects = @@ -183,6 +185,20 @@ FeaturesAPI_ExtrusionCut::FeaturesAPI_ExtrusionCut( initialize(); } +//================================================================================================== +FeaturesAPI_ExtrusionCut::FeaturesAPI_ExtrusionCut( + const std::shared_ptr& theFeature, + const std::list& theBaseObjects, + const std::list& theBooleanObjects) +: FeaturesAPI_ExtrusionBoolean(theFeature) +{ + if(initialize()) { + fillAttribute(theBaseObjects, mybaseObjects); + fillAttribute(FeaturesPlugin_Extrusion::CREATION_METHOD_THROUGH_ALL(), mycreationMethod); + setBooleanObjects(theBooleanObjects); + } +} + //================================================================================================== FeaturesAPI_ExtrusionCut::FeaturesAPI_ExtrusionCut( const std::shared_ptr& theFeature, @@ -198,6 +214,22 @@ FeaturesAPI_ExtrusionCut::FeaturesAPI_ExtrusionCut( } } +//================================================================================================== +FeaturesAPI_ExtrusionCut::FeaturesAPI_ExtrusionCut( + const std::shared_ptr& theFeature, + const std::list& theBaseObjects, + const ModelHighAPI_Selection& theDirection, + const std::list& theBooleanObjects) +: FeaturesAPI_ExtrusionBoolean(theFeature) +{ + if(initialize()) { + fillAttribute(theBaseObjects, mybaseObjects); + fillAttribute(theDirection, mydirection); + fillAttribute(FeaturesPlugin_Extrusion::CREATION_METHOD_THROUGH_ALL(), mycreationMethod); + setBooleanObjects(theBooleanObjects); + } +} + //================================================================================================== FeaturesAPI_ExtrusionCut::FeaturesAPI_ExtrusionCut( const std::shared_ptr& theFeature, @@ -287,6 +319,17 @@ FeaturesAPI_ExtrusionCut::FeaturesAPI_ExtrusionCut( } } +//================================================================================================== +ExtrusionCutPtr addExtrusionCut(const std::shared_ptr& thePart, + const std::list& theBaseObjects, + const std::list& theBooleanObjects) +{ + std::shared_ptr aFeature = + thePart->addFeature(FeaturesPlugin_ExtrusionCut::ID()); + return ExtrusionCutPtr(new FeaturesAPI_ExtrusionCut(aFeature, theBaseObjects, + theBooleanObjects)); +} + //================================================================================================== ExtrusionCutPtr addExtrusionCut(const std::shared_ptr& thePart, const std::list& theBaseObjects, @@ -299,6 +342,18 @@ ExtrusionCutPtr addExtrusionCut(const std::shared_ptr& thePar theSize, theBooleanObjects)); } +//================================================================================================== +ExtrusionCutPtr addExtrusionCut(const std::shared_ptr& thePart, + const std::list& theBaseObjects, + const ModelHighAPI_Selection& theDirection, + const std::list& theBooleanObjects) +{ + std::shared_ptr aFeature = + thePart->addFeature(FeaturesPlugin_ExtrusionCut::ID()); + return ExtrusionCutPtr(new FeaturesAPI_ExtrusionCut(aFeature, theBaseObjects, theDirection, + theBooleanObjects)); +} + //================================================================================================== ExtrusionCutPtr addExtrusionCut(const std::shared_ptr& thePart, const std::list& theBaseObjects, @@ -394,6 +449,20 @@ FeaturesAPI_ExtrusionFuse::FeaturesAPI_ExtrusionFuse( initialize(); } +//================================================================================================== +FeaturesAPI_ExtrusionFuse::FeaturesAPI_ExtrusionFuse( + const std::shared_ptr& theFeature, + const std::list& theBaseObjects, + const std::list& theBooleanObjects) +: FeaturesAPI_ExtrusionBoolean(theFeature) +{ + if(initialize()) { + fillAttribute(theBaseObjects, mybaseObjects); + fillAttribute(FeaturesPlugin_Extrusion::CREATION_METHOD_THROUGH_ALL(), mycreationMethod); + setBooleanObjects(theBooleanObjects); + } +} + //================================================================================================== FeaturesAPI_ExtrusionFuse::FeaturesAPI_ExtrusionFuse( const std::shared_ptr& theFeature, @@ -409,6 +478,22 @@ FeaturesAPI_ExtrusionFuse::FeaturesAPI_ExtrusionFuse( } } +//================================================================================================== +FeaturesAPI_ExtrusionFuse::FeaturesAPI_ExtrusionFuse( + const std::shared_ptr& theFeature, + const std::list& theBaseObjects, + const ModelHighAPI_Selection& theDirection, + const std::list& theBooleanObjects) +: FeaturesAPI_ExtrusionBoolean(theFeature) +{ + if(initialize()) { + fillAttribute(theBaseObjects, mybaseObjects); + fillAttribute(theDirection, mydirection); + fillAttribute(FeaturesPlugin_Extrusion::CREATION_METHOD_THROUGH_ALL(), mycreationMethod); + setBooleanObjects(theBooleanObjects); + } +} + //================================================================================================== FeaturesAPI_ExtrusionFuse::FeaturesAPI_ExtrusionFuse( const std::shared_ptr& theFeature, @@ -498,6 +583,17 @@ FeaturesAPI_ExtrusionFuse::FeaturesAPI_ExtrusionFuse( } } +//================================================================================================== +ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr& thePart, + const std::list& theBaseObjects, + const std::list& theBooleanObjects) +{ + std::shared_ptr aFeature = + thePart->addFeature(FeaturesPlugin_ExtrusionFuse::ID()); + return ExtrusionFusePtr(new FeaturesAPI_ExtrusionFuse(aFeature, theBaseObjects, + theBooleanObjects)); +} + //================================================================================================== ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr& thePart, const std::list& theBaseObjects, @@ -510,6 +606,18 @@ ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr& theP theSize, theBooleanObjects)); } +//================================================================================================== +ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr& thePart, + const std::list& theBaseObjects, + const ModelHighAPI_Selection& theDirection, + const std::list& theBooleanObjects) +{ + std::shared_ptr aFeature = + thePart->addFeature(FeaturesPlugin_ExtrusionFuse::ID()); + return ExtrusionFusePtr(new FeaturesAPI_ExtrusionFuse(aFeature, theBaseObjects, + theDirection, theBooleanObjects)); +} + //================================================================================================== ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr& thePart, const std::list& theBaseObjects, diff --git a/src/FeaturesAPI/FeaturesAPI_ExtrusionBoolean.h b/src/FeaturesAPI/FeaturesAPI_ExtrusionBoolean.h index 42a479119..c5777d319 100644 --- a/src/FeaturesAPI/FeaturesAPI_ExtrusionBoolean.h +++ b/src/FeaturesAPI/FeaturesAPI_ExtrusionBoolean.h @@ -130,6 +130,12 @@ public: FEATURESAPI_EXPORT explicit FeaturesAPI_ExtrusionCut(const std::shared_ptr& theFeature); + /// Constructor with values. + FEATURESAPI_EXPORT + explicit FeaturesAPI_ExtrusionCut(const std::shared_ptr& theFeature, + const std::list& theBaseObjects, + const std::list& theBooleanObjects); + /// Constructor with values. FEATURESAPI_EXPORT explicit FeaturesAPI_ExtrusionCut(const std::shared_ptr& theFeature, @@ -137,6 +143,13 @@ public: const ModelHighAPI_Double& theSize, const std::list& theBooleanObjects); + /// Constructor with values. + FEATURESAPI_EXPORT + explicit FeaturesAPI_ExtrusionCut(const std::shared_ptr& theFeature, + const std::list& theBaseObjects, + const ModelHighAPI_Selection& theDirection, + const std::list& theBooleanObjects); + /// Constructor with values. FEATURESAPI_EXPORT explicit FeaturesAPI_ExtrusionCut(const std::shared_ptr& theFeature, @@ -187,6 +200,13 @@ public: /// Pointer on ExtrusionCut object. typedef std::shared_ptr ExtrusionCutPtr; +/// \ingroup CPPHighAPI +/// \brief Create ExtrusionCut feature. +FEATURESAPI_EXPORT +ExtrusionCutPtr addExtrusionCut(const std::shared_ptr& thePart, + const std::list& theBaseObjects, + const std::list& theBooleanObjects); + /// \ingroup CPPHighAPI /// \brief Create ExtrusionCut feature. FEATURESAPI_EXPORT @@ -195,6 +215,14 @@ ExtrusionCutPtr addExtrusionCut(const std::shared_ptr& thePar const ModelHighAPI_Double& theSize, const std::list& theBooleanObjects); +/// \ingroup CPPHighAPI +/// \brief Create ExtrusionCut feature. +FEATURESAPI_EXPORT +ExtrusionCutPtr addExtrusionCut(const std::shared_ptr& thePart, + const std::list& theBaseObjects, + const ModelHighAPI_Selection& theDirection, + const std::list& theBooleanObjects); + /// \ingroup CPPHighAPI /// \brief Create ExtrusionCut feature. FEATURESAPI_EXPORT @@ -259,6 +287,12 @@ public: FEATURESAPI_EXPORT explicit FeaturesAPI_ExtrusionFuse(const std::shared_ptr& theFeature); + /// Constructor with values. + FEATURESAPI_EXPORT + explicit FeaturesAPI_ExtrusionFuse(const std::shared_ptr& theFeature, + const std::list& theBaseObjects, + const std::list& theBooleanObjects); + /// Constructor with values. FEATURESAPI_EXPORT explicit FeaturesAPI_ExtrusionFuse(const std::shared_ptr& theFeature, @@ -266,6 +300,13 @@ public: const ModelHighAPI_Double& theSize, const std::list& theBooleanObjects); + /// Constructor with values. + FEATURESAPI_EXPORT + explicit FeaturesAPI_ExtrusionFuse(const std::shared_ptr& theFeature, + const std::list& theBaseObjects, + const ModelHighAPI_Selection& theDirection, + const std::list& theBooleanObjects); + /// Constructor with values. FEATURESAPI_EXPORT explicit FeaturesAPI_ExtrusionFuse(const std::shared_ptr& theFeature, @@ -316,6 +357,13 @@ public: /// Pointer on ExtrusionFuse object. typedef std::shared_ptr ExtrusionFusePtr; +/// \ingroup CPPHighAPI +/// \brief Create ExtrusionFuse feature. +FEATURESAPI_EXPORT +ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr& thePart, + const std::list& theBaseObjects, + const std::list& theBooleanObjects); + /// \ingroup CPPHighAPI /// \brief Create ExtrusionFuse feature. FEATURESAPI_EXPORT @@ -324,6 +372,14 @@ ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr& theP const ModelHighAPI_Double& theSize, const std::list& theBooleanObjects); +/// \ingroup CPPHighAPI +/// \brief Create ExtrusionFuse feature. +FEATURESAPI_EXPORT +ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr& thePart, + const std::list& theBaseObjects, + const ModelHighAPI_Selection& theDirection, + const std::list& theBooleanObjects); + /// \ingroup CPPHighAPI /// \brief Create ExtrusionFuse feature. FEATURESAPI_EXPORT diff --git a/src/FeaturesPlugin/CMakeLists.txt b/src/FeaturesPlugin/CMakeLists.txt index 5316c8c07..224e94084 100644 --- a/src/FeaturesPlugin/CMakeLists.txt +++ b/src/FeaturesPlugin/CMakeLists.txt @@ -178,9 +178,11 @@ ADD_UNIT_TESTS(TestExtrusion.py TestExtrusionCut_BySize.py TestExtrusionCut_ByPlanesAndOffsets.py TestExtrusionCut_ByFaces.py + TestExtrusionCut_ThroughAll.py TestExtrusionFuse.py TestExtrusionFuse_BySize.py TestExtrusionFuse_ByPlanesAndOffsets.py + TestExtrusionFuse_ThroughAll.py TestExtrusion_ErrorMsg.py TestExtrusion_ZeroOffsetError.py TestExtrusion_ByFaces01.py diff --git a/src/FeaturesPlugin/FeaturesPlugin_Extrusion.cpp b/src/FeaturesPlugin/FeaturesPlugin_Extrusion.cpp index bfcbde007..57b1ba874 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Extrusion.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Extrusion.cpp @@ -101,53 +101,20 @@ bool FeaturesPlugin_Extrusion::makeExtrusions(ListOfShape& theBaseShapes, getBaseShapes(theBaseShapes); //Getting direction. - static const std::string aSelectionError = "Error: The direction shape selection is bad."; - AttributeSelectionPtr aSelection = selection(DIRECTION_OBJECT_ID()); - GeomShapePtr aShape = aSelection->value(); - if (!aShape.get()) { - if (aSelection->context().get()) { - aShape = aSelection->context()->shape(); - } - } - - GeomEdgePtr anEdge; - if (aShape.get()) { - if (aShape->isEdge()) - { - anEdge = aShape->edge(); - } - else if (aShape->isCompound()) - { - GeomAPI_ShapeIterator anIt(aShape); - anEdge = anIt.current()->edge(); - } - } - std::shared_ptr aDir; - if(anEdge.get()) { - if(anEdge->isLine()) { - aDir = anEdge->line()->direction(); - } - } + getDirection(aDir); // Getting sizes. double aToSize = 0.0; double aFromSize = 0.0; - - if(string(CREATION_METHOD())->value() == CREATION_METHOD_BY_SIZES()) { - aToSize = real(TO_SIZE_ID())->value(); - aFromSize = real(FROM_SIZE_ID())->value(); - } else { - aToSize = real(TO_OFFSET_ID())->value(); - aFromSize = real(FROM_OFFSET_ID())->value(); - } + getSizes(aToSize, aFromSize); // Getting bounding planes. GeomShapePtr aToShape; GeomShapePtr aFromShape; if(string(CREATION_METHOD())->value() == CREATION_METHOD_BY_PLANES()) { - aSelection = selection(TO_OBJECT_ID()); + AttributeSelectionPtr aSelection = selection(TO_OBJECT_ID()); if(aSelection.get()) { aToShape = std::dynamic_pointer_cast(aSelection->value()); if(!aToShape.get() && aSelection->context().get()) { @@ -214,3 +181,48 @@ void FeaturesPlugin_Extrusion::storeResultWithBoundaries( setResult(aResultBody, theIndex); } + +//================================================================================================= +void FeaturesPlugin_Extrusion::getDirection(std::shared_ptr& theDir) +{ + static const std::string aSelectionError = "Error: The direction shape selection is bad."; + AttributeSelectionPtr aSelection = selection(DIRECTION_OBJECT_ID()); + GeomShapePtr aShape = aSelection->value(); + if (!aShape.get()) { + if (aSelection->context().get()) { + aShape = aSelection->context()->shape(); + } + } + + GeomEdgePtr anEdge; + if (aShape.get()) { + if (aShape->isEdge()) + { + anEdge = aShape->edge(); + } + else if (aShape->isCompound()) + { + GeomAPI_ShapeIterator anIt(aShape); + anEdge = anIt.current()->edge(); + } + } + + if (anEdge.get()) { + if (anEdge->isLine()) { + theDir = anEdge->line()->direction(); + } + } +} + +//================================================================================================= +void FeaturesPlugin_Extrusion::getSizes(double& theToSize, double& theFromSize) +{ + if (string(CREATION_METHOD())->value() == CREATION_METHOD_BY_SIZES()) { + theToSize = real(TO_SIZE_ID())->value(); + theFromSize = real(FROM_SIZE_ID())->value(); + } if (string(CREATION_METHOD())->value() == CREATION_METHOD_BY_PLANES()) { + theToSize = real(TO_OFFSET_ID())->value(); + theFromSize = real(FROM_OFFSET_ID())->value(); + } else { + } +} diff --git a/src/FeaturesPlugin/FeaturesPlugin_Extrusion.h b/src/FeaturesPlugin/FeaturesPlugin_Extrusion.h index d0a6e3745..7a80cc587 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Extrusion.h +++ b/src/FeaturesPlugin/FeaturesPlugin_Extrusion.h @@ -67,6 +67,13 @@ public: return MY_CREATION_METHOD_ID; } + /// Attribute name for creation method. + inline static const std::string& CREATION_METHOD_THROUGH_ALL() + { + static const std::string MY_CREATION_METHOD_ID("ThroughAll"); + return MY_CREATION_METHOD_ID; + } + /// Attribute name of an object to which the extrusion grows. inline static const std::string& DIRECTION_OBJECT_ID() { @@ -144,6 +151,12 @@ protected: const ListOfShape& theBoundaryShapes, const std::shared_ptr theMakeShape, const int theIndex = 0); + + /// Retrieve direction argument. + void getDirection(std::shared_ptr& theDir); + + /// Retrieve or calculate prism sizes. + virtual void getSizes(double& theToSize, double& theFromSize); }; #endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_ExtrusionBoolean.cpp b/src/FeaturesPlugin/FeaturesPlugin_ExtrusionBoolean.cpp index edbdcf948..7075175e3 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_ExtrusionBoolean.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_ExtrusionBoolean.cpp @@ -19,6 +19,11 @@ #include "FeaturesPlugin_ExtrusionBoolean.h" +#include +#include + +#include + //================================================================================================= void FeaturesPlugin_ExtrusionBoolean::initAttributes() { @@ -42,3 +47,35 @@ void FeaturesPlugin_ExtrusionBoolean::storeGenerationHistory(ResultBodyPtr theRe { FeaturesPlugin_Extrusion::storeGenerationHistory(theResultBody, theBaseShape, theMakeShape); } + +//================================================================================================= +void FeaturesPlugin_ExtrusionBoolean::getSizes(double& theToSize, double& theFromSize) +{ + if (string(CREATION_METHOD())->value() != CREATION_METHOD_THROUGH_ALL()) { + FeaturesPlugin_Extrusion::getSizes(theToSize, theFromSize); + } else { + // Getting objects. + ListOfShape anObjects; + AttributeSelectionListPtr anObjectsSelList = myFeature->selectionList(OBJECTS_ID()); + for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) { + AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex); + GeomShapePtr anObject = anObjectAttr->value(); + if (!anObject.get()) { + myFeature->setError("Error: Could not get object."); + return; + } + anObjects.push_back(anObject); + } + + // Getting prism bases. + ListOfShape aBaseShapes; + getBaseShapes(aBaseShapes); + + // Getting prism direction. + std::shared_ptr aDir; + getDirection(aDir); + + // Calculate sizes + GeomAlgoAPI_ShapeTools::computeThroughAll(anObjects, aBaseShapes, aDir, theToSize, theFromSize); + } +} diff --git a/src/FeaturesPlugin/FeaturesPlugin_ExtrusionBoolean.h b/src/FeaturesPlugin/FeaturesPlugin_ExtrusionBoolean.h index ee575471b..ee624029b 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_ExtrusionBoolean.h +++ b/src/FeaturesPlugin/FeaturesPlugin_ExtrusionBoolean.h @@ -44,6 +44,10 @@ protected: void storeGenerationHistory(ResultBodyPtr theResultBody, const GeomShapePtr theBaseShape, const std::shared_ptr theMakeShape); + + /// Calculate prism sizes to ensure that it passes through all objects + /// Redefined from FeaturesPlugin_Extrusion + virtual void getSizes(double& theToSize, double& theFromSize); }; #endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_ExtrusionFuse.cpp b/src/FeaturesPlugin/FeaturesPlugin_ExtrusionFuse.cpp index 52461e303..a50ec3768 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_ExtrusionFuse.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_ExtrusionFuse.cpp @@ -19,6 +19,14 @@ #include "FeaturesPlugin_ExtrusionFuse.h" +#include +#include + +#include +#include +#include +#include + //================================================================================================= FeaturesPlugin_ExtrusionFuse::FeaturesPlugin_ExtrusionFuse() { @@ -29,5 +37,127 @@ FeaturesPlugin_ExtrusionFuse::FeaturesPlugin_ExtrusionFuse() //================================================================================================= void FeaturesPlugin_ExtrusionFuse::execute() { - executeCompositeBoolean(); + if (string(CREATION_METHOD())->value() != CREATION_METHOD_THROUGH_ALL()) + executeCompositeBoolean(); + else { + executeFuseThroughAll(); + } +} + +//================================================================================================= +void FeaturesPlugin_ExtrusionFuse::executeFuseThroughAll() +{ + // Getting objects. + ListOfShape anObjects; + AttributeSelectionListPtr anObjectsSelList = myFeature->selectionList(OBJECTS_ID()); + for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) { + AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex); + GeomShapePtr anObject = anObjectAttr->value(); + if (!anObject.get()) { + myFeature->setError("Error: Could not get object."); + return; + } + anObjects.push_back(anObject); + } + + // Make generation. + ListOfShape aGenBaseShapes; + ListOfMakeShape aGenMakeShapes; + if (!makeGeneration(aGenBaseShapes, aGenMakeShapes)) { + return; + } + + // Getting tools. + ListOfShape aNewTools; + ListOfMakeShape aToolsMakeShapes; + for (ListOfMakeShape::const_iterator + anIt = aGenMakeShapes.cbegin(); anIt != aGenMakeShapes.cend(); ++anIt) { + GeomMakeShapePtr anAlgo = (*anIt); + std::shared_ptr aPrismAlgo = std::dynamic_pointer_cast(anAlgo); + + // Cut the prism by all objects and throw away end pieces + std::shared_ptr aToolAlgo (new GeomAlgoAPI_ThroughAll(aPrismAlgo, anObjects)); + + // Checking that the algorithm worked properly + if (!aToolAlgo->isDone() || aToolAlgo->shape()->isNull() || !aToolAlgo->isValid()) { + myFeature->setError("Error: ThroughAll algorithm failed."); + } else { + GeomShapePtr aCuttedTool = aToolAlgo->shape(); + aNewTools.push_back(aCuttedTool); + aToolsMakeShapes.push_back(aToolAlgo); + } + } + + // Perform FeaturesPlugin_CompositeBoolean::makeBoolean() with new (cutted) tools + ListOfShape aBooleanObjects; + ListOfMakeShape aBooleanMakeShapes; + if (!makeBoolean(aNewTools, aBooleanObjects, aBooleanMakeShapes)) { + return; + } + + if (myOperationType == BOOL_FUSE) { + aNewTools.splice(aNewTools.begin(), aBooleanObjects); + aBooleanObjects.splice(aBooleanObjects.begin(), aNewTools, aNewTools.begin()); + } + + // 4. Store result (like in FeaturesPlugin_CompositeBoolean::executeCompositeBoolean()) + int aResultIndex = 0; + std::vector aResultBaseAlgoList; + ListOfShape aResultShapesList; + ListOfShape::const_iterator aBoolObjIt = aBooleanObjects.cbegin(); + ListOfMakeShape::const_iterator aBoolMSIt = aBooleanMakeShapes.cbegin(); + for(; aBoolObjIt != aBooleanObjects.cend() && aBoolMSIt != aBooleanMakeShapes.cend(); + ++aBoolObjIt, ++aBoolMSIt) { + + ResultBodyPtr aResultBody = myFeature->document()->createBody(myFeature->data(), aResultIndex); + + if((*aBoolObjIt)->isEqual((*aBoolMSIt)->shape())) { + aResultBody->store((*aBoolMSIt)->shape(), false); + } + else + { + aResultBody->storeModified(*aBoolObjIt, (*aBoolMSIt)->shape()); + + // Store generation history. + ListOfShape::const_iterator aGenBaseIt = aGenBaseShapes.cbegin(); + ListOfMakeShape::const_iterator aGenMSIt = aGenMakeShapes.cbegin(); + for(; aGenBaseIt != aGenBaseShapes.cend() && aGenMSIt != aGenMakeShapes.cend(); + ++aGenBaseIt, ++aGenMSIt) { + + // ??? + ListOfMakeShape::const_iterator aToolsMSIt = aToolsMakeShapes.cbegin(); + for(; aToolsMSIt != aToolsMakeShapes.cend(); ++aToolsMSIt) { + std::shared_ptr aMSList(new GeomAlgoAPI_MakeShapeList()); + + // prism generation + aMSList->appendAlgo(*aGenMSIt); + + // tool modification (cut by objects) + aMSList->appendAlgo(*aToolsMSIt); + + // bool fuse + aMSList->appendAlgo(*aBoolMSIt); + storeGenerationHistory(aResultBody, *aGenBaseIt, aMSList); + } + } + + storeModificationHistory(aResultBody, *aBoolObjIt, aNewTools, *aBoolMSIt); + + ResultBaseAlgo aRBA; + aRBA.resultBody = aResultBody; + aRBA.baseShape = *aBoolObjIt; + aRBA.makeShape = *aBoolMSIt; + aResultBaseAlgoList.push_back(aRBA); + aResultShapesList.push_back((*aBoolMSIt)->shape()); + } + + myFeature->setResult(aResultBody, aResultIndex++); + } + + // Store deleted shapes after all results has been proceeded. This is to avoid issue when in one + // result shape has been deleted, but in another it was modified or stayed. + GeomShapePtr aResultShapesCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList); + storeDeletedShapes(aResultBaseAlgoList, aNewTools, aResultShapesCompound); + + myFeature->removeResults(aResultIndex); } diff --git a/src/FeaturesPlugin/FeaturesPlugin_ExtrusionFuse.h b/src/FeaturesPlugin/FeaturesPlugin_ExtrusionFuse.h index 55f5a671e..a2daea88a 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_ExtrusionFuse.h +++ b/src/FeaturesPlugin/FeaturesPlugin_ExtrusionFuse.h @@ -28,7 +28,7 @@ /// fuse result with other objects in a single operation. class FeaturesPlugin_ExtrusionFuse : public FeaturesPlugin_ExtrusionBoolean { -public: + public: /// Use plugin manager for features creation. FeaturesPlugin_ExtrusionFuse(); @@ -48,6 +48,9 @@ public: /// Creates a new part document if needed. FEATURESPLUGIN_EXPORT virtual void execute(); + + private: + void executeFuseThroughAll(); }; #endif diff --git a/src/FeaturesPlugin/Test/TestExtrusionCut_ThroughAll.py b/src/FeaturesPlugin/Test/TestExtrusionCut_ThroughAll.py new file mode 100644 index 000000000..ce66b253f --- /dev/null +++ b/src/FeaturesPlugin/Test/TestExtrusionCut_ThroughAll.py @@ -0,0 +1,71 @@ +# Copyright (C) 2018-2019 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 * + +import math + +def checkMiddlePoint(shape, x, y, z, tolerance = 1.e-7): + assert(shape is not None) + middlePoint = shape.middlePoint() + assert(math.fabs(middlePoint.x() - x) < tolerance), "{} != {}".format(middlePoint.x(), x) + assert(math.fabs(middlePoint.y() - y) < tolerance), "{} != {}".format(middlePoint.y(), y) + assert(math.fabs(middlePoint.z() - z) < tolerance), "{} != {}".format(middlePoint.z(), z) + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Box_1 = model.addBox(Part_1_doc, 10, 10, 10) +Axis_1 = model.addAxis(Part_1_doc, 0, -10, 10) + +ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), [model.selection("SOLID", "Box_1_1")]) +Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1/Left")) +SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Top]"), False) +SketchLine_1 = SketchProjection_1.createdFeature() +SketchCircle_1 = Sketch_1.addCircle(5, 10, 2) +SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.result(), SketchCircle_1.center()) +ExtrusionCut_1.setNestedSketch(Sketch_1) +model.do() +Shape = ExtrusionCut_1.results()[0].resultSubShapePair()[0].shape() +checkMiddlePoint(Shape, 5.0, 5.0, 4.97049495) + +ExtrusionCut_1.setDirection(model.selection("EDGE", "Axis_1")) +model.do() +Shape = ExtrusionCut_1.results()[0].resultSubShapePair()[0].shape() +checkMiddlePoint(Shape, 4.99796028, 5.00196717, 4.97487226) + +ExtrusionCut_2 = model.addExtrusionCut(Part_1_doc, [], [model.selection("SOLID", "ExtrusionCut_1_1")]) +Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1/Front")) +SketchCircle_2 = Sketch_2.addCircle(2, 7, 1.5) +ExtrusionCut_2.setNestedSketch(Sketch_2) +model.do() + +ExtrusionCut_3 = model.addExtrusionCut(Part_1_doc, [], [model.selection("SOLID", "ExtrusionCut_2_1")]) +Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "ExtrusionCut_2_1/Modified_Face&Box_1_1/Front")) +SketchCircle_3 = Sketch_3.addCircle(7, 2, 1.5) +ExtrusionCut_3.setNestedSketch(Sketch_3) +model.do() +Shape = ExtrusionCut_3.results()[0].resultSubShapePair()[0].shape() +checkMiddlePoint(Shape, 4.99787246, 4.92218515, 4.91081244) + +model.end() + +assert(model.checkPythonDump()) diff --git a/src/FeaturesPlugin/Test/TestExtrusionFuse_ThroughAll.py b/src/FeaturesPlugin/Test/TestExtrusionFuse_ThroughAll.py new file mode 100644 index 000000000..e84a50bbe --- /dev/null +++ b/src/FeaturesPlugin/Test/TestExtrusionFuse_ThroughAll.py @@ -0,0 +1,56 @@ +# Copyright (C) 2018-2019 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 * + +import math + +def checkMiddlePoint(shape, x, y, z, tolerance = 1.e-7): + assert(shape is not None) + middlePoint = shape.middlePoint() + assert(math.fabs(middlePoint.x() - x) < tolerance), "{} != {}".format(middlePoint.x(), x) + assert(math.fabs(middlePoint.y() - y) < tolerance), "{} != {}".format(middlePoint.y(), y) + assert(math.fabs(middlePoint.z() - z) < tolerance), "{} != {}".format(middlePoint.z(), z) + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() + +Box_1 = model.addBox(Part_1_doc, 10, 10, 10) +Box_2 = model.addBox(Part_1_doc, 10, 10, 10) +Box_3 = model.addBox(Part_1_doc, 20, 20, 20) +Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_2_1")], 20, 10, 0) +Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], 40, 20, 0) +Edge_1 = model.addEdge(Part_1_doc, model.selection("VERTEX", "[Box_1_1/Back][Box_1_1/Left][Box_1_1/Bottom]"), model.selection("VERTEX", "[Translation_2_1/MF:Translated&Box_3_1/Front][Translation_2_1/MF:Translated&Box_3_1/Right][Translation_2_1/MF:Translated&Box_3_1/Top]")) +Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1/Back")) +SketchCircle_1 = Sketch_1.addCircle(2.134236344973221, -2.430731739079631, 1.564909384334321) +model.do() +Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")]) +ExtrusionFuse_1_objects_2 = [model.selection("SOLID", "Box_1_1"), model.selection("SOLID", "Translation_1_1"), model.selection("SOLID", "Translation_2_1")] +ExtrusionFuse_1 = model.addExtrusionFuse(Part_1_doc, [model.selection("FACE", "Face_1_1")], model.selection("EDGE", "Edge_1_1"), ExtrusionFuse_1_objects_2) + +model.do() +Shape = ExtrusionFuse_1.results()[0].resultSubShapePair()[0].shape() +checkMiddlePoint(Shape, 37.46245068, 23.05267081, 8.52187757) + +model.end() + +assert(model.checkPythonDump()) diff --git a/src/FeaturesPlugin/doc/extrusionFuseFeature.rst b/src/FeaturesPlugin/doc/extrusionFuseFeature.rst index 65d971a87..59d49043e 100644 --- a/src/FeaturesPlugin/doc/extrusionFuseFeature.rst +++ b/src/FeaturesPlugin/doc/extrusionFuseFeature.rst @@ -18,7 +18,7 @@ The following property panel will be opened: .. centered:: Start sketch -There are two variants of the property panel for Extrusion Fuse depending on the chosen option: +There are three variants of the property panel for Extrusion Fuse depending on the chosen option: .. image:: images/extrusion_by_sizes.png :align: left @@ -28,6 +28,10 @@ There are two variants of the property panel for Extrusion Fuse depending on the :align: left **By Bounding Planes** extrudes objects by specifying bounding planes and offsets. +.. image:: images/extrusion_through_all.png + :align: left +**Through All** extrudes base objects to pass through all objects fuse with. + By sizes -------- @@ -149,3 +153,46 @@ The Result of the operation will be an extruded shape: **Extrusion Fuse created** **See Also** a sample TUI Script of :ref:`tui_create_extrusion_fuse_by_bounding_planes` operation. + +Through all +----------- + +.. image:: images/ExtrusionFuse3.png + :align: center + +.. centered:: + Extrusion Fuse: definition through all objects + +- **Base objects** - contains a list of objects selected in the Object Browser or in the Viewer, which will be extruded. +- **Axis** - if selected, it will be the direction of extrusion, otherwise objects normals will be used. +- **Fuse with** - contains a list of objects which will be fused with the result of extrusion. + +**TUI Commands**: + +.. py:function:: model.addExtrusionFuse(part, objectsToExtrude, objectsToFuse) + + :param part: The current part object. + :param list: A list of objects for extrusion. + :param list: A list of objects to fuse with. + :return: Created object. + +.. py:function:: model.addExtrusionFuse(part, objectsToExtrude, direction, objectsToFuse) + + :param part: The current part object. + :param list: A list of objects for extrusion. + :param object: A direction of extrusion + :param list: A list of objects to fuse with. + :return: Created object. + +Result +"""""" + +The Result of the operation will be an extruded shape: + +.. image:: images/extrusion_fuse_through_all_result.png + :align: center + +.. centered:: + **Extrusion Fuse created** + +**See Also** a sample TUI Script of :ref:`tui_create_extrusion_fuse_through_all` operation. diff --git a/src/FeaturesPlugin/doc/images/extrusion_fuse_through_all_result.png b/src/FeaturesPlugin/doc/images/extrusion_fuse_through_all_result.png new file mode 100644 index 0000000000000000000000000000000000000000..d043450a1bbbf8995980b8ac8ea52275a03d097a GIT binary patch literal 18397 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

w1jopp?SjqXoXE>snL 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 literal 0 HcmV?d00001 diff --git a/src/FeaturesPlugin/extrusioncut_widget.xml b/src/FeaturesPlugin/extrusioncut_widget.xml index c8561193e..bbbf73dd8 100644 --- a/src/FeaturesPlugin/extrusioncut_widget.xml +++ b/src/FeaturesPlugin/extrusioncut_widget.xml @@ -83,6 +83,8 @@ + + + + #include + +#include #include -#include #include #include +#include #include #include #include #include +#include #include #include #include @@ -46,40 +49,48 @@ #include #include #include +#include + +#include + #include #include -#include -#include -#include + +#include #include #include +#include + #include #include + #include #include #include + #include #include + #include #include -#include + #include #include -#include + +#include #include #include #include #include #include -#include +#include + #include #include -#include +#include -#include -#include -#include +#include //================================================================================================== static GProp_GProps props(const TopoDS_Shape& theShape) @@ -1076,6 +1087,7 @@ static TopoDS_Wire fixParametricGaps(const TopoDS_Wire& theWire) return aFixedWire; } +//================================================================================================== std::shared_ptr GeomAlgoAPI_ShapeTools::wireToEdge( const std::shared_ptr& theWire) { @@ -1094,6 +1106,7 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::wireToEdge( return anEdge; } +//================================================================================================== ListOfShape GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(const GeomShapePtr& theShape) { ListOfShape aSubShapes; @@ -1114,4 +1127,123 @@ ListOfShape GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(const GeomShapePtr& the } return aSubShapes; -} \ No newline at end of file +} + +//================================================================================================== +static void getMinMaxPointsOnLine(const std::list >& thePoints, + const gp_Dir theDir, + double& theMin, double& theMax) +{ + theMin = RealLast(); + theMax = RealFirst(); + // Project bounding points on theDir + for (std::list >::const_iterator + aPointsIt = thePoints.begin(); aPointsIt != thePoints.end(); aPointsIt++) { + const gp_Pnt& aPnt = (*aPointsIt)->impl(); + gp_Dir aPntDir (aPnt.XYZ()); + Standard_Real proj = (theDir*aPntDir) * aPnt.XYZ().Modulus(); + if (proj < theMin) theMin = proj; + if (proj > theMax) theMax = proj; + } +} + +//================================================================================================== +void GeomAlgoAPI_ShapeTools::computeThroughAll(const ListOfShape& theObjects, + const ListOfShape& theBaseShapes, + const std::shared_ptr theDir, + double& theToSize, double& theFromSize) +{ + // Bounding box of objects + std::list > aBndObjs = GeomAlgoAPI_ShapeTools::getBoundingBox(theObjects); + if (aBndObjs.size() != 8) { + return; + } + + // Prism direction + if (theDir.get()) { + // One direction for all prisms + gp_Dir aDir = theDir->impl(); + + // Bounding box of the base + std::list > aBndBases = GeomAlgoAPI_ShapeTools::getBoundingBox(theBaseShapes); + if (aBndBases.size() != 8) { + return; + } + + // Objects bounds + Standard_Real lowBnd, upperBnd; + getMinMaxPointsOnLine(aBndObjs, aDir, lowBnd, upperBnd); + + // Base bounds + Standard_Real lowBase, upperBase; + getMinMaxPointsOnLine(aBndBases, aDir, lowBase, upperBase); + + // ----------.-----.---------.--------------.-----------> theDir + // lowBnd lowBase upperBase upperBnd + + theToSize = upperBnd - lowBase; + theFromSize = upperBase - lowBnd; + } else { + // Direction is a normal to each base shape (different normals to bases) + // So we calculate own sizes for each base shape + theToSize = 0.0; + theFromSize = 0.0; + + for (ListOfShape::const_iterator anIt = theBaseShapes.begin(); anIt != theBaseShapes.end(); ++anIt) { + const GeomShapePtr& aBaseShape_i = (*anIt); + ListOfShape aBaseShapes_i; + aBaseShapes_i.push_back(aBaseShape_i); + + // Bounding box of the base + std::list > aBndBases = GeomAlgoAPI_ShapeTools::getBoundingBox(aBaseShapes_i); + if (aBndBases.size() != 8) { + return; + } + + // Direction (normal to aBaseShapes_i) + // Code like in GeomAlgoAPI_Prism + gp_Dir aDir; + const TopoDS_Shape& aBaseShape = aBaseShape_i->impl(); + BRepBuilderAPI_FindPlane aFindPlane(aBaseShape); + if (aFindPlane.Found() == Standard_True) { + Handle(Geom_Plane) aPlane; + if (aBaseShape.ShapeType() == TopAbs_FACE || aBaseShape.ShapeType() == TopAbs_SHELL) { + TopExp_Explorer anExp(aBaseShape, TopAbs_FACE); + const TopoDS_Shape& aFace = anExp.Current(); + Handle(Geom_Surface) aSurface = BRep_Tool::Surface(TopoDS::Face(aFace)); + if(aSurface->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) { + Handle(Geom_RectangularTrimmedSurface) aTrimSurface = + Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface); + aSurface = aTrimSurface->BasisSurface(); + } + if(aSurface->DynamicType() != STANDARD_TYPE(Geom_Plane)) { + return; + } + aPlane = Handle(Geom_Plane)::DownCast(aSurface); + } else { + aPlane = aFindPlane.Plane(); + } + aDir = aPlane->Axis().Direction(); + } else { + return; + } + + // Objects bounds + Standard_Real lowBnd, upperBnd; + getMinMaxPointsOnLine(aBndObjs, aDir, lowBnd, upperBnd); + + // Base bounds + Standard_Real lowBase, upperBase; + getMinMaxPointsOnLine(aBndBases, aDir, lowBase, upperBase); + + // ----------.-----.---------.--------------.-----------> theDir + // lowBnd lowBase upperBase upperBnd + + double aToSize_i = upperBnd - lowBase; + double aFromSize_i = upperBase - lowBnd; + + if (aToSize_i > theToSize) theToSize = aToSize_i; + if (aFromSize_i > theFromSize) theFromSize = aFromSize_i; + } + } +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h index da415d359..49b343244 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h @@ -193,6 +193,17 @@ public: /// \param[in] theShape shape that should be exploded /// \return list of sub-shapes (vertices, edges, faces, solids) GEOMALGOAPI_EXPORT static ListOfShape getLowLevelSubShapes(const GeomShapePtr& theShape); + + /// \brief Calculate prism sizes to ensure that it passes through all objects + /// \param[in] theObjects objects to be joined/cutted by the prism + /// \param[in] theBaseShapes bases of the prism + /// \param[in] theDir direction of the prism + /// \param[out] theToSize upper offset of the prism + /// \param[out] theFromSize lower offset of the prism + GEOMALGOAPI_EXPORT static void computeThroughAll(const ListOfShape& theObjects, + const ListOfShape& theBaseShapes, + const std::shared_ptr theDir, + double& theToSize, double& theFromSize); }; #endif diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.cpp new file mode 100644 index 000000000..f64ef6004 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.cpp @@ -0,0 +1,88 @@ +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "GeomAlgoAPI_ThroughAll.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +//================================================================================================= +GeomAlgoAPI_ThroughAll::GeomAlgoAPI_ThroughAll(std::shared_ptr thePrismAlgo, + const ListOfShape& theObjects) +: GeomAlgoAPI_Boolean(thePrismAlgo->shape(), theObjects, GeomAlgoAPI_Tools::BOOL_CUT) +{ + removeEnds(thePrismAlgo); +} + +//================================================================================================= +void GeomAlgoAPI_ThroughAll::removeEnds(std::shared_ptr thePrismAlgo) +{ + GeomShapePtr aCuttedTool = shape(); // result of BOP Cut (thePrismAlgo->shape() by theObjects) + + // Simplify the result + ListOfShape aPieces = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(aCuttedTool); + + // Get end shapes of Prism + const ListOfShape& fromShapes = thePrismAlgo->fromShapes(); + const ListOfShape& toShapes = thePrismAlgo->toShapes(); + ListOfShape endShapes (fromShapes); + endShapes.insert(endShapes.end(), toShapes.begin(), toShapes.end()); + + // Throw away end pieces of cutted tools (containing endShapes) + TopTools_ListOfShape listTools; + for (ListOfShape::const_iterator + anIt = aPieces.begin(); anIt != aPieces.end(); anIt++) { + TopoDS_Shape aPiece = (*anIt)->impl(); + bool endPiece = false; + + for (ListOfShape::const_iterator aBaseIt = endShapes.begin(); + aBaseIt != endShapes.end() && !endPiece; aBaseIt++) { + // Check, if the piece contains aBase (one of endShapes) + TopoDS_Shape aBase = (*aBaseIt)->impl(); + TopExp_Explorer anExp (aPiece, aBase.ShapeType()); + for (; anExp.More() && !endPiece; anExp.Next()) { + if (anExp.Current().IsSame(aBase)) + endPiece = true; + } + } + + if (!endPiece) { + listTools.Append(aPiece); + } + } + + BRep_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + for (TopTools_ListOfShape::Iterator anIt(listTools); anIt.More(); anIt.Next()) { + aBuilder.Add(aCompound, anIt.Value()); + } + + std::shared_ptr aShape (new GeomAPI_Shape()); + aShape->setImpl(new TopoDS_Shape(aCompound)); + this->setShape(aShape); + this->setDone(true); +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.h b/src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.h new file mode 100644 index 000000000..bd54dd73c --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.h @@ -0,0 +1,46 @@ +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef GeomAlgoAPI_ThroughAll_H_ +#define GeomAlgoAPI_ThroughAll_H_ + +#include +#include +#include +//#include + +#include + +/// \class GeomAlgoAPI_ThroughAll +/// \ingroup DataAlgo +/// \brief Cuts a prism by all given objects, throw away end pieces +class GeomAlgoAPI_ThroughAll : public GeomAlgoAPI_Boolean +{ +public: + + /// Constructor. + GEOMALGOAPI_EXPORT GeomAlgoAPI_ThroughAll (std::shared_ptr thePrismAlgo, + const ListOfShape& theObjects); + +private: + /// Builds resulting shape. + void removeEnds (std::shared_ptr thePrismAlgo); +}; + +#endif -- 2.39.2