]> SALOME platform Git repositories - modules/smesh.git/blobdiff - src/SMESH/SMESH_MeshEditor.cxx
Salome HOME
0020139: EDF 944 SMESH : Get 2D/3D element with X, Y, Z coordinates
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
index 31187db166df132c217b769b3557a2184aa96dad..1c6134612a95955b57b8e2b48201d7cb7a5d96fa 100644 (file)
@@ -79,6 +79,7 @@
 #include <map>
 #include <set>
 #include <numeric>
+#include <limits>
 
 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
 
@@ -2804,12 +2805,12 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
       return;
     }
 
-    issimple[iNode] = (listNewNodes.size()==nbSteps);
+    issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
 
     itNN[ iNode ] = listNewNodes.begin();
     prevNod[ iNode ] = node;
     nextNod[ iNode ] = listNewNodes.front();
-    if( !issimple[iNode] ) {
+    if( !elem->IsQuadratic() || !issimple[iNode] ) {
       if ( prevNod[ iNode ] != nextNod [ iNode ])
         iNotSameNode = iNode;
       else {
@@ -2822,8 +2823,8 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
 
   //cout<<"  nbSame = "<<nbSame<<endl;
   if ( nbSame == nbNodes || nbSame > 2) {
-    //MESSAGE( " Too many same nodes of element " << elem->GetID() );
-    INFOS( " Too many same nodes of element " << elem->GetID() );
+    MESSAGE( " Too many same nodes of element " << elem->GetID() );
+    //INFOS( " Too many same nodes of element " << elem->GetID() );
     return;
   }
 
@@ -5580,75 +5581,125 @@ bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& poi
   while ( nodeIt->more() )
     xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
 
+  int i, nbNodes = element->NbNodes();
+
   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
   {
-    // gravity center
-    gp_XYZ gc(0,0,0);
-    gc = accumulate( xyz.begin(), xyz.end(), gc );
-    gc /= element->NbNodes();
-
-    // compute face normal using gc
-    gp_Vec normal(0,0,0);
+    // compute face normal
+    gp_Vec faceNorm(0,0,0);
     xyz.push_back( xyz.front() );
-    for ( int i = 0; i < element->NbNodes(); ++i )
+    for ( i = 0; i < nbNodes; ++i )
     {
-      gp_Vec edge( xyz[i], xyz[i+1]);
-      gp_Vec n2gc( xyz[i], gc );
-      normal += edge ^ n2gc;
+      gp_Vec edge1( xyz[i+1], xyz[i]);
+      gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
+      faceNorm += edge1 ^ edge2;
+    }
+    double normSize = faceNorm.Magnitude();
+    if ( normSize <= tol )
+    {
+      // degenerated face: point is out if it is out of all face edges
+      for ( i = 0; i < nbNodes; ++i )
+      {
+        SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
+        SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
+        SMDS_MeshEdge edge( &n1, &n2 );
+        if ( !isOut( &edge, point, tol ))
+          return false;
+      }
+      return true;
     }
-    double faceDoubleArea = normal.Magnitude();
-    if ( faceDoubleArea <= numeric_limits<double>::min() )
-      return true; // invalid face
-    normal /= faceDoubleArea;
+    faceNorm /= normSize;
 
     // check if the point lays on face plane
     gp_Vec n2p( xyz[0], point );
-    if ( fabs( n2p * normal ) > tol )
+    if ( fabs( n2p * faceNorm ) > tol )
       return true; // not on face plane
 
-    // check if point is out of face boundary
-    int i, out = false;
-    for ( i = 0; !out && i < element->NbNodes(); ++i )
+    // check if point is out of face boundary:
+    // define it by closest transition of a ray point->infinity through face boundary
+    // on the face plane.
+    // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
+    // to find intersections of the ray with the boundary.
+    gp_Vec ray = n2p;
+    gp_Vec plnNorm = ray ^ faceNorm;
+    normSize = plnNorm.Magnitude();
+    if ( normSize <= tol ) return false; // point coincides with the first node
+    plnNorm /= normSize;
+    // for each node of the face, compute its signed distance to the plane
+    vector<double> dist( nbNodes + 1);
+    for ( i = 0; i < nbNodes; ++i )
     {
-      gp_Vec edge( xyz[i], xyz[i+1]);
-      gp_Vec n2p ( xyz[i], point );
-      gp_Vec cross = edge ^ n2p;
-      out = ( cross * normal < -tol );
-    }
-    if ( out && element->IsPoly() )
+      gp_Vec n2p( xyz[i], point );
+      dist[i] = n2p * plnNorm;
+    }
+    dist.back() = dist.front();
+    // find the closest intersection
+    int    iClosest = -1;
+    double rClosest, distClosest = 1e100;;
+    gp_Pnt pClosest;
+    for ( i = 0; i < nbNodes; ++i )
     {
-      // define point position by the closest edge
-      double minDist = numeric_limits<double>::max();
-      int iMinDist;
-      for ( i = 0; i < element->NbNodes(); ++i )
+      double r;
+      if ( fabs( dist[i]) < tol )
+        r = 0.;
+      else if ( fabs( dist[i+1]) < tol )
+        r = 1.;
+      else if ( dist[i] * dist[i+1] < 0 )
+        r = dist[i] / ( dist[i] - dist[i+1] );
+      else
+        continue; // no intersection
+      gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
+      gp_Vec p2int ( point, pInt);
+      if ( p2int * ray > -tol ) // right half-space
       {
-        gp_Vec edge( xyz[i], xyz[i+1]);
-        gp_Vec n1p ( xyz[i], point);
-        double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
-        if ( dist < minDist )
-          iMinDist = i;
+        double intDist = p2int.SquareMagnitude();
+        if ( intDist < distClosest )
+        {
+          iClosest = i;
+          rClosest = r;
+          pClosest = pInt;
+          distClosest = intDist;
+        }
       }
-      gp_Vec edge( xyz[iMinDist], xyz[iMinDist+1]);
-      gp_Vec n2p ( xyz[iMinDist], point );
-      gp_Vec cross = edge ^ n2p;
-      out = ( cross * normal < -tol );
     }
-    return out;
+    if ( iClosest < 0 )
+      return true; // no intesections - out
+
+    // analyse transition
+    gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
+    gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
+    gp_Vec p2int ( point, pClosest );
+    bool out = (edgeNorm * p2int) < -tol;
+    if ( rClosest > 0. && rClosest < 1. ) // not node intersection
+      return out;
+
+    // ray pass through a face node; analyze transition through an adjacent edge
+    gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
+    gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
+    gp_Vec edgeAdjacent( p1, p2 );
+    gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
+    bool out2 = (edgeNorm2 * p2int) < -tol;
+
+    bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
+    return covexCorner ? (out || out2) : (out && out2);
   }
   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
   {
-    for ( int i = 1; i < element->NbNodes(); ++i )
+    // point is out of edge if it is NOT ON any straight part of edge
+    // (we consider quadratic edge as being composed of two straight parts)
+    for ( i = 1; i < nbNodes; ++i )
     {
       gp_Vec edge( xyz[i-1], xyz[i]);
       gp_Vec n1p ( xyz[i-1], point);
       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
       if ( dist > tol )
-        return true;
+        continue;
       gp_Vec n2p( xyz[i], point );
       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
-        return true;
+        continue;
+      return false; // point is ON this part
     }
-    return false;
+    return true;
   }
   // Node or 0D element -------------------------------------------------------------------------
   {
@@ -7644,6 +7695,9 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
         case 4:
           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
           break;
+        case 5:
+          NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
+          break;
         case 6:
           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
           break;
@@ -7688,7 +7742,6 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
         SMESH_subMesh* sm = smIt->next();
         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
           aHelper.SetSubShape( sm->GetSubShape() );
-          if ( !theForce3d) aHelper.SetCheckNodePosition(true);
           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
         }
       }
@@ -7769,6 +7822,10 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
                                       aNds[3], id, theForce3d );
         break;
+      case 5:
+        NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
+                                      aNds[3], aNds[4], id, theForce3d);
+        break;
       case 6:
         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
                                       aNds[3], aNds[4], aNds[5], id, theForce3d);
@@ -8724,7 +8781,7 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
         theNodeNodeMap[ aCurrNode ] = aNewNode;
         myLastCreatedNodes.Append( aNewNode );
       }
-      isDuplicate |= (aCurrNode == aNewNode);
+      isDuplicate |= (aCurrNode != aNewNode);
       newNodes[ ind++ ] = aNewNode;
     }
     if ( !isDuplicate )
@@ -8762,6 +8819,95 @@ static bool isInside(const SMDS_MeshElement* theElem,
   return (aState == TopAbs_IN || aState == TopAbs_ON );
 }
 
+/*!
+  \brief Creates a hole in a mesh by doubling the nodes of some particular elements
+  \param theNodes - identifiers of nodes to be doubled
+  \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
+         nodes. If list of element identifiers is empty then nodes are doubled but 
+         they not assigned to elements
+  \return TRUE if operation has been completed successfully, FALSE otherwise
+*/
+bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
+                                    const std::list< int >& theListOfModifiedElems )
+{
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
+  if ( theListOfNodes.size() == 0 )
+    return false;
+
+  SMESHDS_Mesh* aMeshDS = GetMeshDS();
+  if ( !aMeshDS )
+    return false;
+
+  // iterate through nodes and duplicate them
+
+  std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
+
+  std::list< int >::const_iterator aNodeIter;
+  for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
+  {
+    int aCurr = *aNodeIter;
+    SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
+    if ( !aNode )
+      continue;
+
+    // duplicate node
+
+    const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
+    if ( aNewNode )
+    {
+      anOldNodeToNewNode[ aNode ] = aNewNode;
+      myLastCreatedNodes.Append( aNewNode );
+    }
+  }
+
+  // Create map of new nodes for modified elements
+
+  std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
+
+  std::list< int >::const_iterator anElemIter;
+  for ( anElemIter = theListOfModifiedElems.begin(); 
+        anElemIter != theListOfModifiedElems.end(); ++anElemIter )
+  {
+    int aCurr = *anElemIter;
+    SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
+    if ( !anElem )
+      continue;
+
+    vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
+
+    SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
+    int ind = 0;
+    while ( anIter->more() ) 
+    { 
+      SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
+      if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
+      {
+        const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
+        aNodeArr[ ind++ ] = aNewNode;
+      }
+      else
+        aNodeArr[ ind++ ] = aCurrNode;
+    }
+    anElemToNodes[ anElem ] = aNodeArr;
+  }
+
+  // Change nodes of elements  
+
+  std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
+    anElemToNodesIter = anElemToNodes.begin();
+  for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
+  {
+    const SMDS_MeshElement* anElem = anElemToNodesIter->first;
+    vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
+    if ( anElem )
+      aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
+  }
+
+  return true;
+}
+
 /*!
   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
   \param theElems - group of of elements (edges or faces) to be replicated
@@ -8829,7 +8975,9 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D()
   {
     const SMDS_MeshVolume* volume = vIt->next();
     SMDS_VolumeTool vTool( volume );
-    bool isPoly = volume->IsPoly();
+    vTool.SetExternalNormal();
+    const bool isPoly = volume->IsPoly();
+    const bool isQuad = volume->IsQuadratic();
     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
     {
       if (!vTool.IsFreeFace(iface))
@@ -8837,11 +8985,11 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D()
       vector<const SMDS_MeshNode *> nodes;
       int nbFaceNodes = vTool.NbFaceNodes(iface);
       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
-      if (vTool.IsFaceExternal(iface))
-        for (int inode = 0; inode < nbFaceNodes; inode++)
-          nodes.push_back(faceNodes[inode]);
-      else
-        for (int inode = nbFaceNodes - 1; inode >= 0; inode--)
+      int inode = 0;
+      for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
+        nodes.push_back(faceNodes[inode]);
+      if (isQuad)
+        for ( inode = 1; inode < nbFaceNodes; inode += 2)
           nodes.push_back(faceNodes[inode]);
 
       // add new face based on volume nodes