From: vsr Date: Mon, 31 Jan 2011 09:26:19 +0000 (+0000) Subject: 0020876: EDF 1246 SMESH: DoubleNodes fonctions available in the GUI X-Git-Tag: StartingPortingMED3~91 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=e30e3628ce1c7687b6e462e793c9e402684811e1;p=modules%2Fsmesh.git 0020876: EDF 1246 SMESH: DoubleNodes fonctions available in the GUI Allow multiple selection of groups as input --- diff --git a/idl/SMESH_MeshEditor.idl b/idl/SMESH_MeshEditor.idl index f001799cf..8b038becf 100644 --- a/idl/SMESH_MeshEditor.idl +++ b/idl/SMESH_MeshEditor.idl @@ -772,27 +772,27 @@ module SMESH * they not assigned to elements * \return TRUE if operation has been completed successfully, FALSE otherwise * \sa DoubleNode(), DoubleNodeGroup(), DoubleNodeGroups() - */ + */ boolean DoubleNodes( in long_array theNodes, in long_array theModifiedElems ); /*! - * \brief Creates a hole in a mesh by doubling the nodes of some particular elements - * This method provided for convenience works as DoubleNodes() described above. - * \param theNodeId - identifier of node to be doubled. - * \param theModifiedElems - identifiers of elements to be updated. - * \return TRUE if operation has been completed successfully, FALSE otherwise - * \sa DoubleNodes(), DoubleNodeGroup(), DoubleNodeGroups() - */ + * \brief Creates a hole in a mesh by doubling the nodes of some particular elements + * This method provided for convenience works as DoubleNodes() described above. + * \param theNodeId - identifier of node to be doubled. + * \param theModifiedElems - identifiers of elements to be updated. + * \return TRUE if operation has been completed successfully, FALSE otherwise + * \sa DoubleNodes(), DoubleNodeGroup(), DoubleNodeGroups() + */ boolean DoubleNode( in long theNodeId, in long_array theModifiedElems ); /*! - * \brief Creates a hole in a mesh by doubling the nodes of some particular elements - * This method provided for convenience works as DoubleNodes() described above. - * \param theNodes - group of nodes to be doubled. - * \param theModifiedElems - group of elements to be updated. - * \return TRUE if operation has been completed successfully, FALSE otherwise - * \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups(), DoubleNodeGroupNew() - */ + * \brief Creates a hole in a mesh by doubling the nodes of some particular elements + * This method provided for convenience works as DoubleNodes() described above. + * \param theNodes - group of nodes to be doubled. + * \param theModifiedElems - group of elements to be updated. + * \return TRUE if operation has been completed successfully, FALSE otherwise + * \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups(), DoubleNodeGroupNew() + */ boolean DoubleNodeGroup( in SMESH_GroupBase theNodes, in SMESH_GroupBase theModifiedElems ); @@ -809,16 +809,28 @@ module SMESH in SMESH_GroupBase theModifiedElems ); /*! - \brief Creates a hole in a mesh by doubling the nodes of some particular elements - This method provided for convenience works as DoubleNodes() described above. - \param theNodes - list of groups of nodes to be doubled - \param theModifiedElems - list of groups of elements to be updated. - \return TRUE if operation has been completed successfully, FALSE otherwise - \sa DoubleNode(), DoubleNodeGroup(), DoubleNodes() - */ + * \brief Creates a hole in a mesh by doubling the nodes of some particular elements + * This method provided for convenience works as DoubleNodes() described above. + * \param theNodes - list of groups of nodes to be doubled + * \param theModifiedElems - list of groups of elements to be updated. + * \return TRUE if operation has been completed successfully, FALSE otherwise + * \sa DoubleNode(), DoubleNodeGroup(), DoubleNodes() + */ boolean DoubleNodeGroups( in ListOfGroups theNodes, in ListOfGroups theModifiedElems ); + /*! + * \brief Creates a hole in a mesh by doubling the nodes of some particular elements + * Works as DoubleNodeGroups() described above, but returns a new group with + * newly created nodes. + * \param theNodes - list of groups of nodes to be doubled + * \param theModifiedElems - list of groups of elements to be updated. + * \return a new group with newly created nodes + * \sa DoubleNodeGroups() + */ + SMESH_Group DoubleNodeGroupsNew( in ListOfGroups theNodes, + in ListOfGroups theModifiedElems ); + /*! * \brief Creates a hole in a mesh by doubling the nodes of some particular elements * \param theElems - the list of elements (edges or faces) to be replicated @@ -828,7 +840,7 @@ module SMESH * replicated nodes should be associated to. * \return TRUE if operation has been completed successfully, FALSE otherwise * \sa DoubleNodeGroup(), DoubleNodeGroups() - */ + */ boolean DoubleNodeElem( in long_array theElems, in long_array theNodesNot, in long_array theAffectedElems ); @@ -843,7 +855,7 @@ module SMESH * The replicated nodes should be associated to affected elements. * \return TRUE if operation has been completed successfully, FALSE otherwise * \sa DoubleNodeGroupInRegion(), DoubleNodeGroupsInRegion() - */ + */ boolean DoubleNodeElemInRegion( in long_array theElems, in long_array theNodesNot, in GEOM::GEOM_Object theShape ); @@ -857,7 +869,7 @@ module SMESH * should be associated to. * \return TRUE if operation has been completed successfully, FALSE otherwise * \sa DoubleNodes(), DoubleNodeGroups(), DoubleNodeElemGroupNew() - */ + */ boolean DoubleNodeElemGroup( in SMESH_GroupBase theElems, in SMESH_GroupBase theNodesNot, in SMESH_GroupBase theAffectedElems ); @@ -872,7 +884,7 @@ module SMESH * should be associated to. * \return a new group with newly created elements * \sa DoubleNodeElemGroup() - */ + */ SMESH_Group DoubleNodeElemGroupNew( in SMESH_GroupBase theElems, in SMESH_GroupBase theNodesNot, in SMESH_GroupBase theAffectedElems ); @@ -887,7 +899,7 @@ module SMESH * The replicated nodes should be associated to affected elements. * \return TRUE if operation has been completed successfully, FALSE otherwise * \sa DoubleNodesInRegion(), DoubleNodeGroupsInRegion() - */ + */ boolean DoubleNodeElemGroupInRegion( in SMESH_GroupBase theElems, in SMESH_GroupBase theNodesNot, in GEOM::GEOM_Object theShape ); @@ -901,7 +913,7 @@ module SMESH * should be associated to. * \return TRUE if operation has been completed successfully, FALSE otherwise * \sa DoubleNodeGroup(), DoubleNodes(), DoubleNodeElemGroupsNew() - */ + */ boolean DoubleNodeElemGroups( in ListOfGroups theElems, in ListOfGroups theNodesNot, in ListOfGroups theAffectedElems ); @@ -916,7 +928,7 @@ module SMESH * should be associated to. * \return a new group with newly created elements * \sa DoubleNodeElemGroups() - */ + */ SMESH_Group DoubleNodeElemGroupsNew( in ListOfGroups theElems, in ListOfGroups theNodesNot, in ListOfGroups theAffectedElems ); @@ -931,7 +943,7 @@ module SMESH * The replicated nodes should be associated to affected elements. * \return TRUE if operation has been completed successfully, FALSE otherwise * \sa DoubleNodeGroupInRegion(), DoubleNodesInRegion() - */ + */ boolean DoubleNodeElemGroupsInRegion( in ListOfGroups theElems, in ListOfGroups theNodesNot, in GEOM::GEOM_Object theShape ); diff --git a/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.cxx b/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.cxx index a2a0afd9c..a51278687 100644 --- a/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.cxx @@ -47,6 +47,7 @@ #include #include +#include // Qt includes #include @@ -70,6 +71,22 @@ #define SPACING 6 #define MARGIN 11 +/*! + \class BusyLocker + \brief Simple 'busy state' flag locker. + \internal +*/ + +class BusyLocker +{ +public: + //! Constructor. Sets passed boolean flag to \c true. + BusyLocker( bool& busy ) : myBusy( busy ) { myBusy = true; } + //! Destructor. Clear external boolean flag passed as parameter to the constructor to \c false. + ~BusyLocker() { myBusy = false; } +private: + bool& myBusy; //! External 'busy state' boolean flag +}; /*! \brief Constructor @@ -218,14 +235,15 @@ SMESHGUI_DuplicateNodesDlg::~SMESHGUI_DuplicateNodesDlg() void SMESHGUI_DuplicateNodesDlg::Init() { mySMESHGUI->SetActiveDialogBox((QDialog*)this); + myCheckBoxNewGroup->setChecked(true); // Set initial parameters myBusy = false; myCurrentLineEdit = myLineEdit1; - myGroup1 = SMESH::SMESH_GroupBase::_nil(); - myGroup2 = SMESH::SMESH_GroupBase::_nil(); - myGroup3 = SMESH::SMESH_GroupBase::_nil(); + myGroups1.clear(); + myGroups2.clear(); + myGroups3.clear(); // Set selection mode mySelectionMgr->installFilter(new SMESH_TypeFilter(GROUP)); @@ -253,8 +271,9 @@ void SMESHGUI_DuplicateNodesDlg::onConstructorsClicked (int constructorId) myLineEdit2->clear(); myLineEdit3->clear(); - // Checkbox should be checked by default - myCheckBoxNewGroup->setChecked(true); + myGroups1.clear(); + myGroups2.clear(); + myGroups3.clear(); // Set the first field as current myCurrentLineEdit = myLineEdit1; @@ -307,10 +326,10 @@ void SMESHGUI_DuplicateNodesDlg::onConstructorsClicked (int constructorId) */ bool SMESHGUI_DuplicateNodesDlg::onApply() { - if (mySMESHGUI->isActiveStudyLocked() || !isValid()) + if ( mySMESHGUI->isActiveStudyLocked() || !isValid() ) return false; - myBusy = true; + BusyLocker lock( myBusy ); bool toCreateGroup = myCheckBoxNewGroup->isChecked(); int operationMode = myGroupConstructors->checkedId(); @@ -320,28 +339,50 @@ bool SMESHGUI_DuplicateNodesDlg::onApply() SUIT_OverrideCursor aWaitCursor; try { - SMESH::SMESH_Mesh_ptr aMesh = myGroup1->GetMesh(); + SMESH::SMESH_Mesh_var aMesh = myGroups1[0]->GetMesh(); SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor(); - if (operationMode == 0) { - if (toCreateGroup) { - SMESH::SMESH_GroupBase_ptr aNewGroup = - aMeshEditor->DoubleNodeGroupNew(myGroup1, myGroup2); - if (!CORBA::is_nil(aNewGroup)) - result = true; + if ( operationMode == 0 ) { + SMESH::ListOfGroups_var g1 = new SMESH::ListOfGroups(); + g1->length( myGroups1.count() ); + for ( int i = 0; i < myGroups1.count(); i++ ) + g1[i] = myGroups1[i]; + SMESH::ListOfGroups_var g2 = new SMESH::ListOfGroups(); + g2->length( myGroups2.count() ); + for ( int i = 0; i < myGroups2.count(); i++ ) + g2[i] = myGroups2[i]; + + if ( toCreateGroup ) { + SMESH::SMESH_GroupBase_var aNewGroup = + aMeshEditor->DoubleNodeGroupsNew( g1.in(), g2.in() ); + result = !CORBA::is_nil( aNewGroup ); + } + else { + result = aMeshEditor->DoubleNodeGroups( g1.in(), g2.in() ); } - else - result = aMeshEditor->DoubleNodeGroup(myGroup1, myGroup2); } else { - if (toCreateGroup) { + SMESH::ListOfGroups_var g1 = new SMESH::ListOfGroups(); + g1->length( myGroups1.count() ); + for ( int i = 0; i < myGroups1.count(); i++ ) + g1[i] = myGroups1[i]; + SMESH::ListOfGroups_var g2 = new SMESH::ListOfGroups(); + g2->length( myGroups2.count() ); + for ( int i = 0; i < myGroups2.count(); i++ ) + g2[i] = myGroups2[i]; + SMESH::ListOfGroups_var g3 = new SMESH::ListOfGroups(); + g3->length( myGroups3.count() ); + + for ( int i = 0; i < myGroups3.count(); i++ ) + g3[i] = myGroups3[i]; + if ( toCreateGroup ) { SMESH::SMESH_GroupBase_ptr aNewGroup = - aMeshEditor->DoubleNodeElemGroupNew(myGroup1, myGroup2, myGroup3); - if (!CORBA::is_nil(aNewGroup)) - result = true; + aMeshEditor->DoubleNodeElemGroupsNew( g1.in(), g2.in(), g3.in() ); + result = !CORBA::is_nil( aNewGroup ); + } + else { + result = aMeshEditor->DoubleNodeElemGroups( g1.in(), g2.in(), g3.in() ); } - else - result = aMeshEditor->DoubleNodeElemGroup(myGroup1, myGroup2, myGroup3); } } catch (const SALOME::SALOME_Exception& S_ex) { @@ -358,7 +399,6 @@ bool SMESHGUI_DuplicateNodesDlg::onApply() SUIT_MessageBox::warning(this, tr("SMESH_WRN_WARNING"), tr("SMESH_OPERATION_FAILED")); - myBusy = false; return false; } @@ -400,64 +440,67 @@ void SMESHGUI_DuplicateNodesDlg::onClose() */ void SMESHGUI_DuplicateNodesDlg::onSelectionChanged() { - if (myBusy || !isEnabled()) return; + if ( myBusy || !isEnabled() ) return; - // Try to get selected group + int operationMode = myGroupConstructors->checkedId(); + SALOME_ListIO aList; mySelectionMgr->selectedObjects( aList ); int aNbSel = aList.Extent(); - SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_nil(); - if (aNbSel == 1) { - Handle(SALOME_InteractiveObject) IO = aList.First(); - aGroup = SMESH::IObjectToInterface(IO); - - // Check group type - if (!CORBA::is_nil(aGroup)) { - int operationMode = myGroupConstructors->checkedId(); + QList aGroups; + + SALOME_ListIteratorOfListIO anIter ( aList ); + bool ok = true; + for ( ; anIter.More() && ok; anIter.Next()) { + SMESH::SMESH_GroupBase_var aGroup = SMESH::IObjectToInterface( anIter.Value() ); + // check group is selected + ok = !CORBA::is_nil( aGroup ); + // check groups of the same mesh are selected + if ( ok ) { + SMESH::SMESH_Mesh_var aMesh1; + if ( !aGroups.isEmpty() ) aMesh1 = aGroups[0]->GetMesh(); + SMESH::SMESH_Mesh_var aMesh2 = aGroup->GetMesh(); + ok = CORBA::is_nil( aMesh1 ) || aMesh1->_is_equivalent( aMesh2 ); + } + // check group of proper type is selected + if ( ok ) { SMESH::ElementType aGroupType = aGroup->GetType(); - bool isTypeValid = true; - - if (operationMode == 0) { - if ( (myCurrentLineEdit == myLineEdit1 && aGroupType != SMESH::NODE) || - (myCurrentLineEdit == myLineEdit2 && aGroupType == SMESH::NODE) ) - isTypeValid = false; + if ( operationMode == 0 ) { + ok = ( myCurrentLineEdit == myLineEdit1 && aGroupType == SMESH::NODE ) || + ( myCurrentLineEdit == myLineEdit2 && aGroupType != SMESH::NODE ); } - else if (operationMode == 1) { - if ( (myCurrentLineEdit == myLineEdit1 && aGroupType != SMESH::EDGE && - aGroupType != SMESH::FACE) || - (myCurrentLineEdit == myLineEdit2 && aGroupType != SMESH::NODE) || - (myCurrentLineEdit == myLineEdit3 && aGroupType == SMESH::NODE) ) - isTypeValid = false; + else { + ok = ( myCurrentLineEdit == myLineEdit1 && ( aGroupType == SMESH::EDGE || + aGroupType == SMESH::FACE ) ) || + ( myCurrentLineEdit == myLineEdit2 && aGroupType == SMESH::NODE ) || + ( myCurrentLineEdit == myLineEdit3 && aGroupType != SMESH::NODE ); } - - if (!isTypeValid) - aGroup = SMESH::SMESH_GroupBase::_nil(); } + if ( ok ) aGroups << aGroup; } // Clear current field myCurrentLineEdit->clear(); - // Set corresponding SMESH group - if (myCurrentLineEdit == myLineEdit1) { - myGroup1 = SMESH::SMESH_Group::_narrow(aGroup); + if ( ok && !aGroups.isEmpty() ) { + if ( myCurrentLineEdit == myLineEdit1 ) myGroups1 = aGroups; + else if ( myCurrentLineEdit == myLineEdit2 ) myGroups2 = aGroups; + else if ( myCurrentLineEdit == myLineEdit3 ) myGroups3 = aGroups; + myCurrentLineEdit->setText( aGroups.count() == 1 ? aGroups[0]->GetName() : + QObject::tr( "SMESH_OBJECTS_SELECTED" ).arg( aGroups.count() ) ); } - else if (myCurrentLineEdit == myLineEdit2) { - myGroup2 = SMESH::SMESH_Group::_narrow(aGroup); - } - else if (myCurrentLineEdit == myLineEdit3) { - myGroup3 = SMESH::SMESH_Group::_narrow(aGroup); + else { + if ( myCurrentLineEdit == myLineEdit1 ) myGroups1.clear(); + else if ( myCurrentLineEdit == myLineEdit2 ) myGroups2.clear(); + else if ( myCurrentLineEdit == myLineEdit3 ) myGroups3.clear(); + myCurrentLineEdit->clear(); } - - // Set group name - if (!CORBA::is_nil(aGroup)) - myCurrentLineEdit->setText(aGroup->GetName()); // Enable/disable "Apply and Close" and "Apply" buttons bool isDataValid = isValid(); - myButtonOk->setEnabled(isDataValid); - myButtonApply->setEnabled(isDataValid); + myButtonOk->setEnabled( isDataValid ); + myButtonApply->setEnabled( isDataValid ); } /*! @@ -488,14 +531,9 @@ void SMESHGUI_DuplicateNodesDlg::onEditCurrentArgument() */ bool SMESHGUI_DuplicateNodesDlg::isValid() { - // Only first group (nodes/elemets to duplicate) is mandatory - bool isValid = !CORBA::is_nil(myGroup1); - - // First (elements to duplicate) and last groups should be defined in the second operation mode - if (isValid && myGroupConstructors->checkedId() == 1) - isValid = !CORBA::is_nil(myGroup3); - - return isValid; + return myGroupConstructors->checkedId() == 1 ? + ( !myGroups1.isEmpty() && !myGroups3.isEmpty() ) : + ( !myGroups1.isEmpty() ); } diff --git a/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.h b/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.h index 974b7d7fa..91b9af300 100644 --- a/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.h +++ b/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.h @@ -107,9 +107,9 @@ private: SMESHGUI* mySMESHGUI; LightApp_SelectionMgr* mySelectionMgr; - SMESH::SMESH_GroupBase_var myGroup1; - SMESH::SMESH_GroupBase_var myGroup2; - SMESH::SMESH_GroupBase_var myGroup3; + QList myGroups1; + QList myGroups2; + QList myGroups3; bool myBusy; diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx index 3ffce11d3..f08fa9c87 100644 --- a/src/SMESH_I/SMESH_2smeshpy.cxx +++ b/src/SMESH_I/SMESH_2smeshpy.cxx @@ -1195,8 +1195,10 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand) } // DoubleNodeElemGroupNew() -> DoubleNodeElemGroup() // DoubleNodeGroupNew() -> DoubleNodeGroup() + // DoubleNodeGroupsNew() -> DoubleNodeGroups() // DoubleNodeElemGroupsNew() -> DoubleNodeElemGroups() - if ( !isPyMeshMethod && ( method == "DoubleNodeElemGroupNew" || method == "DoubleNodeGroupNew" || method == "DoubleNodeElemGroupsNew")) + if ( !isPyMeshMethod && ( method == "DoubleNodeElemGroupNew" || method == "DoubleNodeElemGroupsNew" || + method == "DoubleNodeGroupNew" || method == "DoubleNodeGroupsNew")) { isPyMeshMethod=true; theCommand->SetMethod( method.SubString( 1, method.Length()-3)); diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index 9d1cf79dd..608b95e90 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -4898,6 +4898,45 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& t return aResult; } +//================================================================================ +/*! + * \brief Creates a hole in a mesh by doubling the nodes of some particular elements. + * Works as DoubleNodeGroups(), but returns a new group with newly created nodes. + * \param theNodes - group of nodes to be doubled. + * \param theModifiedElems - group of elements to be updated. + * \return a new group with newly created nodes + * \sa DoubleNodeGroups() + */ +//================================================================================ + +SMESH::SMESH_Group_ptr SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes, + const SMESH::ListOfGroups& theModifiedElems ) +{ + SMESH::SMESH_Group_var aNewGroup; + + TPythonDump pyDump; // suppress dump by the next line + + bool aResult = DoubleNodeGroups( theNodes, theModifiedElems ); + + if ( aResult ) + { + // Create group with newly created nodes + SMESH::long_array_var anIds = GetLastCreatedNodes(); + if (anIds->length() > 0) { + string anUnindexedName (theNodes[0]->GetName()); + string aNewName = generateGroupName(anUnindexedName + "_double"); + aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str()); + aNewGroup->Add(anIds); + } + } + + pyDump << "createdNodes = " << this << ".DoubleNodeGroupsNew( " << theNodes << ", " + << theModifiedElems << " )"; + + return aNewGroup._retn(); +} + + //================================================================================ /*! \brief Creates a hole in a mesh by doubling the nodes of some particular elements diff --git a/src/SMESH_I/SMESH_MeshEditor_i.hxx b/src/SMESH_I/SMESH_MeshEditor_i.hxx index ea8f30142..3938fd87c 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.hxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.hxx @@ -569,7 +569,10 @@ public: SMESH::SMESH_GroupBase_ptr theModifiedElems ); CORBA::Boolean DoubleNodeGroups( const SMESH::ListOfGroups& theNodes, - const SMESH::ListOfGroups& theModifiedElems); + const SMESH::ListOfGroups& theModifiedElems ); + + SMESH::SMESH_Group_ptr DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes, + const SMESH::ListOfGroups& theModifiedElems ); /*! * \brief Creates a hole in a mesh by doubling the nodes of some particular elements diff --git a/src/SMESH_SWIG/smeshDC.py b/src/SMESH_SWIG/smeshDC.py index 5fa6cc4b4..eb1f50573 100644 --- a/src/SMESH_SWIG/smeshDC.py +++ b/src/SMESH_SWIG/smeshDC.py @@ -4031,7 +4031,9 @@ class Mesh: # @param theModifiedElems list of groups of elements to be updated. # @return TRUE if operation has been completed successfully, FALSE otherwise # @ingroup l2_modif_edit - def DoubleNodeGroups(self, theNodes, theModifiedElems): + def DoubleNodeGroups(self, theNodes, theModifiedElems, theMakeGroup=False): + if theMakeGroup: + return self.editor.DoubleNodeGroupsNew(theNodes, theModifiedElems) return self.editor.DoubleNodeGroups(theNodes, theModifiedElems) ## Creates a hole in a mesh by doubling the nodes of some particular elements