Salome HOME
Fix for the issue "21356: EDF 1705 SMESH: Extrusion along a path using a mesh w/o...
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
index db3d48077d56a5d71a5d1b9d286e4587a2cf623e..ffe2ce9a6cabd3c23c9176277371136d4e924f45 100644 (file)
 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
-//
 
-//  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
+// SMESH SMESH : idl implementation based on 'SMESH' unit's classes
 // File      : SMESH_MeshEditor.cxx
 // Created   : Mon Apr 12 16:10:22 2004
 // Author    : Edward AGAPOV (eap)
-//
+
 #define CHRONODEF
 #include "SMESH_MeshEditor.hxx"
 
 #include "SMESH_OctreeNode.hxx"
 #include "SMESH_subMesh.hxx"
 
+#include <Basics_OCCTVersion.hxx>
+
 #include "utilities.h"
 
 #include <BRepAdaptor_Surface.hxx>
+#include <BRepBuilderAPI_MakeEdge.hxx>
 #include <BRepClass3d_SolidClassifier.hxx>
 #include <BRep_Tool.hxx>
 #include <ElCLib.hxx>
@@ -455,6 +457,25 @@ static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
   aNodes[5] = nd2;
 }
 
+//=======================================================================
+//function : edgeConnectivity
+//purpose  : auxilary 
+//           return number of the edges connected with the theNode.
+//           if theEdges has connections with the other type of the
+//           elements, return -1 
+//=======================================================================
+static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
+{
+  SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
+  int nb=0;
+  while(elemIt->more()) {
+    elemIt->next();
+    nb++;
+  }
+  return nb;
+}
+
+
 //=======================================================================
 //function : GetNodesFromTwoTria
 //purpose  : auxilary
@@ -1615,6 +1636,7 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
       helper.SetIsQuadratic( false );
     }
     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
+    helper.SetElementsOnShape( true );
     if ( splitMethod._baryNode )
     {
       // make a node at barycenter
@@ -1642,7 +1664,6 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
     }
 
     // make tetras
-    helper.SetElementsOnShape( true );
     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
     const int* tetConn = splitMethod._connectivity;
     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
@@ -1670,6 +1691,12 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
         helper.SetElementsOnShape( false );
         vector< const SMDS_MeshElement* > triangles;
 
+        // find submesh to add new triangles in
+        if ( !fSubMesh || !fSubMesh->Contains( face ))
+        {
+          int shapeID = FindShape( face );
+          fSubMesh = GetMeshDS()->MeshElements( shapeID );
+        }
         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
         if ( iF_n != splitMethod._faceBaryNode.end() )
         {
@@ -1681,6 +1708,9 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
             if ( !volTool.IsFaceExternal( iF ))
               swap( n2, n3 );
             triangles.push_back( helper.AddFace( n1,n2,n3 ));
+
+            if ( fSubMesh && n3->getshapeId() < 1 )
+              fSubMesh->AddNode( n3 );
           }
         }
         else
@@ -1719,12 +1749,6 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
                                                  volNodes[ facet->_n3 ]));
           }
         }
-        // find submesh to add new triangles in
-        if ( !fSubMesh || !fSubMesh->Contains( face ))
-        {
-          int shapeID = FindShape( face );
-          fSubMesh = GetMeshDS()->MeshElements( shapeID );
-        }
         for ( int i = 0; i < triangles.size(); ++i )
         {
           if ( !triangles[i] ) continue;
@@ -2826,8 +2850,13 @@ static bool getClosestUV (Extrema_GenExtPS& projector,
   if ( projector.IsDone() ) {
     double u, v, minVal = DBL_MAX;
     for ( int i = projector.NbExt(); i > 0; i-- )
+#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
+      if ( projector.SquareDistance( i ) < minVal ) {
+        minVal = projector.SquareDistance( i );
+#else
       if ( projector.Value( i ) < minVal ) {
         minVal = projector.Value( i );
+#endif
         projector.Point( i ).Parameter( u, v );
       }
     result.SetCoord( u, v );
@@ -3088,35 +3117,27 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
     // fix nodes on mesh boundary
 
     if ( checkBoundaryNodes ) {
-      map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
-      map< NLink, int >::iterator link_nb;
+      map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
+      map< SMESH_TLink, int >::iterator link_nb;
       // put all elements links to linkNbMap
       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
         const SMDS_MeshElement* elem = (*elemIt);
-        int nbn =  elem->NbNodes();
-        if(elem->IsQuadratic())
-          nbn = nbn/2;
+        int nbn =  elem->NbCornerNodes();
         // loop on elem links: insert them in linkNbMap
-        const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
         for ( int iN = 0; iN < nbn; ++iN ) {
-          curNode = elem->GetNode( iN );
-          NLink link;
-          if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
-          else                      link = make_pair( prevNode , curNode );
-          prevNode = curNode;
-          link_nb = linkNbMap.find( link );
-          if ( link_nb == linkNbMap.end() )
-            linkNbMap.insert( make_pair ( link, 1 ));
-          else
-            link_nb->second++;
+          const SMDS_MeshNode* n1 = elem->GetNode( iN );
+          const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
+          SMESH_TLink link( n1, n2 );
+          link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
+          link_nb->second++;
         }
       }
       // remove nodes that are in links encountered only once from setMovableNodes
       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
         if ( link_nb->second == 1 ) {
-          setMovableNodes.erase( link_nb->first.first );
-          setMovableNodes.erase( link_nb->first.second );
+          setMovableNodes.erase( link_nb->first.node1() );
+          setMovableNodes.erase( link_nb->first.node2() );
         }
       }
     }
@@ -4120,7 +4141,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                 if ( f )
                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
                 else
-                  myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
+                  AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
               }
             }
 
@@ -4686,8 +4707,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
     }
     //Extrusion_Error err =
     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
-  }
-  else if( aS.ShapeType() == TopAbs_WIRE ) {
+  } else if( aS.ShapeType() == TopAbs_WIRE ) {
     list< SMESH_subMesh* > LSM;
     TopTools_SequenceOfShape Edges;
     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
@@ -4700,6 +4720,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
     int startNid = theN1->GetID();
     TColStd_MapOfInteger UsedNums;
+    
     int NbEdges = Edges.Length();
     int i = 1;
     for(; i<=NbEdges; i++) {
@@ -4833,8 +4854,127 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
   list<SMESH_MeshEditor_PathPoint> fullList;
 
   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
-  // Sub shape for the Pattern must be an Edge or Wire
-  if( aS.ShapeType() == TopAbs_EDGE ) {
+
+  if( aS == SMESH_Mesh::PseudoShape() ) {
+    //Mesh without shape
+    const SMDS_MeshNode* currentNode = NULL;
+    const SMDS_MeshNode* prevNode = theN1;
+    std::vector<const SMDS_MeshNode*> aNodesList;
+    aNodesList.push_back(theN1);
+    int nbEdges = 0, conn=0;
+    const SMDS_MeshElement* prevElem = NULL;
+    const SMDS_MeshElement* currentElem = NULL;
+    int totalNbEdges = theTrack->NbEdges();
+    SMDS_ElemIteratorPtr nIt;
+    bool isClosed = false;
+
+    //check start node
+    if( !theTrack->GetMeshDS()->Contains(theN1) ) {
+      return EXTR_BAD_STARTING_NODE;
+    }
+    
+    conn = nbEdgeConnectivity(theN1);
+    if(conn > 2)
+      return EXTR_PATH_NOT_EDGE;
+
+    aItE = theN1->GetInverseElementIterator();
+    prevElem = aItE->next();
+    currentElem = prevElem;
+    //Get all nodes
+    if(totalNbEdges == 1 ) {
+      nIt = currentElem->nodesIterator();
+      currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
+      if(currentNode == prevNode)
+       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
+      aNodesList.push_back(currentNode);
+    } else { 
+      nIt = currentElem->nodesIterator();
+      while( nIt->more() ) {
+       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
+       if(currentNode == prevNode)
+         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
+       aNodesList.push_back(currentNode);
+       
+       //case of the closed mesh
+       if(currentNode == theN1) {
+         nbEdges++;
+         isClosed = true;
+         break;
+       }
+
+       conn = nbEdgeConnectivity(currentNode);
+       if(conn > 2) {
+         return EXTR_PATH_NOT_EDGE;    
+       }else if( conn == 1 && nbEdges > 0 ) {
+         //End of the path
+         nbEdges++;
+         break;
+       }else {
+         prevNode = currentNode;
+         aItE = currentNode->GetInverseElementIterator();
+         currentElem = aItE->next();
+         if( currentElem  == prevElem)
+           currentElem = aItE->next();
+         nIt = currentElem->nodesIterator();
+         prevElem = currentElem;
+         nbEdges++;
+       }
+      }
+    } 
+    
+    if(nbEdges != totalNbEdges)
+      return EXTR_PATH_NOT_EDGE;
+
+    TopTools_SequenceOfShape Edges;
+    double x1,x2,y1,y2,z1,z2;
+    list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
+    int startNid = theN1->GetID();
+    for(int i = 1; i < aNodesList.size(); i++) {
+      x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
+      y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
+      z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
+      TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));  
+      list<SMESH_MeshEditor_PathPoint> LPP;
+      aPrms.clear();
+      MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
+      LLPPs.push_back(LPP);
+      if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
+      else startNid = aNodesList[i-1]->GetID();
+
+    }
+
+    list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
+    list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
+    list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
+    for(; itPP!=firstList.end(); itPP++) {
+      fullList.push_back( *itPP );
+    }
+
+    SMESH_MeshEditor_PathPoint PP1 = fullList.back();
+    SMESH_MeshEditor_PathPoint PP2;
+    fullList.pop_back();
+    itLLPP++;
+    for(; itLLPP!=LLPPs.end(); itLLPP++) {
+      list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
+      itPP = currList.begin();
+      PP2 = currList.front();
+      gp_Dir D1 = PP1.Tangent();
+      gp_Dir D2 = PP2.Tangent();
+      gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
+                           (D1.Z()+D2.Z())/2 ) );
+      PP1.SetTangent(Dnew);
+      fullList.push_back(PP1);
+      itPP++;
+      for(; itPP!=currList.end(); itPP++) {
+        fullList.push_back( *itPP );
+      }
+      PP1 = fullList.back();
+      fullList.pop_back();
+    }
+    fullList.push_back(PP1);
+    
+  } // Sub shape for the Pattern must be an Edge or Wire
+  else if( aS.ShapeType() == TopAbs_EDGE ) {
     aTrackEdge = TopoDS::Edge( aS );
     // the Edge must not be degenerated
     if ( BRep_Tool::Degenerated( aTrackEdge ) )
@@ -7048,7 +7188,7 @@ SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
 
 //=======================================================================
 /*!
- * \brief Return SMESH_ElementSearcher
+ * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
  */
 //=======================================================================
 
@@ -10790,7 +10930,11 @@ namespace {
       _extremum.Perform(aPnt);
       if ( _extremum.IsDone() )
         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
+#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
+          _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
+#else
           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
+#endif
     }
     TopAbs_State State() const
     {
@@ -11578,13 +11722,12 @@ namespace
  *  \param group - a group to store created boundary elements in
  *  \param targetMesh - a mesh to store created boundary elements in
  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
- *  \param toCopyExistingBondary - if true, not only new but also pre-existing
+ *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
  *                                boundary elements will be copied into the targetMesh
  *  \param toAddExistingBondary - if true, not only new but also pre-existing
  *                                boundary elements will be added into the new group
  *  \param aroundElements - if true, elements will be created on boundary of given
- *                          elements else, on boundary of the whole mesh. This
- *                          option works for 2D elements only.
+ *                          elements else, on boundary of the whole mesh.
  * \return nb of added boundary elements
  */
 //================================================================================
@@ -11594,7 +11737,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
                                        SMESH_Group*            group/*=0*/,
                                        SMESH_Mesh*             targetMesh/*=0*/,
                                        bool                    toCopyElements/*=false*/,
-                                       bool                    toCopyExistingBondary/*=false*/,
+                                       bool                    toCopyExistingBoundary/*=false*/,
                                        bool                    toAddExistingBondary/*= false*/,
                                        bool                    aroundElements/*= false*/)
 {
@@ -11604,11 +11747,8 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
     throw SALOME_Exception(LOCALIZED("wrong element type"));
 
-  if ( aroundElements && elemType == SMDSAbs_Volume )
-    throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
-
   if ( !targetMesh )
-    toCopyElements = toCopyExistingBondary = false;
+    toCopyElements = toCopyExistingBoundary = false;
 
   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
@@ -11646,11 +11786,13 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
     {
       vTool.SetExternalNormal();
+      const SMDS_MeshElement* otherVol = 0;
       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
       {
-        if (!vTool.IsFreeFace(iface))
+        if ( !vTool.IsFreeFace(iface, &otherVol) &&
+             ( !aroundElements || elements.count( otherVol )))
           continue;
-        int nbFaceNodes = vTool.NbFaceNodes(iface);
+        const int nbFaceNodes = vTool.NbFaceNodes(iface);
         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
         if ( missType == SMDSAbs_Edge ) // boundary edges
         {
@@ -11679,6 +11821,21 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
             presentBndElems.push_back( f );
           else
             missingBndElems.push_back( nodes );
+
+          if ( targetMesh != myMesh )
+          {
+            // add 1D elements on face boundary to be added to a new mesh
+            const SMDS_MeshElement* edge;
+            for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
+            {
+              if ( iQuad )
+                edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
+              else
+                edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
+              if ( edge && avoidSet.insert( edge ).second )
+                presentBndElems.push_back( edge );
+            }
+          }
         }
       }
     }
@@ -11709,7 +11866,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
     // ---------------------------------
     if ( targetMesh != myMesh )
       // instead of making a map of nodes in this mesh and targetMesh,
-      // we create nodes with same IDs. We can renumber them later, if needed
+      // we create nodes with same IDs.
       for ( int i = 0; i < missingBndElems.size(); ++i )
       {
         TConnectivity& srcNodes = missingBndElems[i];
@@ -11738,14 +11895,14 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
     // ----------------------------------
     // 3. Copy present boundary elements
     // ----------------------------------
-    if ( toCopyExistingBondary )
+    if ( toCopyExistingBoundary )
       for ( int i = 0 ; i < presentBndElems.size(); ++i )
       {
         const SMDS_MeshElement* e = presentBndElems[i];
         TConnectivity nodes( e->NbNodes() );
         for ( inode = 0; inode < nodes.size(); ++inode )
           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
-        presentEditor->AddElement(nodes, missType, e->IsPoly());
+        presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
       }
     else // store present elements to add them to a group
       for ( int i = 0 ; i < presentBndElems.size(); ++i )