Salome HOME
Merge branch 'V9_9_BR'
[modules/smesh.git] / src / SMESH_I / SMESH_MeshEditor_i.cxx
index 14ed601a62739d64bfc82f9a65683f065f269a31..e87f092a24eedb24845e8929c5ed63f03f1f1def 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2021  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2022  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -102,7 +102,7 @@ namespace MeshEditor_I {
     //!< Constructor
     TPreviewMesh(SMDSAbs_ElementType previewElements = SMDSAbs_All) {
       _isShapeToMesh = (_id = 0);
-      _myMeshDS  = new SMESHDS_Mesh( _id, true );
+      _meshDS  = new SMESHDS_Mesh( _id, true );
       myPreviewType = previewElements;
     }
     //!< Copy a set of elements
@@ -155,8 +155,8 @@ namespace MeshEditor_I {
     //!< Copy a node
     SMDS_MeshNode* Copy( const SMDS_MeshNode* anElemNode )
     {
-      return _myMeshDS->AddNodeWithID(anElemNode->X(), anElemNode->Y(), anElemNode->Z(),
-                                      anElemNode->GetID());
+      return _meshDS->AddNodeWithID(anElemNode->X(), anElemNode->Y(), anElemNode->Z(),
+                                    anElemNode->GetID());
     }
     void RemoveAll()
     {
@@ -279,13 +279,13 @@ namespace MeshEditor_I {
     SMDS_MeshElement::Filter & filter = *aFilter;
 
     if ( aType == SMDSAbs_Node )
-      for ( SMESH::smIdType i = 0; i < IDs.length(); i++ ) {
+      for ( CORBA::ULong i = 0; i < IDs.length(); i++ ) {
         const SMDS_MeshElement * elem = aMesh->FindNode( IDs[i] );
         if ( filter( elem ))
           aMap.insert( aMap.end(), elem );
       }
     else
-      for ( SMESH::smIdType i = 0; i<IDs.length(); i++) {
+      for ( CORBA::ULong i = 0; i<IDs.length(); i++) {
         const SMDS_MeshElement * elem = aMesh->FindElement( IDs[i] );
         if ( filter( elem ))
           aMap.insert( aMap.end(), elem );
@@ -789,7 +789,7 @@ SMESH_MeshEditor_i::RemoveElements(const SMESH::smIdType_array & IDsOfElements)
 
   list< smIdType > IdList;
 
-  for ( SMESH::smIdType i = 0; i < IDsOfElements.length(); i++ )
+  for ( CORBA::ULong i = 0; i < IDsOfElements.length(); i++ )
     IdList.push_back( IDsOfElements[i] );
 
   // Update Python script
@@ -817,7 +817,7 @@ CORBA::Boolean SMESH_MeshEditor_i::RemoveNodes(const SMESH::smIdType_array & IDs
   initData();
 
   list< smIdType > IdList;
-  for ( SMESH::smIdType i = 0; i < IDsOfNodes.length(); i++)
+  for ( CORBA::ULong i = 0; i < IDsOfNodes.length(); i++)
     IdList.push_back( IDsOfNodes[i] );
 
   // Update Python script
@@ -834,7 +834,7 @@ CORBA::Boolean SMESH_MeshEditor_i::RemoveNodes(const SMESH::smIdType_array & IDs
 
 //=============================================================================
 /*!
- *
+ * Remove orphan nodes
  */
 //=============================================================================
 
@@ -865,6 +865,58 @@ SMESH::smIdType SMESH_MeshEditor_i::RemoveOrphanNodes()
   return 0;
 }
 
+//=============================================================================
+/*!
+ * Remove a node and fill a hole appeared by changing surrounding faces
+ */
+//=============================================================================
+
+void SMESH_MeshEditor_i::RemoveNodeWithReconnection( SMESH::smIdType nodeID )
+{
+  SMESH_TRY;
+  initData();
+
+  const SMDS_MeshNode * node = getMeshDS()->FindNode( nodeID );
+  if ( ! node )
+    THROW_SALOME_CORBA_EXCEPTION( SMESH_Comment( "Invalid node ID ") << nodeID,
+                                  SALOME::BAD_PARAM);
+  if ( node->NbInverseElements( SMDSAbs_Volume ) > 0 )
+    THROW_SALOME_CORBA_EXCEPTION( "RemoveNodeWithReconnection() applies to 2D mesh only",
+                                  SALOME::BAD_PARAM);
+
+  if ( myIsPreviewMode ) // make preview data
+  {
+    // in a preview mesh, make edges linked to a node
+    TPreviewMesh& tmpMesh = *getPreviewMesh( SMDSAbs_Edge );
+    TIDSortedElemSet linkedNodes;
+    ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
+    SMDS_MeshNode *nodeCpy1 = tmpMesh.Copy( node );
+    for ( const SMDS_MeshElement* n : linkedNodes )
+    {
+      SMDS_MeshNode *nodeCpy2 = tmpMesh.Copy ( cast2Node( n ));
+      tmpMesh.GetMeshDS()->AddEdge( nodeCpy1, nodeCpy2 );
+    }
+    // copy surrounding faces
+    for ( SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator( SMDSAbs_Face ); fIt->more(); )
+      tmpMesh.Copy ( fIt->next() );
+    
+    // remove copied node
+    if ( nodeCpy1 )
+      getEditor().RemoveNodeWithReconnection( nodeCpy1 );
+  }
+  else
+  {
+    getEditor().RemoveNodeWithReconnection( node );
+
+    // Update Python script
+    TPythonDump() << this << ".RemoveNodeWithReconnection( " << nodeID << " )";
+
+    declareMeshModified( /*isReComputeSafe=*/ true );
+  }
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+}
+
 //=============================================================================
 /*!
  * Add a new node.
@@ -1567,6 +1619,121 @@ CORBA::Boolean SMESH_MeshEditor_i::DeleteDiag(SMESH::smIdType NodeID1,
   return 0;
 }
 
+//=============================================================================
+/*!
+ * \brief Split a diagonal of a quadrangle formed by two adjacent triangles
+ *        so that four new triangles appear in place of the two triangles
+ */
+//=============================================================================
+
+void SMESH_MeshEditor_i::AddNodeOnSegment(SMESH::smIdType nodeID1,
+                                          SMESH::smIdType nodeID2,
+                                          CORBA::Double   position)
+{
+  SMESH_TRY;
+  initData();
+
+  const SMDS_MeshNode * n1 = getMeshDS()->FindNode( nodeID1 );
+  const SMDS_MeshNode * n2 = getMeshDS()->FindNode( nodeID2 );
+  if ( !n1 )
+    THROW_SALOME_CORBA_EXCEPTION( SMESH_Comment( "Invalid node ID: ") << nodeID1,
+                                  SALOME::BAD_PARAM);
+  if ( !n2 )
+    THROW_SALOME_CORBA_EXCEPTION( SMESH_Comment( "Invalid node ID: ") << nodeID2,
+                                  SALOME::BAD_PARAM);
+
+  if ( myIsPreviewMode ) // make preview data
+  {
+    TPreviewMesh* tmpMesh = getPreviewMesh();
+    TIDSortedElemSet elemSet, avoidSet;
+    TopoDS_Shape shape;
+    while ( const SMDS_MeshElement* face = SMESH_MeshAlgos::FindFaceInSet( n1, n2,
+                                                                           elemSet, avoidSet ))
+    {
+      if ( avoidSet.empty() )
+      {
+        shape = getMeshDS()->IndexToShape( face->GetShapeID() );
+        if ( !shape.IsNull() )
+        {
+          tmpMesh->ShapeToMesh( TopoDS_Shape() );
+          tmpMesh->ShapeToMesh( shape );
+        }
+      }
+      SMDS_MeshElement* faceCopy = tmpMesh->Copy ( face );
+      avoidSet.insert( face );
+
+      if ( !shape.IsNull() )
+        tmpMesh->GetMeshDS()->SetMeshElementOnShape( faceCopy, shape );
+    }
+    n1 = tmpMesh->GetMeshDS()->FindNode( nodeID1 );
+    n2 = tmpMesh->GetMeshDS()->FindNode( nodeID2 );
+
+    if ( !shape.IsNull() )
+    {
+      tmpMesh->GetMeshDS()->SetMeshElementOnShape( n1, shape );
+      tmpMesh->GetMeshDS()->SetMeshElementOnShape( n2, shape );
+    }
+  }
+
+  getEditor().SplitEdge( n1, n2, position );
+
+  if ( !myIsPreviewMode )
+  {
+    // Update Python script
+    TPythonDump() << this << ".AddNodeOnSegment( "
+                  << nodeID1 << ", " << nodeID2 << ", " << position << " )";
+
+    declareMeshModified( /*isReComputeSafe=*/true );
+  }
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+}
+
+//=============================================================================
+/*!
+ * \brief Split a face into triangles by adding a new node onto the face
+ *        and connecting the new node with face nodes
+ */
+//=============================================================================
+
+void  SMESH_MeshEditor_i::AddNodeOnFace(SMESH::smIdType theFaceID,
+                                        CORBA::Double   theX,
+                                        CORBA::Double   theY,
+                                        CORBA::Double   theZ)
+{
+  SMESH_TRY;
+  initData();
+
+  const SMDS_MeshElement * face = getMeshDS()->FindElement( theFaceID );
+  if ( !face )
+    THROW_SALOME_CORBA_EXCEPTION( SMESH_Comment( "Invalid face ID: ") << theFaceID,
+                                  SALOME::BAD_PARAM);
+  if ( face->GetType() != SMDSAbs_Face )
+    THROW_SALOME_CORBA_EXCEPTION( "The element is not a face ", SALOME::BAD_PARAM );
+
+  if ( myIsPreviewMode ) // make preview data
+  {
+    TPreviewMesh* tmpMesh = getPreviewMesh();
+    face = tmpMesh->Copy ( face );
+  }
+
+  getEditor().SplitFace( face, theX, theY, theZ );
+
+  if ( !myIsPreviewMode )
+  {
+    // Update Python script
+    TPythonDump() << this << ".AddNodeOnFace( "
+                  << theFaceID << ", "
+                  << theX << ", "
+                  << theY << ", "
+                  << theZ << " )";
+
+    declareMeshModified( /*isReComputeSafe=*/true );
+  }
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+}
+
 //=============================================================================
 /*!
  *
@@ -1578,7 +1745,7 @@ CORBA::Boolean SMESH_MeshEditor_i::Reorient(const SMESH::smIdType_array & IDsOfE
   SMESH_TRY;
   initData();
 
-  for ( SMESH::smIdType i = 0; i < IDsOfElements.length(); i++ )
+  for ( CORBA::ULong i = 0; i < IDsOfElements.length(); i++ )
   {
     SMESH::smIdType index = IDsOfElements[i];
     const SMDS_MeshElement * elem = getMeshDS()->FindElement(index);
@@ -1696,7 +1863,8 @@ CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup,
   if ( dirVec.Magnitude() < std::numeric_limits< double >::min() )
     THROW_SALOME_CORBA_EXCEPTION("Zero size vector", SALOME::BAD_PARAM);
 
-  int nbReori = getEditor().Reorient2D( elements, dirVec, face );
+  TIDSortedElemSet refFaces = { face };
+  int nbReori = getEditor().Reorient2D( elements, dirVec, refFaces, /*allowNonManifold=*/true );
 
   if ( nbReori ) {
     declareMeshModified( /*isReComputeSafe=*/false );
@@ -1713,6 +1881,64 @@ CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup,
   return 0;
 }
 
+//=======================================================================
+//function : Reorient2DByNeighbours
+//purpose  : Reorient faces contained in a list of objectFaces
+//           equally to faces contained in a list of referenceFaces.
+//=======================================================================
+
+CORBA::Long
+SMESH_MeshEditor_i::Reorient2DByNeighbours(const SMESH::ListOfIDSources& theObjectFaces,
+                                           const SMESH::ListOfIDSources& theReferenceFaces)
+{
+  SMESH_TRY;
+  initData(/*deleteSearchers=*/false);
+
+  if ( theObjectFaces.length() == 0 )
+    return 0;
+
+  // get object faces
+  TIDSortedElemSet objFaces;
+  bool invalidObjFaces = false;
+  for ( CORBA::ULong i = 0; i < theObjectFaces.length(); ++i )
+  {
+    IDSource_Error err;
+    if ( !idSourceToSet( theObjectFaces[i], getMeshDS(), objFaces, SMDSAbs_Face,
+                         /*emptyIfIsMesh=*/1, &err ) &&
+         err == IDSource_INVALID )
+      invalidObjFaces = true;
+  }
+  if ( objFaces.empty() && invalidObjFaces )
+    THROW_SALOME_CORBA_EXCEPTION("No valid faces in given groups", SALOME::BAD_PARAM);
+
+  // get reference faces
+  TIDSortedElemSet refFaces;
+  for ( CORBA::ULong i = 0; i < theReferenceFaces.length(); ++i )
+  {
+    idSourceToSet( theReferenceFaces[i], getMeshDS(), refFaces, SMDSAbs_Face, /*emptyIfIsMesh=*/1 );
+  }
+  if ( refFaces.empty() && theReferenceFaces.length() > 0 )
+    THROW_SALOME_CORBA_EXCEPTION("Reference faces are invalid", SALOME::BAD_PARAM);
+
+
+  gp_Vec zeroVec( 0,0,0 );
+
+  // reorient
+  int nbReori = getEditor().Reorient2D( objFaces, zeroVec, refFaces, /*allowNonManifold=*/false );
+
+  if ( nbReori )
+    declareMeshModified( /*isReComputeSafe=*/false );
+
+  TPythonDump() << this << ".Reorient2DByNeighbours("
+                << theObjectFaces << ", "
+                << theReferenceFaces << ")";
+
+  return nbReori;
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return 0;
+}
+
 //=======================================================================
 //function : Reorient2DBy3D
 //purpose  : Reorient faces basing on orientation of adjacent volumes.
@@ -2006,8 +2232,8 @@ CORBA::Boolean SMESH_MeshEditor_i::SplitQuadObject (SMESH::SMESH_IDSource_ptr th
  */
 //=============================================================================
 
-CORBA::Long SMESH_MeshEditor_i::BestSplit (CORBA::Long                 IDOfQuad,
-                                           SMESH::NumericalFunctor_ptr Criterion)
+CORBA::Short SMESH_MeshEditor_i::BestSplit (SMESH::smIdType             IDOfQuad,
+                                            SMESH::NumericalFunctor_ptr Criterion)
 {
   SMESH_TRY;
   initData();
@@ -2252,7 +2478,7 @@ SMESH_MeshEditor_i::smooth(const SMESH::smIdType_array &          IDsOfElements,
   arrayToSet(IDsOfElements, aMesh, elements, SMDSAbs_Face);
 
   set<const SMDS_MeshNode*> fixedNodes;
-  for ( SMESH::smIdType i = 0; i < IDsOfFixedNodes.length(); i++) {
+  for ( CORBA::ULong i = 0; i < IDsOfFixedNodes.length(); i++) {
     SMESH::smIdType index = IDsOfFixedNodes[i];
     const SMDS_MeshNode * node = aMesh->FindNode(index);
     if ( node )
@@ -4342,7 +4568,7 @@ void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& theGrou
     if ( elemTypes->length() == 1 && elemTypes[0] == SMESH::NODE )
       continue;
     SMESH::smIdType_array_var elementsId = theElementsToKeep[i]->GetIDs();
-    for ( SMESH::smIdType j = 0; j < elementsId->length(); ++j )
+    for ( CORBA::ULong j = 0; j < elementsId->length(); ++j )
       idsToKeep.Add( elementsId[ j ]);
   }
 
@@ -4353,7 +4579,7 @@ void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& theGrou
     const SMESH::long_array& anElemsIDGroup = theGroupsOfElementsID[ i ];
     aListOfListOfElementsID.push_back( list< smIdType >() );
     list< smIdType >& aListOfElemsID = aListOfListOfElementsID.back();
-    for ( SMESH::smIdType j = 0; j < anElemsIDGroup.length(); j++ )
+    for ( CORBA::ULong j = 0; j < anElemsIDGroup.length(); j++ )
     {
       SMESH::smIdType id = anElemsIDGroup[ j ];
       if ( idsToKeep.Contains( id )) aListOfElemsID.push_front( id );
@@ -4430,7 +4656,6 @@ CORBA::Boolean SMESH_MeshEditor_i::MoveNode(SMESH::smIdType NodeID,
     // move copied node
     if ( nodeCpy1 )
       tmpMesh.GetMeshDS()->MoveNode(nodeCpy1, x, y, z);
-    // fill preview data
   }
   else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
     theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
@@ -6671,7 +6896,7 @@ SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theE
          duplication is not performed.
   This method is the first step of DoubleNodeElemGroupsInRegion.
   \param theElems - list of groups of elements (edges or faces) to be replicated
-  \param theNodesNot - list of groups of nodes not to replicated
+  \param theNodesNot - list of groups of nodes not to replicate
   \param theShape - shape to detect affected elements (element which geometric center
          located on or inside shape).
          The replicated nodes should be associated to affected elements.