From 30ac20cda15d2a090608c40f97496341646ef088 Mon Sep 17 00:00:00 2001 From: cg246364 Date: Wed, 13 Apr 2022 15:54:06 +0200 Subject: [PATCH] Implementation of shared faces inspection --- .../ConnectorPlugin_PublishToStudyFeature.py | 81 ++++---- src/FeaturesAPI/CMakeLists.txt | 2 + src/FeaturesAPI/FeaturesAPI.i | 2 + src/FeaturesAPI/FeaturesAPI_SharedFaces.cpp | 83 ++++++++ src/FeaturesAPI/FeaturesAPI_SharedFaces.h | 77 ++++++++ src/FeaturesAPI/FeaturesAPI_swig.h | 1 + src/FeaturesPlugin/CMakeLists.txt | 9 + .../FeaturesPlugin_CommonSharedFaces.cpp | 96 ++++++++++ .../FeaturesPlugin_CommonSharedFaces.h | 66 +++++++ .../FeaturesPlugin_GroupSharedFaces.cpp | 121 ++++++++++++ .../FeaturesPlugin_GroupSharedFaces.h | 114 +++++++++++ src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp | 6 + .../FeaturesPlugin_SharedFaces.cpp | 178 ++++++++++++++++++ .../FeaturesPlugin_SharedFaces.h | 133 +++++++++++++ src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts | 122 ++++++++++++ .../Test/TestCheckSharedFaces.py | 122 ++++++++++++ src/FeaturesPlugin/doc/FeaturesPlugin.rst | 1 + .../doc/TUI_sharedFacesFeature.rst | 11 ++ .../doc/checkSharedFaceFeature.rst | 52 +++++ .../doc/examples/check_shared_faces.py | 21 +++ .../images/checkSharedFacesPropertyPanel.png | Bin 0 -> 26398 bytes .../doc/images/sharedFacesResult.png | Bin 0 -> 7992 bytes .../doc/images/shared_shapes.png | Bin 0 -> 583 bytes src/FeaturesPlugin/icons/shared_shapes.png | Bin 0 -> 583 bytes src/FeaturesPlugin/plugin-Features.xml | 10 +- .../shared_faces_macro_widget.xml | 35 ++++ src/FeaturesPlugin/shared_faces_widget.xml | 31 +++ src/FeaturesPlugin/tests.set | 1 + src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp | 17 ++ src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h | 5 + src/PythonAPI/model/features/__init__.py | 2 +- 31 files changed, 1358 insertions(+), 41 deletions(-) create mode 100644 src/FeaturesAPI/FeaturesAPI_SharedFaces.cpp create mode 100644 src/FeaturesAPI/FeaturesAPI_SharedFaces.h create mode 100644 src/FeaturesPlugin/FeaturesPlugin_CommonSharedFaces.cpp create mode 100644 src/FeaturesPlugin/FeaturesPlugin_CommonSharedFaces.h create mode 100644 src/FeaturesPlugin/FeaturesPlugin_GroupSharedFaces.cpp create mode 100644 src/FeaturesPlugin/FeaturesPlugin_GroupSharedFaces.h create mode 100644 src/FeaturesPlugin/FeaturesPlugin_SharedFaces.cpp create mode 100644 src/FeaturesPlugin/FeaturesPlugin_SharedFaces.h create mode 100644 src/FeaturesPlugin/Test/TestCheckSharedFaces.py create mode 100644 src/FeaturesPlugin/doc/TUI_sharedFacesFeature.rst create mode 100644 src/FeaturesPlugin/doc/checkSharedFaceFeature.rst create mode 100644 src/FeaturesPlugin/doc/examples/check_shared_faces.py create mode 100644 src/FeaturesPlugin/doc/images/checkSharedFacesPropertyPanel.png create mode 100644 src/FeaturesPlugin/doc/images/sharedFacesResult.png create mode 100644 src/FeaturesPlugin/doc/images/shared_shapes.png create mode 100644 src/FeaturesPlugin/icons/shared_shapes.png create mode 100644 src/FeaturesPlugin/shared_faces_macro_widget.xml create mode 100644 src/FeaturesPlugin/shared_faces_widget.xml diff --git a/src/ConnectorPlugin/ConnectorPlugin_PublishToStudyFeature.py b/src/ConnectorPlugin/ConnectorPlugin_PublishToStudyFeature.py index a721ad73b..252eb893f 100644 --- a/src/ConnectorPlugin/ConnectorPlugin_PublishToStudyFeature.py +++ b/src/ConnectorPlugin/ConnectorPlugin_PublishToStudyFeature.py @@ -163,51 +163,54 @@ class PublishToStudyFeature(ModelAPI.ModelAPI_Feature): # If theFields is true, the same is performed for Fields. def processGroups(self, theRes, theEngine, thePartFeatureId, theStudyShape, theFields): allGroupsProcessed = [] + allRefGroups = [] if theFields: - aRefGroups = ModelAPI.referencedFeatures(theRes, "Field", True) + allRefGroups.append(ModelAPI.referencedFeatures(theRes, "Field", True)) else: - aRefGroups = ModelAPI.referencedFeatures(theRes, "Group", True) - for aRef in aRefGroups: - aGroupIndices = [] - aGroupHasIndex = {} - aResShape = theRes.shape() - if theFields: - aSelList = aRef.selectionList("selected") - else: - aSelList = aRef.selectionList("group_list") - aSelType = GeomAPI_Shape.shapeTypeByStr(aSelList.selectionType()) - for aGroupRes in aRef.results(): - aShape = aGroupRes.shape() - anExplorer = GeomAPI_ShapeExplorer(aShape, aSelType) - while anExplorer.more(): - anId = GeomAlgoAPI.GeomAlgoAPI_CompoundBuilder.id(aResShape, anExplorer.current()) - if anId > 0 and not anId in aGroupHasIndex: - aGroupIndices.append(anId) - aGroupHasIndex[anId] = 0 - anExplorer.next() - if len(aGroupIndices): # create group - aGroupFeatureId = aRef.data().featureId() + allRefGroups.append(ModelAPI.referencedFeatures(theRes, "Group", True)) + allRefGroups.append(ModelAPI.referencedFeatures(theRes, "Shared_faces", True)) + for aRefGroups in allRefGroups: + for aRef in aRefGroups: + aGroupIndices = [] + aGroupHasIndex = {} + aResShape = theRes.shape() if theFields: - aFieldOp = theEngine.GetIFieldOperations() - aGroupEntry = "field" + str(thePartFeatureId) + ":" + str(aGroupFeatureId) - aGroup = aFieldOp.FindField(theStudyShape, aGroupEntry) + aSelList = aRef.selectionList("selected") else: - aGroupOp = theEngine.GetIGroupOperations() - aGroupEntry = "group" + str(thePartFeatureId) + ":" + str(aGroupFeatureId) - aGroup = aGroupOp.FindGroup(theStudyShape, aGroupEntry) - if not aGroup: # create a new + aSelList = aRef.selectionList("group_list") + aSelType = GeomAPI_Shape.shapeTypeByStr(aSelList.selectionType()) + for aGroupRes in aRef.results(): + aShape = aGroupRes.shape() + anExplorer = GeomAPI_ShapeExplorer(aShape, aSelType) + while anExplorer.more(): + anId = GeomAlgoAPI.GeomAlgoAPI_CompoundBuilder.id(aResShape, anExplorer.current()) + if anId > 0 and not anId in aGroupHasIndex: + aGroupIndices.append(anId) + aGroupHasIndex[anId] = 0 + anExplorer.next() + if len(aGroupIndices): # create group + aGroupFeatureId = aRef.data().featureId() if theFields: - aGroup = aFieldOp.CreateFieldByType(theStudyShape, aSelType) + aFieldOp = theEngine.GetIFieldOperations() + aGroupEntry = "field" + str(thePartFeatureId) + ":" + str(aGroupFeatureId) + aGroup = aFieldOp.FindField(theStudyShape, aGroupEntry) else: - aGroup = aGroupOp.CreateGroup(theStudyShape, aSelType) - aGroup.SetEntry(aGroupEntry) - theEngine.AddInStudy(aGroup, aRef.firstResult().data().name(), theStudyShape) - aGroup.SetSelection(aGroupIndices) - if theFields: - self.fillField(aGroup, aRef, theEngine, aGroupIndices) - # a group takes shape from the main result - #aGroup.SetShapeByStream(aRef.firstResult().shape().getShapeStream(False)) # group shape - allGroupsProcessed.append(aGroupEntry) + aGroupOp = theEngine.GetIGroupOperations() + aGroupEntry = "group" + str(thePartFeatureId) + ":" + str(aGroupFeatureId) + aGroup = aGroupOp.FindGroup(theStudyShape, aGroupEntry) + if not aGroup: # create a new + if theFields: + aGroup = aFieldOp.CreateFieldByType(theStudyShape, aSelType) + else: + aGroup = aGroupOp.CreateGroup(theStudyShape, aSelType) + aGroup.SetEntry(aGroupEntry) + theEngine.AddInStudy(aGroup, aRef.firstResult().data().name(), theStudyShape) + aGroup.SetSelection(aGroupIndices) + if theFields: + self.fillField(aGroup, aRef, theEngine, aGroupIndices) + # a group takes shape from the main result + #aGroup.SetShapeByStream(aRef.firstResult().shape().getShapeStream(False)) # group shape + allGroupsProcessed.append(aGroupEntry) # check all existing groups: if some does not processed, remove it from the tree aSOIter = SHAPERSTUDY_utils.getStudy().NewChildIterator(theStudyShape.GetSO()) while aSOIter.More(): diff --git a/src/FeaturesAPI/CMakeLists.txt b/src/FeaturesAPI/CMakeLists.txt index 6cd9ba368..48acfd445 100644 --- a/src/FeaturesAPI/CMakeLists.txt +++ b/src/FeaturesAPI/CMakeLists.txt @@ -55,6 +55,7 @@ SET(PROJECT_HEADERS FeaturesAPI_PointCoordinates.h FeaturesAPI_GeometryCalculation.h FeaturesAPI_BoundingBox.h + FeaturesAPI_SharedFaces.h ) SET(PROJECT_SOURCES @@ -92,6 +93,7 @@ SET(PROJECT_SOURCES FeaturesAPI_PointCoordinates.cpp FeaturesAPI_GeometryCalculation.cpp FeaturesAPI_BoundingBox.cpp + FeaturesAPI_SharedFaces.cpp ) SET(PROJECT_LIBRARIES diff --git a/src/FeaturesAPI/FeaturesAPI.i b/src/FeaturesAPI/FeaturesAPI.i index d9fa7c0b5..1aa995545 100644 --- a/src/FeaturesAPI/FeaturesAPI.i +++ b/src/FeaturesAPI/FeaturesAPI.i @@ -94,6 +94,7 @@ %shared_ptr(FeaturesAPI_ImportResult) %shared_ptr(FeaturesAPI_Defeaturing) %shared_ptr(FeaturesAPI_BoundingBox) +%shared_ptr(FeaturesAPI_SharedFaces) %typecheck(SWIG_TYPECHECK_POINTER) std::pair, bool>, const std::pair, bool> & { @@ -235,3 +236,4 @@ %include "FeaturesAPI_PointCoordinates.h" %include "FeaturesAPI_GeometryCalculation.h" %include "FeaturesAPI_BoundingBox.h" +%include "FeaturesAPI_SharedFaces.h" diff --git a/src/FeaturesAPI/FeaturesAPI_SharedFaces.cpp b/src/FeaturesAPI/FeaturesAPI_SharedFaces.cpp new file mode 100644 index 000000000..402eb873e --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_SharedFaces.cpp @@ -0,0 +1,83 @@ +// Copyright (C) 2018-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "FeaturesAPI_SharedFaces.h" + +#include + +#include +#include +#include +#include + +//================================================================================================= +FeaturesAPI_SharedFaces::FeaturesAPI_SharedFaces( + const std::shared_ptr& theFeature) +: ModelHighAPI_Interface(theFeature) +{ + initialize(); +} + +//================================================================================================= +FeaturesAPI_SharedFaces::FeaturesAPI_SharedFaces( + const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theObject, + const std::string & theNameGroup) +:ModelHighAPI_Interface(theFeature) +{ + if (initialize()) { + fillAttribute(theObject, myobjectselected); + fillAttribute(theNameGroup, mygroupname); + execute(); + } +} + +//================================================================================================= +FeaturesAPI_SharedFaces::~FeaturesAPI_SharedFaces() +{ +} + +//================================================================================================= +void FeaturesAPI_SharedFaces::dump(ModelHighAPI_Dumper& theDumper) const +{ + FeaturePtr aBase = feature(); + const std::string& aDocName = theDumper.name(aBase->document()); + + AttributeSelectionPtr anAttrObject; + anAttrObject = aBase->selection(FeaturesPlugin_GroupSharedFaces::OBJECT_ID()); + + theDumper << aBase << " = model.getSharedFaces(" << aDocName << ", " << anAttrObject; + theDumper << ", " << aBase->string(FeaturesPlugin_GroupSharedFaces::GROUP_NAME_ID()); + theDumper << ")" << std::endl; +} + +//================================================================================================= +SharedFacesPtr getSharedFaces(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theObject, + const std::string & theNameGroup) +{ + FeaturePtr aFeature = thePart->addFeature(FeaturesPlugin_GroupSharedFaces::ID()); + SharedFacesPtr aSharedFaces; + + aSharedFaces.reset(new FeaturesAPI_SharedFaces(aFeature, + theObject, + theNameGroup)); + return aSharedFaces; +} + diff --git a/src/FeaturesAPI/FeaturesAPI_SharedFaces.h b/src/FeaturesAPI/FeaturesAPI_SharedFaces.h new file mode 100644 index 000000000..ac62ee747 --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_SharedFaces.h @@ -0,0 +1,77 @@ +// Copyright (C) 2018-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef FeaturesAPI_SharedFaces_H_ +#define FeaturesAPI_SharedFaces_H_ + +#include "FeaturesAPI.h" + +#include "FeaturesPlugin_GroupSharedFaces.h" + +#include +#include +#include + +class ModelAPI_Document; +class ModelHighAPI_Selection; + +/// \class FeaturesAPI_SharedFaces +/// \ingroup CPPHighAPI +/// \brief Interface to find shared faces +class FeaturesAPI_SharedFaces: public ModelHighAPI_Interface +{ +public: + /// Constructor without values. + FEATURESAPI_EXPORT + explicit FeaturesAPI_SharedFaces(const std::shared_ptr& theFeature); + + FEATURESAPI_EXPORT + explicit FeaturesAPI_SharedFaces(const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theObject, + const std::string & theNameGroup); + + /// Destructor. + FEATURESAPI_EXPORT + virtual ~FeaturesAPI_SharedFaces(); + + INTERFACE_2(FeaturesPlugin_GroupSharedFaces::ID(), + objectselected, FeaturesPlugin_GroupSharedFaces::OBJECT_ID(), + ModelAPI_AttributeSelection, /** object selected*/, + groupname, FeaturesPlugin_GroupSharedFaces::GROUP_NAME_ID(), + ModelAPI_AttributeString, /** group name*/) + + /// Dump wrapped feature + FEATURESAPI_EXPORT + virtual void dump(ModelHighAPI_Dumper& theDumper) const; +}; + +/// Pointer on the SharedFaces object. +typedef std::shared_ptr SharedFacesPtr; + +/// \ingroup CPPHighAPI +/// \brief Create a group of shared faces in a compsolid or a compound +/// \param thePart the part +/// \param theObject the selected object +/// \param theNameGroup the group name +FEATURESAPI_EXPORT +SharedFacesPtr getSharedFaces(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theObject, + const std::string & theNameGroup); + +#endif // FeaturesAPI_SharedFaces_H_ diff --git a/src/FeaturesAPI/FeaturesAPI_swig.h b/src/FeaturesAPI/FeaturesAPI_swig.h index ede8f2c11..65454314c 100644 --- a/src/FeaturesAPI/FeaturesAPI_swig.h +++ b/src/FeaturesAPI/FeaturesAPI_swig.h @@ -57,5 +57,6 @@ #include "FeaturesAPI_PointCoordinates.h" #include "FeaturesAPI_GeometryCalculation.h" #include "FeaturesAPI_BoundingBox.h" + #include "FeaturesAPI_SharedFaces.h" #endif // FeaturesAPI_swig_H_ diff --git a/src/FeaturesPlugin/CMakeLists.txt b/src/FeaturesPlugin/CMakeLists.txt index e3f25e81d..c44abcef3 100644 --- a/src/FeaturesPlugin/CMakeLists.txt +++ b/src/FeaturesPlugin/CMakeLists.txt @@ -74,6 +74,9 @@ SET(PROJECT_HEADERS FeaturesPlugin_InspectBoundingBox.h FeaturesPlugin_NormalToFace.h FeaturesPlugin_InspectNormalToFace.h + FeaturesPlugin_CommonSharedFaces.h + FeaturesPlugin_GroupSharedFaces.h + FeaturesPlugin_SharedFaces.h ) SET(PROJECT_SOURCES @@ -128,6 +131,9 @@ SET(PROJECT_SOURCES FeaturesPlugin_InspectBoundingBox.cpp FeaturesPlugin_NormalToFace.cpp FeaturesPlugin_InspectNormalToFace.cpp + FeaturesPlugin_CommonSharedFaces.cpp + FeaturesPlugin_GroupSharedFaces.cpp + FeaturesPlugin_SharedFaces.cpp ) SET(XML_RESOURCES @@ -170,6 +176,8 @@ SET(XML_RESOURCES create_bounding_box_widget.xml normal_to_face_widget.xml create_normal_to_face_widget.xml + shared_faces_macro_widget.xml + shared_faces_widget.xml ) SET(TEXT_RESOURCES @@ -190,6 +198,7 @@ INCLUDE_DIRECTORIES( ../ModuleBase ../Events ../Config + ../Locale ${OpenCASCADE_INCLUDE_DIR} ) diff --git a/src/FeaturesPlugin/FeaturesPlugin_CommonSharedFaces.cpp b/src/FeaturesPlugin/FeaturesPlugin_CommonSharedFaces.cpp new file mode 100644 index 000000000..a53129891 --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_CommonSharedFaces.cpp @@ -0,0 +1,96 @@ +// Copyright (C) 2018-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "FeaturesPlugin_CommonSharedFaces.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include + +//================================================================================================= +void FeaturesPlugin_CommonSharedFaces::updateFaces() +{ + AttributeSelectionPtr aCompSolidAttr = + std::dynamic_pointer_cast(attributObject()); + AttributeSelectionListPtr aFacesListAttr = + std::dynamic_pointer_cast (attributListFaces()); + + GeomShapePtr aShape = aCompSolidAttr->value(); + + AttributeBooleanPtr anIsCompute = + std::dynamic_pointer_cast(attributIsCompute()); + if (!anIsCompute->value()) { + myShape = aShape; + anIsCompute->setValue(true); + } + if (aShape.get() && aCompSolidAttr->context().get() && !aShape->isEqual(myShape)) { + if (aFacesListAttr->isInitialized()) + aFacesListAttr->clear(); + aShape = aCompSolidAttr->context()->shape(); + if (aShape) { + ListOfShape aFaces = GeomAlgoAPI_ShapeTools::getSharedFaces(aShape); + myShape = aShape; + aFacesListAttr->setSelectionType("face"); + ListOfShape::const_iterator anIt = aFaces.cbegin(); + for(; anIt != aFaces.cend(); ++anIt) { + GeomShapePtr aFacePtr = *anIt; + aFacesListAttr->append(aCompSolidAttr->context(), aFacePtr); + } + std::stringstream alabel; + alabel << aFacesListAttr->size(); + AttributeStringPtr aNumberFacesAttr = + std::dynamic_pointer_cast(attributNumberFaces()); + aNumberFacesAttr->setValue(alabel.str()); + } + } +} + +//================================================================================================= +void FeaturesPlugin_CommonSharedFaces::setFacesGroup(const std::wstring& theName ) +{ + std::vector aColor; + ResultGroupPtr aGroup = document()->createGroup(data()); + // Clean the result of the operation + aGroup->data()->setName(theName); + aGroup->store(GeomShapePtr()); + + // shapes containing in group + ListOfShape aFaces; + AttributeSelectionListPtr aFacesListAttr = + std::dynamic_pointer_cast (attributListFaces()); + + for (int anI =0; anI< aFacesListAttr->size(); anI++) { + AttributeSelectionPtr aAtt = aFacesListAttr->value(anI); + aFaces.push_back(aAtt->value()); + } + + GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aFaces); + aGroup->store(aCompound); + aColor = {255,0,0}; + setResult(aGroup); + ModelAPI_Tools::setColor(lastResult(),aColor); +} + diff --git a/src/FeaturesPlugin/FeaturesPlugin_CommonSharedFaces.h b/src/FeaturesPlugin/FeaturesPlugin_CommonSharedFaces.h new file mode 100644 index 000000000..3a31c3b4e --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_CommonSharedFaces.h @@ -0,0 +1,66 @@ +// Copyright (C) 2018-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef FeaturesPlugin_CommonSharedFaces_H_ +#define FeaturesPlugin_CommonSharedFaces_H_ + +#include "FeaturesPlugin.h" + +#include +#include +#include + + +/// \class FeaturesPlugin_CommonSharedFaces +/// \ingroup Plugins +/// \brief Feature to check the shared faces of solid + +class FeaturesPlugin_CommonSharedFaces : public ModelAPI_Feature +{ +public: + /// Performs the algorithm and stores results it in the data structure. + FEATURESPLUGIN_EXPORT virtual void execute(){}; + + /// Return Attribut values of result. + virtual AttributePtr attributObject() = 0; + + /// Return Attribut values of result. + virtual AttributePtr attributListFaces() = 0; + + /// Return Attribut values of result. + virtual AttributePtr attributNumberFaces() = 0; + + /// Return Attribut values of IsCompute. + virtual AttributePtr attributIsCompute() = 0; + + protected: + FeaturesPlugin_CommonSharedFaces() {} + + //Set group of faces + void setFacesGroup(const std::wstring& theName ); + + // Update the list of faces + void updateFaces(); + + // the shape studied + GeomShapePtr myShape; + +}; + +#endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_GroupSharedFaces.cpp b/src/FeaturesPlugin/FeaturesPlugin_GroupSharedFaces.cpp new file mode 100644 index 000000000..cfed4a5b1 --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_GroupSharedFaces.cpp @@ -0,0 +1,121 @@ +// Copyright (C) 2018-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "FeaturesPlugin_GroupSharedFaces.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//================================================================================================= +FeaturesPlugin_GroupSharedFaces::FeaturesPlugin_GroupSharedFaces() +{ +} + +//================================================================================================= +void FeaturesPlugin_GroupSharedFaces::initAttributes() +{ + // attribute for object selected + data()->addAttribute(OBJECT_ID(), ModelAPI_AttributeSelection::typeId()); + AttributeSelectionListPtr aList = std::dynamic_pointer_cast( + data()->addAttribute(LIST_FACES_ID(), ModelAPI_AttributeSelectionList::typeId())); + + data()->addAttribute(NUMBER_FACES_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(TRANSPARENCY_ID(), ModelAPI_AttributeInteger::typeId()); + data()->addAttribute(GROUP_NAME_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(COMPUTE_ID(), ModelAPI_AttributeBoolean::typeId()); + + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), TRANSPARENCY_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), COMPUTE_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), NUMBER_FACES_ID()); + data()->boolean(COMPUTE_ID())->setValue(true); +} + +//================================================================================================= +AttributePtr FeaturesPlugin_GroupSharedFaces::attributObject() +{ + return attribute(OBJECT_ID()); +} + +//================================================================================================= +AttributePtr FeaturesPlugin_GroupSharedFaces::attributIsCompute() +{ + return attribute(COMPUTE_ID()); +} + +//================================================================================================= +AttributePtr FeaturesPlugin_GroupSharedFaces::attributListFaces() +{ + return attribute(LIST_FACES_ID()); +} + +//================================================================================================= +AttributePtr FeaturesPlugin_GroupSharedFaces::attributNumberFaces() +{ + return attribute(NUMBER_FACES_ID()); +} + +//================================================================================================= +void FeaturesPlugin_GroupSharedFaces::execute() +{ + if (selectionList(LIST_FACES_ID())->isInitialized() + && string(GROUP_NAME_ID())->value() != "") { + AttributeStringPtr aNameAtt = string( GROUP_NAME_ID() ) ; + std::wstring aNameFace = aNameAtt->isUValue() ? + Locale::Convert::toWString(aNameAtt->valueU()) : + Locale::Convert::toWString(aNameAtt->value()); + + if (lastResult().get()) + eraseResultFromList(lastResult()); + setFacesGroup(aNameFace); + } else { + if (lastResult().get()) { + eraseResultFromList(lastResult()); + } + } + if (selection(OBJECT_ID())->isInitialized() && integer(TRANSPARENCY_ID())->isInitialized()) { + AttributeSelectionPtr aCompSolidAttr = selection(OBJECT_ID()); + ResultPtr aResult = aCompSolidAttr->context(); + + double aTranparency = integer(TRANSPARENCY_ID())->value() / 100.0; + ModelAPI_Tools::setTransparency(aResult, aTranparency); + + ResultBodyPtr aResultBody = std::dynamic_pointer_cast(aResult); + std::list allRes; + ModelAPI_Tools::allSubs(aResultBody, allRes); + std::list::iterator aRes; + for(aRes = allRes.begin(); aRes != allRes.end(); aRes++) { + ModelAPI_Tools::setTransparency(*aRes, aTranparency); + } + } +} + +//================================================================================================= +void FeaturesPlugin_GroupSharedFaces::attributeChanged(const std::string& theID) +{ + if (theID == OBJECT_ID()) + updateFaces(); +} diff --git a/src/FeaturesPlugin/FeaturesPlugin_GroupSharedFaces.h b/src/FeaturesPlugin/FeaturesPlugin_GroupSharedFaces.h new file mode 100644 index 000000000..d81781b1c --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_GroupSharedFaces.h @@ -0,0 +1,114 @@ +// Copyright (C) 2018-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef FeaturesPlugin_GroupSharedFaces_H_ +#define FeaturesPlugin_GroupSharedFaces_H_ + +#include + +/// \class FeaturesPlugin_GroupSharedFaces +/// \ingroup Plugins +/// \brief Feature to check the shared faces of solid + +class FeaturesPlugin_GroupSharedFaces : public FeaturesPlugin_CommonSharedFaces +{ +public: + /// Group shared faces kind. + inline static const std::string& ID() + { + static const std::string MY_ID("Shared_faces"); + return MY_ID; + } + + /// Attribute name for object selected. + inline static const std::string& OBJECT_ID() + { + static const std::string MY_OBJECT_ID("main_object"); + return MY_OBJECT_ID; + } + + /// Attribute name for number of faces. + inline static const std::string& NUMBER_FACES_ID() + { + static const std::string MY_NUMBER_FACES_ID("number_shared_faces"); + return MY_NUMBER_FACES_ID; + } + + /// Attribute name for z coodinate. + inline static const std::string& LIST_FACES_ID() + { + static const std::string MY_LIST_FACES_ID("group_list"); + return MY_LIST_FACES_ID; + } + + /// Attribute name for transparency. + inline static const std::string& TRANSPARENCY_ID() + { + static const std::string MY_TRANSPARENCY_ID("transparency"); + return MY_TRANSPARENCY_ID; + } + + /// Attribute name for group name. + inline static const std::string& GROUP_NAME_ID() + { + static const std::string MY_GROUP_NAME_ID("group_name"); + return MY_GROUP_NAME_ID; + } + + /// Attribute name for indicate to launch the algo. + inline static const std::string& COMPUTE_ID() + { + static const std::string MY_COMPUTE_ID("compute"); + return MY_COMPUTE_ID; + } + + /// \return the kind of a feature. + virtual const std::string& getKind() + { + return ID(); + } + + /// Performs the algorithm and stores results it in the data structure. + FEATURESPLUGIN_EXPORT virtual void execute(); + + /// Request for initialization of data model of the feature: adding all attributes + FEATURESPLUGIN_EXPORT virtual void initAttributes(); + + /// Called on change of any argument-attribute of this object + /// \param theID identifier of changed attribute + FEATURESPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID); + + /// Use plugin manager for features creation + FeaturesPlugin_GroupSharedFaces(); + +private: + /// Return Attribut values of object. + virtual AttributePtr attributObject(); + + /// Return Attribut values of list of faces. + virtual AttributePtr attributListFaces(); + + /// Return Attribut values of number of faces. + virtual AttributePtr attributNumberFaces(); + + /// Return Attribut values of IsCompute. + virtual AttributePtr attributIsCompute(); +}; + +#endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp index 3d00700d6..7fe7a513b 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -215,6 +217,10 @@ FeaturePtr FeaturesPlugin_Plugin::createFeature(std::string theFeatureID) return FeaturePtr(new FeaturesPlugin_InspectNormalToFace); } else if (theFeatureID == FeaturesPlugin_NormalToFace::ID()) { return FeaturePtr(new FeaturesPlugin_NormalToFace); + } else if (theFeatureID == FeaturesPlugin_SharedFaces::ID()) { + return FeaturePtr(new FeaturesPlugin_SharedFaces); + } else if (theFeatureID == FeaturesPlugin_GroupSharedFaces::ID()) { + return FeaturePtr(new FeaturesPlugin_GroupSharedFaces); } diff --git a/src/FeaturesPlugin/FeaturesPlugin_SharedFaces.cpp b/src/FeaturesPlugin/FeaturesPlugin_SharedFaces.cpp new file mode 100644 index 000000000..8015f36ca --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_SharedFaces.cpp @@ -0,0 +1,178 @@ +// Copyright (C) 2018-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "FeaturesPlugin_SharedFaces.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +//================================================================================================= +FeaturesPlugin_SharedFaces::FeaturesPlugin_SharedFaces() +{ +} + +//================================================================================================= +void FeaturesPlugin_SharedFaces::initAttributes() +{ + // attribute for object selected + data()->addAttribute(OBJECT_ID(), ModelAPI_AttributeSelection::typeId()); + AttributeSelectionListPtr aList = std::dynamic_pointer_cast( + data()->addAttribute(LIST_FACES_ID(), ModelAPI_AttributeSelectionList::typeId())); + + data()->addAttribute(NUMBER_FACES_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(TRANSPARENCY_ID(), ModelAPI_AttributeInteger::typeId()); + data()->addAttribute(CREATE_GROUP_ID(), ModelAPI_AttributeBoolean::typeId()); + data()->addAttribute(GROUP_NAME_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(COMPUTE_ID(), ModelAPI_AttributeBoolean::typeId()); + + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), GROUP_NAME_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), COMPUTE_ID()); + data()->boolean(COMPUTE_ID())->setValue(true); +} + +//================================================================================================= +AttributePtr FeaturesPlugin_SharedFaces::attributIsCompute() +{ + return attribute(COMPUTE_ID()); +} + +//================================================================================================= +AttributePtr FeaturesPlugin_SharedFaces::attributObject() +{ + return attribute(OBJECT_ID()); +} + +//================================================================================================= +AttributePtr FeaturesPlugin_SharedFaces::attributListFaces() +{ + return attribute(LIST_FACES_ID()); +} + +//================================================================================================= +AttributePtr FeaturesPlugin_SharedFaces::attributNumberFaces() +{ + return attribute(NUMBER_FACES_ID()); +} + +//================================================================================================= +void FeaturesPlugin_SharedFaces::execute() +{ + if (boolean(CREATE_GROUP_ID())->value()) { + + if (string(GROUP_NAME_ID())->value() != "" + && selectionList(LIST_FACES_ID())->isInitialized()) { + + if (lastResult().get()) { + eraseResultFromList(lastResult()); + } + + if (!myCreateGroupFeature.get()) + createGroup(); + updateGroup(); + } + + } else { + if (selectionList(LIST_FACES_ID())->isInitialized()) { + + if (myCreateGroupFeature.get()) { + myCreateGroupFeature->eraseResults(); + SessionPtr aSession = ModelAPI_Session::get(); + DocumentPtr aDoc = aSession->activeDocument(); + aDoc->removeFeature(myCreateGroupFeature); + myCreateGroupFeature.reset(); + } + + if (lastResult().get()) + eraseResultFromList(lastResult()); + setFacesGroup(L"Group_SharedFaces"); + } + } + + if (selection(OBJECT_ID())->isInitialized()) { + AttributeSelectionPtr aCompSolidAttr = selection(OBJECT_ID()); + ResultPtr aResult = aCompSolidAttr->context(); + + double aTranparency = integer(TRANSPARENCY_ID())->value()/100.0; + ModelAPI_Tools::setTransparency(aResult, aTranparency); + + ResultBodyPtr aResultBody = std::dynamic_pointer_cast(aResult); + std::list allRes; + ModelAPI_Tools::allSubs(aResultBody, allRes); + std::list::iterator aRes; + for(aRes = allRes.begin(); aRes != allRes.end(); aRes++) { + ModelAPI_Tools::setTransparency(*aRes, aTranparency); + } + } +} + +//================================================================================================= +void FeaturesPlugin_SharedFaces::attributeChanged(const std::string& theID) +{ + if (theID == OBJECT_ID()) { + + updateFaces(); + if (myCreateGroupFeature.get()) + updateGroup(); + } +} + + +//================================================================================================= +void FeaturesPlugin_SharedFaces::createGroup() +{ + SessionPtr aSession = ModelAPI_Session::get(); + + DocumentPtr aDoc = aSession->activeDocument(); + + if (aDoc.get()) { + myCreateGroupFeature = aDoc->addFeature(FeaturesPlugin_GroupSharedFaces::ID()); + } +} + +//================================================================================================= +void FeaturesPlugin_SharedFaces::updateGroup() +{ + myCreateGroupFeature->boolean(FeaturesPlugin_GroupSharedFaces::COMPUTE_ID())->setValue(false); + myCreateGroupFeature->string(FeaturesPlugin_GroupSharedFaces::GROUP_NAME_ID()) + ->setValue( string(GROUP_NAME_ID())->value()); + + myCreateGroupFeature->selection(FeaturesPlugin_GroupSharedFaces::OBJECT_ID()) + ->setValue( selection(OBJECT_ID())->context() , + selection(OBJECT_ID())->value() ); + AttributeSelectionListPtr aFacesFeatures = + std::dynamic_pointer_cast + (myCreateGroupFeature->attribute(LIST_FACES_ID())); + + AttributeSelectionListPtr aFaces = + std::dynamic_pointer_cast(attribute(LIST_FACES_ID())); + aFaces->copyTo(aFacesFeatures); + + myCreateGroupFeature->integer(FeaturesPlugin_GroupSharedFaces::TRANSPARENCY_ID()) + ->setValue( integer(TRANSPARENCY_ID())->value()); + myCreateGroupFeature->execute(); + myCreateGroupFeature->boolean(FeaturesPlugin_GroupSharedFaces::COMPUTE_ID())->setValue(true); +} diff --git a/src/FeaturesPlugin/FeaturesPlugin_SharedFaces.h b/src/FeaturesPlugin/FeaturesPlugin_SharedFaces.h new file mode 100644 index 000000000..25112533e --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_SharedFaces.h @@ -0,0 +1,133 @@ +// Copyright (C) 2018-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef FeaturesPlugin_SharedFaces_H_ +#define FeaturesPlugin_SharedFaces_H_ + +#include + +/// \class FeaturesPlugin_SharedFaces +/// \ingroup Plugins +/// \brief Feature to check the shared faces of compsolid or compound + +class FeaturesPlugin_SharedFaces : public FeaturesPlugin_CommonSharedFaces +{ +public: + /// Shared faces kind. + inline static const std::string& ID() + { + static const std::string MY_ID("Shared_faces_macro"); + return MY_ID; + } + + /// Attribute name for object selected. + inline static const std::string& OBJECT_ID() + { + static const std::string MY_OBJECT_ID("main_object"); + return MY_OBJECT_ID; + } + + /// Attribute name for number of faces. + inline static const std::string& NUMBER_FACES_ID() + { + static const std::string MY_NUMBER_FACES_ID("number_shared_faces"); + return MY_NUMBER_FACES_ID; + } + + /// Attribute name for z coodinate. + inline static const std::string& LIST_FACES_ID() + { + static const std::string MY_LIST_FACES_ID("group_list"); + return MY_LIST_FACES_ID; + } + + /// Attribute name for transparency. + inline static const std::string& TRANSPARENCY_ID() + { + static const std::string MY_TRANSPARENCY_ID("transparency"); + return MY_TRANSPARENCY_ID; + } + + /// Attribute name for checkbox create group. + inline static const std::string& CREATE_GROUP_ID() + { + static const std::string MY_CREATE_GROUP_ID("create_group"); + return MY_CREATE_GROUP_ID; + } + + /// Attribute name for indicate to launch the algo. + inline static const std::string& COMPUTE_ID() + { + static const std::string MY_COMPUTE_ID("compute"); + return MY_COMPUTE_ID; + } + + /// Attribute name for group name. + inline static const std::string& GROUP_NAME_ID() + { + static const std::string MY_GROUP_NAME_ID("group_name"); + return MY_GROUP_NAME_ID; + } + + /// \return the kind of a feature. + virtual const std::string& getKind() + { + return ID(); + } + + /// Performs the algorithm and stores results it in the data structure. + FEATURESPLUGIN_EXPORT virtual void execute(); + + /// Request for initialization of data model of the feature: adding all attributes + FEATURESPLUGIN_EXPORT virtual void initAttributes(); + + /// Called on change of any argument-attribute of this object + /// \param theID identifier of changed attribute + FEATURESPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID); + + /// Reimplemented from ModelAPI_Feature::isMacro(). Returns true. + FEATURESPLUGIN_EXPORT virtual bool isMacro() const { return true; } + + /// Use plugin manager for features creation + FeaturesPlugin_SharedFaces(); + +private: + /// Return attribut values of object. + virtual AttributePtr attributObject(); + + /// Return attribut values of list of faces. + virtual AttributePtr attributListFaces(); + + /// Return attribut values of number of faces. + virtual AttributePtr attributNumberFaces(); + + /// Return attribut values of IsCompute. + virtual AttributePtr attributIsCompute(); + + /// Create group + void createGroup(); + + /// Update group + void updateGroup(); + + /// Feature to create group + FeaturePtr myCreateGroupFeature; +}; + +#endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts b/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts index 878c1f4d5..252ff625f 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts +++ b/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts @@ -135,6 +135,10 @@ Bounding box Boîte englobante + + Check shared faces + Vérifier les faces partagées + Placement Placement @@ -4966,6 +4970,124 @@ + + + Shared_faces_macro + + Check shared faces + Vérifier les faces partagées + + + Shared faces + Faces partagées + + + Number of shared faces : + Nombre de faces partagées : + + + + Shared_faces_macro:create_group + + Create group + Créer un groupe + + + + Shared_faces_macro:group_name + + Group name + Nom du groupe + + + + Shared_faces_macro:main_object + + Object + Objet + + + Shared faces + Faces partagées + + + + Shared_faces_macro:group_list + + Shared faces + Faces partagées + + + List of faces : + Liste des faces : + + + + Shared_faces_macro:transparency + + Transparency + Transparence + + + + Shared_faces + + Check shared faces + Vérifier les faces partagées + + + Shared faces + Faces partagées + + + Number of shared faces : + Nombre de faces partagées : + + + + Shared_faces:create_group + + Create group + Créer un groupe + + + + Shared_faces:group_name + + Group name + Nom du groupe + + + + Shared_faces:main_object + + Object + Objet + + + Shared faces + Faces partagées + + + + Shared_faces:group_list + + Shared faces + Faces partagées + + + List of faces : + Liste des faces : + + + + Shared_faces:transparency + + Transparency + Transparence + + + Symmetry diff --git a/src/FeaturesPlugin/Test/TestCheckSharedFaces.py b/src/FeaturesPlugin/Test/TestCheckSharedFaces.py new file mode 100644 index 000000000..41f9e5ce7 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestCheckSharedFaces.py @@ -0,0 +1,122 @@ +# Copyright (C) 2014-2021 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +""" + Unit test of Check shared faces +""" +#========================================================================= +# Initialization of the test +#========================================================================= + + +import os +import math + +from ModelAPI import * +from GeomAPI import * +from salome.shaper import model + + +__updated__ = "2020-11-12" + + +if __name__ == '__main__': + + model.begin() + partSet = model.moduleDocument() + Part_1 = model.addPart(partSet) + Part_1_doc = Part_1.document() + ### Create Box + Box_1 = model.addBox(Part_1_doc, 10, 10, 10) + ### Create Point + Point_2 = model.addPoint(Part_1_doc, 20, 10, 10) + ### Create Box + Box_2 = model.addBox(Part_1_doc, model.selection("VERTEX", "[Box_1_1/Front][Box_1_1/Left][Box_1_1/Bottom]"), model.selection("VERTEX", "Point_1")) + ### Create CompSolid + CompSolid_1 = model.addCompSolid(Part_1_doc, [model.selection("SOLID", "Box_1_1"), model.selection("SOLID", "Box_2_1")]) + ### Create Box + Box_3 = model.addBox(Part_1_doc, 10, 10, 10) + ### Create Box + Box_4 = model.addBox(Part_1_doc, 10, 10, 10) + ### Create Translation + Translation_1 = model.addTranslation(Part_1_doc, [model.selection("COMPOUND", "all-in-Box_4")], axis = model.selection("EDGE", "PartSet/OX"), + distance = 10, keepSubResults = True) + ### Create CompSolid + CompSolid_2 = model.addCompSolid(Part_1_doc, [model.selection("SOLID", "Box_3_1"), model.selection("COMPOUND", "Translation_1_1")]) + ### Create Box + Box_5 = model.addBox(Part_1_doc, 10, 10, 10) + ### Create Translation + Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_5_1")], vector = [10, 0, 10], keepSubResults = True) + ### Create Compound + Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPSOLID", "CompSolid_1_1"), model.selection("SOLID", "Translation_2_1")]) + Compound_1.result().setTransparency(0.5) + Compound_1.result().subResult(0).setTransparency(0.5) + Compound_1.result().subResult(0).subResult(0).setTransparency(0.5) + Compound_1.result().subResult(0).subResult(1).setTransparency(0.5) + Compound_1.result().subResult(1).setTransparency(0.5) + + ### Create Shared_faces for compsolid + Shared_faces_1 = model.getSharedFaces(Part_1_doc, model.selection("COMPSOLID", "CompSolid_1_1"), "faces_compsolid") + + ### Create Shared_faces for compound + Shared_faces_2 = model.getSharedFaces(Part_1_doc, model.selection("COMPOUND", "Compound_1_1"), 'faces_compound') + + model.do() + + # Check results + assert(Part_1_doc.size("Groups") == 2) + Shared_faces_1_Feature = Shared_faces_1.feature() + assert Shared_faces_1_Feature.error() == '' + assert Shared_faces_1_Feature.name() == "Shared_faces_1" + + aSelectionList = Shared_faces_1_Feature.selectionList("group_list") + assert aSelectionList.size() == 1 + + Shared_faces_2_Feature = Shared_faces_2.feature() + assert Shared_faces_2_Feature.error() == '' + assert Shared_faces_2_Feature.name() == "Shared_faces_2" + + aSelectionList = Shared_faces_2_Feature.selectionList("group_list") + assert aSelectionList.size() == 1 + + resShape_1 = modelAPI_Result(Part_1_doc.object("Groups", 0)).shape() + assert(not resShape_1.isNull()) + + # the group result is a face, check that this is one face + aShapeExplorer = GeomAPI_ShapeExplorer(resShape_1, GeomAPI_Shape.FACE) + assert(aShapeExplorer.more()) + assert(aShapeExplorer.current().isFace()) + aShapeExplorer.next() + assert(not aShapeExplorer.more()) + + resShape_2 = modelAPI_Result(Part_1_doc.object("Groups", 1)).shape() + assert(not resShape_2.isNull()) + + # the group result is a face, check that this is one face + aShapeExplorer = GeomAPI_ShapeExplorer(resShape_2, GeomAPI_Shape.FACE) + assert(aShapeExplorer.more()) + assert(aShapeExplorer.current().isFace()) + aShapeExplorer.next() + assert(not aShapeExplorer.more()) + + model.end() + + #========================================================================= + # End of test + #========================================================================= diff --git a/src/FeaturesPlugin/doc/FeaturesPlugin.rst b/src/FeaturesPlugin/doc/FeaturesPlugin.rst index 6fc8177bd..ba11483df 100644 --- a/src/FeaturesPlugin/doc/FeaturesPlugin.rst +++ b/src/FeaturesPlugin/doc/FeaturesPlugin.rst @@ -14,6 +14,7 @@ Features plug-in provides a set of common topological operations. It implements angularCopyFeature.rst boundingBoxFeature.rst chamferFeature.rst + checkSharedFaceFeature.rst copyFeature.rst defeaturingFeature.rst extrusionCutFeature.rst diff --git a/src/FeaturesPlugin/doc/TUI_sharedFacesFeature.rst b/src/FeaturesPlugin/doc/TUI_sharedFacesFeature.rst new file mode 100644 index 000000000..48e2f331c --- /dev/null +++ b/src/FeaturesPlugin/doc/TUI_sharedFacesFeature.rst @@ -0,0 +1,11 @@ + + .. _tui_shared_faces: + +Check shared faces +================== + +.. literalinclude:: examples/check_shared_faces.py + :linenos: + :language: python + +:download:`Download this script ` diff --git a/src/FeaturesPlugin/doc/checkSharedFaceFeature.rst b/src/FeaturesPlugin/doc/checkSharedFaceFeature.rst new file mode 100644 index 000000000..48b7ec39e --- /dev/null +++ b/src/FeaturesPlugin/doc/checkSharedFaceFeature.rst @@ -0,0 +1,52 @@ +.. |shared_shapes.icon| image:: images/shared_shapes.png + +Check shared faces +================== + +The **Check shared faces** feature find the shared faces within a composolid or compound. + +The result is a list of faces and a group that can be created with a specified name. + +To check shared faces in the active part: + +#. Select in the Main Menu *Inspection - > Check shared faces* item or +#. Click |shared_shapes.icon| **Check shared faces** button in the toolbar + +The property panel is shown below. + +.. figure:: images/checkSharedFacesPropertyPanel.png + :align: center + + Check shared faces + + +Input fields: + +- **Object** contains composolid or compound selected in 3D OCC viewer or object browser. +- **Number of shared faces** indicate the number of found faces. +- **List of faces** the list of found faces. +- **Transparency** set the transparency of selected object. +- **Create group** check-box that allows the creation of the found faces group. +- **Group name** specifies the name of the group created. + + +**TUI Command**: + +.. py:function:: model.getSharedFaces(Part_doc, shape, nameGroup) + + :param part: The current part object. + :param object: A composolid or compound in format *model.selection(TYPE, shape)*. + :param string: The name of group to create + :return: Created group. + +Result +"""""" + +Result of **Check shared faces** where **Create group** is checked. + +.. figure:: images/sharedFacesResult.png + :align: center + + Shared faces + +**See Also** a sample TUI Script of :ref:`tui_shared_faces` operation. diff --git a/src/FeaturesPlugin/doc/examples/check_shared_faces.py b/src/FeaturesPlugin/doc/examples/check_shared_faces.py new file mode 100644 index 000000000..198027331 --- /dev/null +++ b/src/FeaturesPlugin/doc/examples/check_shared_faces.py @@ -0,0 +1,21 @@ +from salome.shaper import model +import os + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +### Create Box +Box_1 = model.addBox(Part_1_doc, 10, 10, 10) +### Create Point +Point_2 = model.addPoint(Part_1_doc, 20, 10, 10) +### Create Box +Box_2 = model.addBox(Part_1_doc, model.selection("VERTEX", "[Box_1_1/Front][Box_1_1/Left][Box_1_1/Bottom]"), model.selection("VERTEX", "Point_1")) +### Create CompSolid +CompSolid_1 = model.addCompSolid(Part_1_doc, [model.selection("SOLID", "Box_1_1"), model.selection("SOLID", "Box_2_1")]) + +### Create Shared_faces +Shared_faces_1 = model.getSharedFaces(Part_1_doc, model.selection("COMPSOLID", "CompSolid_1_1"), "mygroup") + +model.do() +model.end() diff --git a/src/FeaturesPlugin/doc/images/checkSharedFacesPropertyPanel.png b/src/FeaturesPlugin/doc/images/checkSharedFacesPropertyPanel.png new file mode 100644 index 0000000000000000000000000000000000000000..c5f0ee92ae482dd0a8d249ee5224ea66378007ee GIT binary patch literal 26398 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 Tqvv^iOA5u&&egVz<1hFZOWeaI literal 0 HcmV?d00001 diff --git a/src/FeaturesPlugin/doc/images/sharedFacesResult.png b/src/FeaturesPlugin/doc/images/sharedFacesResult.png new file mode 100644 index 0000000000000000000000000000000000000000..114ac342149b334af9c2478682effc4d250ff046 GIT binary patch literal 7992 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 literal 0 HcmV?d00001 diff --git a/src/FeaturesPlugin/doc/images/shared_shapes.png b/src/FeaturesPlugin/doc/images/shared_shapes.png new file mode 100644 index 0000000000000000000000000000000000000000..23f804802251319855cadf3afb9bdabb5182e900 GIT binary patch literal 583 zcmV-N0=WH&P)bgGWIS@MM7DVsg zT;{Y$DPd*+G)+U(G}Lv?dcEE@O|yle1kO1`q-skICn*>%Fqoz*B@Fc)W9X*W+AKNZWNCW(f&_Xpg5lBUL3vMMO}M17Qe(?qQFJ zKuXk2^K8;nXaPRFT`wFbH-CcQJrV+{Qf4+2UIQP;JLBg2&%e}7LseCzlt^Y+8tSX6 z?C<~Ky(4%}kT4_M1HX<0+-Ovi3dwBv&QxcF!FxmkDuSxa2zS6&=8L|S5QwUXN=YrR zV2p8SV$?E1Q^E(}_o7C5EXK4%LV0LrsK}r=C93N1S)8l=bgGWIS@MM7DVsg zT;{Y$DPd*+G)+U(G}Lv?dcEE@O|yle1kO1`q-skICn*>%Fqoz*B@Fc)W9X*W+AKNZWNCW(f&_Xpg5lBUL3vMMO}M17Qe(?qQFJ zKuXk2^K8;nXaPRFT`wFbH-CcQJrV+{Qf4+2UIQP;JLBg2&%e}7LseCzlt^Y+8tSX6 z?C<~Ky(4%}kT4_M1HX<0+-Ovi3dwBv&QxcF!FxmkDuSxa2zS6&=8L|S5QwUXN=YrR zV2p8SV$?E1Q^E(}_o7C5EXK4%LV0LrsK}r=C93N1S)8l= + icon="icons/Features/fusion_faces.png" auto_preview="true" helpfile="fusionFacesFeature.html"> + + + + + + diff --git a/src/FeaturesPlugin/shared_faces_macro_widget.xml b/src/FeaturesPlugin/shared_faces_macro_widget.xml new file mode 100644 index 000000000..d9e1e4c5d --- /dev/null +++ b/src/FeaturesPlugin/shared_faces_macro_widget.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + diff --git a/src/FeaturesPlugin/shared_faces_widget.xml b/src/FeaturesPlugin/shared_faces_widget.xml new file mode 100644 index 000000000..0c637211e --- /dev/null +++ b/src/FeaturesPlugin/shared_faces_widget.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + diff --git a/src/FeaturesPlugin/tests.set b/src/FeaturesPlugin/tests.set index 1274228bc..b5c8ae5c0 100644 --- a/src/FeaturesPlugin/tests.set +++ b/src/FeaturesPlugin/tests.set @@ -526,4 +526,5 @@ SET(TEST_NAMES TestBoundingBox.py Test23885.py TestNormalToFace.py + TestCheckSharedFaces.py ) diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp index 1d07bf469..36798b6c5 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp @@ -1468,3 +1468,20 @@ void GeomAlgoAPI_ShapeTools::computeThroughAll(const ListOfShape& theObjects, } } } + +ListOfShape GeomAlgoAPI_ShapeTools::getSharedFaces(const GeomShapePtr& theShape) +{ + ListOfShape aSharedFaces; + TopTools_IndexedDataMapOfShapeListOfShape aMapFS; + TopExp::MapShapesAndUniqueAncestors(theShape->impl(), + TopAbs_FACE, TopAbs_SOLID, aMapFS); + for (Standard_Integer i = 1; i <= aMapFS.Extent(); i++) { + const TopTools_ListOfShape& ancestors = aMapFS.FindFromIndex(i); + if (ancestors.Size() > 1) { + GeomShapePtr aFace(new GeomAPI_Shape); + aFace->setImpl(new TopoDS_Shape(aMapFS.FindKey(i))); + aSharedFaces.push_back(aFace); + } + } + return aSharedFaces; +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h index 5d26f7af7..271d18b5f 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h @@ -230,6 +230,11 @@ public: const ListOfShape& theBaseShapes, const std::shared_ptr theDir, double& theToSize, double& theFromSize); + + /// \brief Get shared faces of a shape + /// \param[in] theShape shape that should be exploded + /// \return list of shared faces + GEOMALGOAPI_EXPORT static ListOfShape getSharedFaces(const GeomShapePtr& theShape); }; #endif diff --git a/src/PythonAPI/model/features/__init__.py b/src/PythonAPI/model/features/__init__.py index 62a0ca1a8..4aa14910f 100644 --- a/src/PythonAPI/model/features/__init__.py +++ b/src/PythonAPI/model/features/__init__.py @@ -31,7 +31,7 @@ from FeaturesAPI import addFillet, addChamfer from FeaturesAPI import addFusionFaces from FeaturesAPI import measureLength, measureDistance, measureRadius, measureAngle from FeaturesAPI import getPointCoordinates, getGeometryCalculation, getBoundingBox -from FeaturesAPI import getNormal +from FeaturesAPI import getNormal, getSharedFaces from FeaturesAPI import addRemoveResults from FeaturesAPI import addCopy, addImportResult from FeaturesAPI import addDefeaturing -- 2.39.2