]> SALOME platform Git repositories - modules/smesh.git/blobdiff - src/SMESHUtils/SMESH_MeshAlgos.cxx
Salome HOME
54499: SALOME crash at mesh evaluation
[modules/smesh.git] / src / SMESHUtils / SMESH_MeshAlgos.cxx
index 1de6ba82abaa93a2a382ff47f04b82e043308354..019f57762e2202d03910ca782171f1cb672dad20 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "SMESH_MeshAlgos.hxx"
 
+#include "ObjectPool.hxx"
 #include "SMDS_FaceOfNodes.hxx"
 #include "SMDS_LinearEdge.hxx"
 #include "SMDS_Mesh.hxx"
@@ -44,6 +45,7 @@
 #include <IntAna_Quadric.hxx>
 #include <gp_Lin.hxx>
 #include <gp_Pln.hxx>
+#include <NCollection_DataMap.hxx>
 
 #include <limits>
 #include <numeric>
@@ -69,7 +71,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
 
     TIDSortedNodeSet nodes;
     if ( theMesh ) {
-      SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
+      SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
       while ( nIt->more() )
         nodes.insert( nodes.end(), nIt->next() );
     }
@@ -114,14 +116,15 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
     if ( !dist2Nodes.empty() )
       return dist2Nodes.begin()->second;
-    std::list<const SMDS_MeshNode*> nodes;
+
+    std::vector<const SMDS_MeshNode*> nodes;
     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
 
     double minSqDist = DBL_MAX;
     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
     {
       // sort leafs by their distance from thePnt
-      typedef std::map< double, SMESH_OctreeNode* > TDistTreeMap;
+      typedef std::multimap< double, SMESH_OctreeNode* > TDistTreeMap;
       TDistTreeMap treeMap;
       std::list< SMESH_OctreeNode* > treeList;
       std::list< SMESH_OctreeNode* >::iterator trIt;
@@ -143,10 +146,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
         {
           const Bnd_B3d& box = *tree->getBox();
           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
-          std::pair<TDistTreeMap::iterator,bool> it_in =
-            treeMap.insert( std::make_pair( sqDist, tree ));
-          if ( !it_in.second ) // not unique distance to box center
-            treeMap.insert( it_in.first, std::make_pair( sqDist + 1e-13*treeMap.size(), tree ));
+          treeMap.insert( std::make_pair( sqDist, tree ));
         }
       }
       // find distance after which there is no sense to check tree's
@@ -163,17 +163,17 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
         if ( sqDist_tree->first > sqLimit )
           break;
         SMESH_OctreeNode* tree = sqDist_tree->second;
-        tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
+        tree->AllNodesAround( tree->GetNodeIterator()->next(), &nodes );
       }
     }
     // find closest among nodes
     minSqDist = DBL_MAX;
     const SMDS_MeshNode* closestNode = 0;
-    std::list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
-    for ( ; nIt != nodes.end(); ++nIt ) {
-      double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
+    for ( size_t i = 0; i < nodes.size(); ++i )
+    {
+      double sqDist = thePnt.SquareDistance( SMESH_NodeXYZ( nodes[ i ]));
       if ( minSqDist > sqDist ) {
-        closestNode = *nIt;
+        closestNode = nodes[ i ];
         minSqDist = sqDist;
       }
     }
@@ -182,7 +182,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
 
   //---------------------------------------------------------------------
   /*!
-   * \brief Finds nodes located within a tolerance near a point 
+   * \brief Finds nodes located within a tolerance near a point
    */
   int FindNearPoint(const gp_Pnt&                        point,
                     const double                         tolerance,
@@ -227,7 +227,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
   {
   public:
 
-    typedef boost::container::flat_set< const SMDS_MeshElement* > TElemSeq;
+    typedef boost::container::flat_set< const SMDS_MeshElement*, TIDCompare > TElemSeq;
 
     ElementBndBoxTree(const SMDS_Mesh&     mesh,
                       SMDSAbs_ElementType  elemType,
@@ -258,7 +258,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
     //!< allocator of ElementBox's and SMESH_TreeLimit
     struct LimitAndPool : public SMESH_TreeLimit
     {
-      TElementBoxPool            _elBoPool;
+      TElementBoxPool _elBoPool;
       LimitAndPool():SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ) {}
     };
     LimitAndPool* getLimitAndPool() const
@@ -1244,11 +1244,11 @@ gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt&            point,
 
   ElementBndBoxTree*& ebbTree = _ebbTree[ _elementType ];
   if ( !ebbTree )
-    ebbTree = new ElementBndBoxTree( *_mesh, _elementType );
+    ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt );
 
   gp_XYZ p = point.XYZ();
   ElementBndBoxTree* ebbLeaf = ebbTree->getLeafAtPoint( p );
-  const Bnd_B3d* box = ebbLeaf->getBox();
+  const Bnd_B3d* box = ebbLeaf ? ebbLeaf->getBox() : ebbTree->getBox();
   double radius = ( box->CornerMax() - box->CornerMin() ).Modulus();
 
   ElementBndBoxTree::TElemSeq elems;
@@ -1294,7 +1294,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
 
   std::vector< SMESH_TNodeXYZ > xyz; xyz.reserve( element->NbNodes()+1 );
 
-  SMDS_ElemIteratorPtr nodeIt = element->interlacedNodesElemIterator();
+  SMDS_NodeIteratorPtr nodeIt = element->interlacedNodesIterator();
   for ( int i = 0; nodeIt->more(); ++i )
     xyz.push_back( SMESH_TNodeXYZ( nodeIt->next() ));
 
@@ -1477,9 +1477,9 @@ namespace
 
   //================================================================================
   /*!
-   * \brief Return of a point relative to a segment
+   * \brief Return position of a point relative to a segment
    *  \param point2D      - the point to analyze position of
-   *  \param xyVec        - end points of segments
+   *  \param segEnds      - end points of segments
    *  \param index0       - 0-based index of the first point of segment
    *  \param posToFindOut - flags of positions to detect
    *  \retval PointPos - point position
@@ -1530,11 +1530,11 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshElement* elem,
   switch ( elem->GetType() )
   {
   case SMDSAbs_Volume:
-    return GetDistance( dynamic_cast<const SMDS_MeshVolume*>( elem ), point, closestPnt );
+    return GetDistance( static_cast<const SMDS_MeshVolume*>( elem ), point, closestPnt );
   case SMDSAbs_Face:
-    return GetDistance( dynamic_cast<const SMDS_MeshFace*>( elem ), point, closestPnt );
+    return GetDistance( static_cast<const SMDS_MeshFace*>( elem ), point, closestPnt );
   case SMDSAbs_Edge:
-    return GetDistance( dynamic_cast<const SMDS_MeshEdge*>( elem ), point, closestPnt );
+    return GetDistance( static_cast<const SMDS_MeshEdge*>( elem ), point, closestPnt );
   case SMDSAbs_Node:
     if ( closestPnt ) *closestPnt = SMESH_TNodeXYZ( elem );
     return point.Distance( SMESH_TNodeXYZ( elem ));
@@ -1608,46 +1608,63 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
   }
 
   // compute distance
-  PointPos pos = *pntPosSet.begin();
-  switch ( pos._name )
-  {
-  case POS_LEFT:
-  {
-    // point is most close to an edge
-    gp_Vec edge( xyz[ pos._index ], xyz[ pos._index+1 ]);
-    gp_Vec n1p ( xyz[ pos._index ], point  );
-    double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
-    // projection of the point on the edge
-    gp_XYZ proj = xyz[ pos._index ] + u * edge.XYZ();
-    if ( closestPnt ) *closestPnt = proj;
-    return point.Distance( proj );
-  }
-  case POS_RIGHT:
+
+  double minDist2 = Precision::Infinite();
+  for ( std::set< PointPos >::iterator posIt = pntPosSet.begin(); posIt != pntPosSet.end(); ++posIt)
   {
-    // point is inside the face
-    double distToFacePlane = Abs( tmpPnt.Y() );
-    if ( closestPnt )
+    PointPos pos = *posIt;
+    if ( pos._name != pntPosSet.begin()->_name )
+      break;
+    switch ( pos._name )
     {
-      if ( distToFacePlane < std::numeric_limits<double>::min() ) {
-        *closestPnt = point.XYZ();
+    case POS_LEFT: // point is most close to an edge
+    {
+      gp_Vec edge( xyz[ pos._index ], xyz[ pos._index+1 ]);
+      gp_Vec n1p ( xyz[ pos._index ], point  );
+      double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
+      // projection of the point on the edge
+      gp_XYZ proj = xyz[ pos._index ] + u * edge.XYZ();
+      double dist2 = point.SquareDistance( proj );
+      if ( dist2 < minDist2 )
+      {
+        if ( closestPnt ) *closestPnt = proj;
+        minDist2 = dist2;
       }
-      else {
-        tmpPnt.SetY( 0 );
-        trsf.Inverted().Transforms( tmpPnt );
-        *closestPnt = tmpPnt;
+      break;
+    }
+
+    case POS_RIGHT: // point is inside the face
+    {
+      double distToFacePlane = Abs( tmpPnt.Y() );
+      if ( closestPnt )
+      {
+        if ( distToFacePlane < std::numeric_limits<double>::min() ) {
+          *closestPnt = point.XYZ();
+        }
+        else {
+          tmpPnt.SetY( 0 );
+          trsf.Inverted().Transforms( tmpPnt );
+          *closestPnt = tmpPnt;
+        }
       }
+      return distToFacePlane;
+    }
+
+    case POS_VERTEX: // point is most close to a node
+    {
+      double dist2 = point.SquareDistance( xyz[ pos._index ]);
+      if ( dist2 < minDist2 )
+      {
+        if ( closestPnt ) *closestPnt = xyz[ pos._index ];
+        minDist2 = dist2;
+      }
+      break;
+    }
+    default:;
+      return badDistance;
     }
-    return distToFacePlane;
-  }
-  case POS_VERTEX:
-  {
-    // point is most close to a node
-    gp_Vec distVec( point, xyz[ pos._index ]);
-    return distVec.Magnitude();
-  }
-  default:;
   }
-  return badDistance;
+  return Sqrt( minDist2 );
 }
 
 //=======================================================================
@@ -1666,9 +1683,8 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg,
   int i = 0, nbNodes = seg->NbNodes();
 
   std::vector< SMESH_TNodeXYZ > xyz( nbNodes );
-  SMDS_ElemIteratorPtr nodeIt = seg->interlacedNodesElemIterator();
-  while ( nodeIt->more() )
-    xyz[ i++ ].Set( nodeIt->next() );
+  for ( SMDS_NodeIteratorPtr nodeIt = seg->interlacedNodesIterator(); nodeIt->more(); i++ )
+    xyz[ i ].Set( nodeIt->next() );
 
   for ( i = 1; i < nbNodes; ++i )
   {
@@ -1792,7 +1808,7 @@ void SMESH_MeshAlgos::GetBarycentricCoords( const gp_XY& p,
   const double t11 = T22, t12 = -T12, t21 = -T21, t22 = T11;
   // vector
   const double r11 = p.X()-t2.X(), r12 = p.Y()-t2.Y();
-  // barycentric coordinates: mutiply matrix by vector
+  // barycentric coordinates: multiply matrix by vector
   bc0 = (t11 * r11 + t12 * r12)/Tdet;
   bc1 = (t21 * r11 + t22 * r12)/Tdet;
 }
@@ -1838,7 +1854,7 @@ SMESH_MeshAlgos::FindFaceInSet(const SMDS_MeshNode*    n1,
     if ( !face && elem->IsQuadratic())
     {
       // analysis for quadratic elements using all nodes
-      SMDS_ElemIteratorPtr anIter = elem->interlacedNodesElemIterator();
+      SMDS_NodeIteratorPtr anIter = elem->interlacedNodesIterator();
       const SMDS_MeshNode* prevN = static_cast<const SMDS_MeshNode*>( anIter->next() );
       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
       {
@@ -1860,6 +1876,222 @@ SMESH_MeshAlgos::FindFaceInSet(const SMDS_MeshNode*    n1,
   return face;
 }
 
+//================================================================================
+/*!
+ * Return sharp edges of faces and non-manifold ones. Optionally adds existing edges.
+ */
+//================================================================================
+
+std::vector< SMESH_MeshAlgos::Edge >
+SMESH_MeshAlgos::FindSharpEdges( SMDS_Mesh* theMesh,
+                                 double     theAngle,
+                                 bool       theAddExisting )
+{
+  std::vector< Edge > resultEdges;
+  if ( !theMesh ) return resultEdges;
+
+  typedef std::pair< bool, const SMDS_MeshNode* >                            TIsSharpAndMedium;
+  typedef NCollection_DataMap< SMESH_TLink, TIsSharpAndMedium, SMESH_TLink > TLinkSharpMap;
+
+  TLinkSharpMap linkIsSharp( theMesh->NbFaces() );
+  TIsSharpAndMedium sharpMedium( true, 0 );
+  bool                 & isSharp = sharpMedium.first;
+  const SMDS_MeshNode* & nMedium = sharpMedium.second;
+
+  if ( theAddExisting )
+  {
+    for ( SMDS_EdgeIteratorPtr edgeIt = theMesh->edgesIterator(); edgeIt->more(); )
+    {
+      const SMDS_MeshElement* edge = edgeIt->next();
+      nMedium = ( edge->IsQuadratic() ) ? edge->GetNode(2) : 0;
+      linkIsSharp.Bind( SMESH_TLink( edge->GetNode(0), edge->GetNode(1)), sharpMedium );
+    }
+  }
+
+  // check angles between face normals
+
+  const double angleCos = Cos( theAngle * M_PI / 180. ), angleCos2 = angleCos * angleCos;
+  gp_XYZ norm1, norm2;
+  std::vector< const SMDS_MeshNode* > faceNodes, linkNodes(2);
+  std::vector<const SMDS_MeshElement *> linkFaces;
+
+  int nbSharp = linkIsSharp.Extent();
+  for ( SMDS_FaceIteratorPtr faceIt = theMesh->facesIterator(); faceIt->more(); )
+  {
+    const SMDS_MeshElement* face = faceIt->next();
+    size_t             nbCorners = face->NbCornerNodes();
+
+    faceNodes.assign( face->begin_nodes(), face->end_nodes() );
+    if ( faceNodes.size() == nbCorners )
+      faceNodes.resize( nbCorners * 2, 0 );
+
+    const SMDS_MeshNode* nPrev = faceNodes[ nbCorners-1 ];
+    for ( size_t i = 0; i < nbCorners; ++i )
+    {
+      SMESH_TLink link( nPrev, faceNodes[i] );
+      if ( !linkIsSharp.IsBound( link ))
+      {
+        linkNodes[0] = link.node1();
+        linkNodes[1] = link.node2();
+        linkFaces.clear();
+        theMesh->GetElementsByNodes( linkNodes, linkFaces, SMDSAbs_Face );
+
+        isSharp = false;
+        if ( linkFaces.size() > 2 )
+        {
+          isSharp = true;
+        }
+        else if ( linkFaces.size() == 2 &&
+                  FaceNormal( linkFaces[0], norm1, /*normalize=*/false ) &&
+                  FaceNormal( linkFaces[1], norm2, /*normalize=*/false ))
+        {
+          double dot = norm1 * norm2; // == cos * |norm1| * |norm2|
+          if (( dot < 0 ) == ( angleCos < 0 ))
+          {
+            double cos2 = dot * dot / norm1.SquareModulus() / norm2.SquareModulus();
+            isSharp = ( angleCos < 0 ) ? ( cos2 > angleCos2 ) : ( cos2 < angleCos2 );
+          }
+          else
+          {
+            isSharp = ( angleCos > 0 );
+          }
+        }
+        nMedium = faceNodes[( i-1+nbCorners ) % nbCorners + nbCorners ];
+
+        linkIsSharp.Bind( link, sharpMedium );
+        nbSharp += isSharp;
+      }
+
+      nPrev = faceNodes[i];
+    }
+  }
+
+  resultEdges.resize( nbSharp );
+  TLinkSharpMap::Iterator linkIsSharpIter( linkIsSharp );
+  for ( int i = 0; linkIsSharpIter.More() && i < nbSharp; linkIsSharpIter.Next() )
+  {
+    const SMESH_TLink&                link = linkIsSharpIter.Key();
+    const TIsSharpAndMedium& isSharpMedium = linkIsSharpIter.Value();
+    if ( isSharpMedium.first )
+    {
+      Edge & edge  = resultEdges[ i++ ];
+      edge._node1  = link.node1();
+      edge._node2  = link.node2();
+      edge._medium = isSharpMedium.second;
+    }
+  }
+
+  return resultEdges;
+}
+
+//================================================================================
+/*!
+ * Distribute all faces of the mesh between groups using given edges as group boundaries
+ */
+//================================================================================
+
+std::vector< std::vector< const SMDS_MeshElement* > >
+SMESH_MeshAlgos::SeparateFacesByEdges( SMDS_Mesh* theMesh, const std::vector< Edge >& theEdges )
+{
+  std::vector< std::vector< const SMDS_MeshElement* > > groups;
+  if ( !theMesh ) return groups;
+
+  // build map of face edges (SMESH_TLink) and their faces
+
+  typedef std::vector< const SMDS_MeshElement* >                    TFaceVec;
+  typedef NCollection_DataMap< SMESH_TLink, TFaceVec, SMESH_TLink > TFacesByLinks;
+  TFacesByLinks facesByLink( theMesh->NbFaces() );
+
+  std::vector< const SMDS_MeshNode* > faceNodes;
+  for ( SMDS_FaceIteratorPtr faceIt = theMesh->facesIterator(); faceIt->more(); )
+  {
+    const SMDS_MeshElement* face = faceIt->next();
+    size_t             nbCorners = face->NbCornerNodes();
+
+    faceNodes.assign( face->begin_nodes(), face->end_nodes() );
+    faceNodes.resize( nbCorners + 1 );
+    faceNodes[ nbCorners ] = faceNodes[0];
+
+    face->setIsMarked( false );
+
+    for ( size_t i = 0; i < nbCorners; ++i )
+    {
+      SMESH_TLink link( faceNodes[i], faceNodes[i+1] );
+      TFaceVec* linkFaces = facesByLink.ChangeSeek( link );
+      if ( !linkFaces )
+      {
+        linkFaces = facesByLink.Bound( link, TFaceVec() );
+        linkFaces->reserve(2);
+      }
+      linkFaces->push_back( face );
+    }
+  }
+
+  // remove the given edges from facesByLink map
+
+  for ( size_t i = 0; i < theEdges.size(); ++i )
+  {
+    SMESH_TLink link( theEdges[i]._node1, theEdges[i]._node2 );
+    facesByLink.UnBind( link );
+  }
+
+  // faces connected via links of facesByLink map form a group
+
+  while ( !facesByLink.IsEmpty() )
+  {
+    groups.push_back( TFaceVec() );
+    TFaceVec & group = groups.back();
+
+    group.push_back( TFacesByLinks::Iterator( facesByLink ).Value()[0] );
+    group.back()->setIsMarked( true );
+
+    for ( size_t iF = 0; iF < group.size(); ++iF )
+    {
+      const SMDS_MeshElement* face = group[iF];
+      size_t             nbCorners = face->NbCornerNodes();
+      faceNodes.assign( face->begin_nodes(), face->end_nodes() );
+      faceNodes.resize( nbCorners + 1 );
+      faceNodes[ nbCorners ] = faceNodes[0];
+
+      for ( size_t iN = 0; iN < nbCorners; ++iN )
+      {
+        SMESH_TLink link( faceNodes[iN], faceNodes[iN+1] );
+        if ( const TFaceVec* faces = facesByLink.Seek( link ))
+        {
+          const TFaceVec& faceNeighbors = *faces;
+          for ( size_t i = 0; i < faceNeighbors.size(); ++i )
+            if ( !faceNeighbors[i]->isMarked() )
+            {
+              group.push_back( faceNeighbors[i] );
+              faceNeighbors[i]->setIsMarked( true );
+            }
+          facesByLink.UnBind( link );
+        }
+      }
+    }
+  }
+
+  // find faces that are alone in its group; they were not in facesByLink
+
+  int nbInGroups = 0;
+  for ( size_t i = 0; i < groups.size(); ++i )
+    nbInGroups += groups[i].size();
+  if ( nbInGroups < theMesh->NbFaces() )
+  {
+    for ( SMDS_FaceIteratorPtr faceIt = theMesh->facesIterator(); faceIt->more(); )
+    {
+      const SMDS_MeshElement* face = faceIt->next();
+      if ( !face->isMarked() )
+      {
+        groups.push_back( TFaceVec() );
+        groups.back().push_back( face );
+      }
+    }
+  }
+
+  return groups;
+}
+
 //================================================================================
 /*!
  * \brief Calculate normal of a mesh face