Salome HOME
22359: Body Fitting algorithm: grid orientation
authoreap <eap@opencascade.com>
Fri, 14 Feb 2014 12:09:40 +0000 (16:09 +0400)
committereap <eap@opencascade.com>
Fri, 14 Feb 2014 12:09:40 +0000 (16:09 +0400)
src/SMESH_I/SMESH_2smeshpy.cxx
src/SMESH_SWIG/StdMeshersBuilder.py
src/StdMeshers/StdMeshers_Cartesian_3D.cxx

index 9c68a33be6d5c427d09f6be082a76501921d79bb..5b9c7ca1385b02304ee515ecd4e999416bad2682 100644 (file)
@@ -3092,9 +3092,11 @@ void _pyComplexParamHypo::Process( const Handle(_pyCommand)& theCommand)
   {
     // CartesianParameters3D hyp
 
   {
     // CartesianParameters3D hyp
 
-    if ( theCommand->GetMethod() == "SetSizeThreshold" )
+    if ( theCommand->GetMethod() == "SetSizeThreshold"  ||
+         theCommand->GetMethod() == "SetToAddEdges" )
     {
     {
-      setCreationArg( 4, theCommand->GetArg( 1 ));
+      int iEdges = ( theCommand->GetMethod().Value( 4 ) == 'T' );
+      setCreationArg( 4+iEdges, theCommand->GetArg( 1 ));
       myArgCommands.push_back( theCommand );
       return;
     }
       myArgCommands.push_back( theCommand );
       return;
     }
index 46032989c8b2d0bf15359e45e3673f187561915b..0d84d50c5eb0f767ac94e983cd00a1b96bfd7a3f 100644 (file)
@@ -1400,18 +1400,17 @@ class StdMeshersBuilder_Cartesian_3D(Mesh_Algorithm):
     #    Examples:
     #    - "10.5" - defines a grid with a constant spacing
     #    - [["1", "1+10*t", "11"] [0.1, 0.6]] - defines different spacing in 3 ranges.
     #    Examples:
     #    - "10.5" - defines a grid with a constant spacing
     #    - [["1", "1+10*t", "11"] [0.1, 0.6]] - defines different spacing in 3 ranges.
-    #  @param yGridDef defines the grid along the Y asix the same way as \a xGridDef does
-    #  @param zGridDef defines the grid along the Z asix the same way as \a xGridDef does
+    #  @param yGridDef defines the grid along the Y asix the same way as \a xGridDef does.
+    #  @param zGridDef defines the grid along the Z asix the same way as \a xGridDef does.
     #  @param sizeThreshold (> 1.0) defines a minimal size of a polyhedron so that
     #  @param sizeThreshold (> 1.0) defines a minimal size of a polyhedron so that
-    #         a polyhedron of size less than hexSize/sizeThreshold is not created
-    #  @param UseExisting if ==true - searches for the existing hypothesis created with
-    #                     the same parameters, else (default) - creates a new one
-    def SetGrid(self, xGridDef, yGridDef, zGridDef, sizeThreshold=4.0, UseExisting=False):
+    #         a polyhedron of size less than hexSize/sizeThreshold is not created.
+    #  @param implEdges enables implementation of geometrical edges into the mesh.
+    def SetGrid(self, xGridDef, yGridDef, zGridDef, sizeThreshold=4.0, implEdges=False):
         if not self.hyp:
             compFun = lambda hyp, args: False
             self.hyp = self.Hypothesis("CartesianParameters3D",
                                        [xGridDef, yGridDef, zGridDef, sizeThreshold],
         if not self.hyp:
             compFun = lambda hyp, args: False
             self.hyp = self.Hypothesis("CartesianParameters3D",
                                        [xGridDef, yGridDef, zGridDef, sizeThreshold],
-                                       UseExisting=UseExisting, CompareMethod=compFun)
+                                       UseExisting=False, CompareMethod=compFun)
         if not self.mesh.IsUsedHypothesis( self.hyp, self.geom ):
             self.mesh.AddHypothesis( self.hyp, self.geom )
 
         if not self.mesh.IsUsedHypothesis( self.hyp, self.geom ):
             self.mesh.AddHypothesis( self.hyp, self.geom )
 
@@ -1427,6 +1426,7 @@ class StdMeshersBuilder_Cartesian_3D(Mesh_Algorithm):
             else:
                 self.hyp.SetGridSpacing( gridDef[0], gridDef[1], axis )
         self.hyp.SetSizeThreshold( sizeThreshold )
             else:
                 self.hyp.SetGridSpacing( gridDef[0], gridDef[1], axis )
         self.hyp.SetSizeThreshold( sizeThreshold )
+        self.hyp.SetToAddEdges( implEdges )
         return self.hyp
 
     ## Defines custom directions of axes of the grid
         return self.hyp
 
     ## Defines custom directions of axes of the grid
index d5435e7ee1b84197a567d3f98ff3902a8d37cf95..f4700221fbd2cf65939f7bff69c8cd218786771b 100644 (file)
@@ -83,7 +83,7 @@
 #include <gp_Sphere.hxx>
 #include <gp_Torus.hxx>
 
 #include <gp_Sphere.hxx>
 #include <gp_Torus.hxx>
 
-//#undef WITH_TBB
+#undef WITH_TBB
 #ifdef WITH_TBB
 #include <tbb/parallel_for.h>
 //#include <tbb/enumerable_thread_specific.h>
 #ifdef WITH_TBB
 #include <tbb/parallel_for.h>
 //#include <tbb/enumerable_thread_specific.h>
@@ -179,7 +179,7 @@ namespace
 
     B_IntersectPoint(): _node(NULL) {}
     void Add( const vector< TGeomID >& fIDs, const SMDS_MeshNode* n=0 ) const;
 
     B_IntersectPoint(): _node(NULL) {}
     void Add( const vector< TGeomID >& fIDs, const SMDS_MeshNode* n=0 ) const;
-    bool HasCommonFace( const B_IntersectPoint * other ) const;
+    int HasCommonFace( const B_IntersectPoint * other, int avoidFace=-1 ) const;
     bool IsOnFace( int faceID ) const;
     virtual ~B_IntersectPoint() {}
   };
     bool IsOnFace( int faceID ) const;
     virtual ~B_IntersectPoint() {}
   };
@@ -442,8 +442,10 @@ namespace
     {
       const SMDS_MeshNode*       _node; // mesh node at hexahedron corner
       const B_IntersectPoint* _intPoint;
     {
       const SMDS_MeshNode*       _node; // mesh node at hexahedron corner
       const B_IntersectPoint* _intPoint;
+      bool                _isUsedInFace;
 
 
-      _Node(const SMDS_MeshNode* n=0, const B_IntersectPoint* ip=0):_node(n), _intPoint(ip) {} 
+      _Node(const SMDS_MeshNode* n=0, const B_IntersectPoint* ip=0)
+        :_node(n), _intPoint(ip), _isUsedInFace(0) {} 
       const SMDS_MeshNode*    Node() const
       { return ( _intPoint && _intPoint->_node ) ? _intPoint->_node : _node; }
       const F_IntersectPoint* FaceIntPnt() const
       const SMDS_MeshNode*    Node() const
       { return ( _intPoint && _intPoint->_node ) ? _intPoint->_node : _node; }
       const F_IntersectPoint* FaceIntPnt() const
@@ -463,9 +465,10 @@ namespace
           _intPoint->Add( ip->_faceIDs );
         }
       }
           _intPoint->Add( ip->_faceIDs );
         }
       }
-      bool IsLinked( const B_IntersectPoint* other ) const
+      int IsLinked( const B_IntersectPoint* other,
+                    int                     avoidFace=-1 ) const // returns id of a common face
       {
       {
-        return _intPoint && _intPoint->HasCommonFace( other );
+        return _intPoint ? _intPoint->HasCommonFace( other, avoidFace ) : 0;
       }
       bool IsOnFace( int faceID ) const // returns true if faceID is found
       {
       }
       bool IsOnFace( int faceID ) const // returns true if faceID is found
       {
@@ -502,9 +505,9 @@ namespace
         return _OrientedLink(&_link->_splits[_reverse ? NbResultLinks()-i-1 : i],_reverse);
       }
       _Node* FirstNode() const { return _link->_nodes[ _reverse ]; }
         return _OrientedLink(&_link->_splits[_reverse ? NbResultLinks()-i-1 : i],_reverse);
       }
       _Node* FirstNode() const { return _link->_nodes[ _reverse ]; }
-      _Node* LastNode() const { return _link->_nodes[ !_reverse ]; }
+      _Node* LastNode()  const { return _link->_nodes[ !_reverse ]; }
       operator bool() const { return _link; }
       operator bool() const { return _link; }
-      vector< TGeomID > GetNotUsedFace(const set<TGeomID>& usedIDs ) const // returns supporting FACEs
+      vector< TGeomID > GetNotUsedFace(const set<TGeomID>& usedIDs ) const // returns supporting FACEs
       {
         vector< TGeomID > faces;
         const B_IntersectPoint *ip0, *ip1;
       {
         vector< TGeomID > faces;
         const B_IntersectPoint *ip0, *ip1;
@@ -518,6 +521,11 @@ namespace
         }
         return faces;
       }
         }
         return faces;
       }
+      bool HasEdgeNodes() const
+      {
+        return ( dynamic_cast< const E_IntersectPoint* >( _link->_nodes[0]->_intPoint ) ||
+                 dynamic_cast< const E_IntersectPoint* >( _link->_nodes[1]->_intPoint ));
+      }
     };
     // --------------------------------------------------------------------------------
     struct _Face
     };
     // --------------------------------------------------------------------------------
     struct _Face
@@ -593,13 +601,16 @@ namespace
                           vector< Hexahedron* >&  hexes,
                           int ijk[], int dIJK[] );
     bool findChain( _Node* n1, _Node* n2, _Face& quad, vector<_Node*>& chainNodes );
                           vector< Hexahedron* >&  hexes,
                           int ijk[], int dIJK[] );
     bool findChain( _Node* n1, _Node* n2, _Face& quad, vector<_Node*>& chainNodes );
+    bool closePolygon( _Face* polygon, vector<_Node*>& chainNodes ) const;
     int  addElements(SMESH_MesherHelper& helper);
     int  addElements(SMESH_MesherHelper& helper);
+    bool is1stNodeOut( int iLink ) const;
     bool isInHole() const;
     bool checkPolyhedronSize() const;
     bool addHexa ();
     bool addTetra();
     bool addPenta();
     bool addPyra ();
     bool isInHole() const;
     bool checkPolyhedronSize() const;
     bool addHexa ();
     bool addTetra();
     bool addPenta();
     bool addPyra ();
+    bool debugDumpLink( _Link* link );
     _Node* FindEqualNode( vector< _Node >&        nodes,
                           const E_IntersectPoint* ip,
                           const double            tol2 )
     _Node* FindEqualNode( vector< _Node >&        nodes,
                           const E_IntersectPoint* ip,
                           const double            tol2 )
@@ -725,7 +736,8 @@ namespace
         return ( ipBef->_transition == Trans_OUT );
       return ( ipBef->_transition != Trans_OUT );
     }
         return ( ipBef->_transition == Trans_OUT );
       return ( ipBef->_transition != Trans_OUT );
     }
-    return prevIsOut; // _transition == Trans_TANGENT
+    // _transition == Trans_TANGENT
+    return !prevIsOut;
   }
   //================================================================================
   /*
   }
   //================================================================================
   /*
@@ -749,15 +761,16 @@ namespace
   }
   //================================================================================
   /*
   }
   //================================================================================
   /*
-   * Returns \c true if \a other B_IntersectPoint holds the same face ID
+   * Returns index of a common face if any, else zero
    */
    */
-  bool B_IntersectPoint::HasCommonFace( const B_IntersectPoint * other ) const
+  int B_IntersectPoint::HasCommonFace( const B_IntersectPoint * other, int avoidFace ) const
   {
     if ( other )
       for ( size_t i = 0; i < other->_faceIDs.size(); ++i )
   {
     if ( other )
       for ( size_t i = 0; i < other->_faceIDs.size(); ++i )
-        if ( IsOnFace( other->_faceIDs[i] ) )
-          return true;
-    return false;
+        if ( avoidFace != other->_faceIDs[i] &&
+             IsOnFace   ( other->_faceIDs[i] ))
+          return other->_faceIDs[i];
+    return 0;
   }
   //================================================================================
   /*
   }
   //================================================================================
   /*
@@ -1582,11 +1595,11 @@ namespace
         _Link& link = _hexLinks[ iLink ];
         link._splits.clear();
         split._nodes[ 0 ] = link._nodes[0];
         _Link& link = _hexLinks[ iLink ];
         link._splits.clear();
         split._nodes[ 0 ] = link._nodes[0];
-        bool isOut = ( ! link._nodes[0]->Node() );
-        //int iEnd = link._intNodes.size() - bool( link._nodes[1]->_intPoint );
+        bool isOut = ( ! link._nodes[0]->Node() ); // is1stNodeOut( iLink );
+        bool checkTransition;
         for ( size_t i = 0; i < link._intNodes.size(); ++i )
         {
         for ( size_t i = 0; i < link._intNodes.size(); ++i )
         {
-          if ( link._intNodes[i].Node() )
+          if ( link._intNodes[i].Node() ) // intersection non-coinsident with a grid node
           {
             if ( split._nodes[ 0 ]->Node() && !isOut )
             {
           {
             if ( split._nodes[ 0 ]->Node() && !isOut )
             {
@@ -1594,11 +1607,19 @@ namespace
               link._splits.push_back( split );
             }
             split._nodes[ 0 ] = &link._intNodes[i];
               link._splits.push_back( split );
             }
             split._nodes[ 0 ] = &link._intNodes[i];
+            checkTransition = true;
           }
           }
-          switch ( link._intNodes[i].FaceIntPnt()->_transition ) {
-          case Trans_OUT: isOut = true; break;
-          case Trans_IN : isOut = false; break;
-          default:; // isOut remains the same
+          else // FACE intersection coinsident with a grid node
+          {
+            checkTransition = ( link._nodes[0]->Node() );
+          }
+          if ( checkTransition )
+          {
+            switch ( link._intNodes[i].FaceIntPnt()->_transition ) {
+            case Trans_OUT: isOut = true; break;
+            case Trans_IN : isOut = false; break;
+            default:; // isOut remains the same
+            }
           }
         }
         if ( link._nodes[ 1 ]->Node() && split._nodes[ 0 ]->Node() && !isOut )
           }
         }
         if ( link._nodes[ 1 ]->Node() && split._nodes[ 0 ]->Node() && !isOut )
@@ -1744,9 +1765,10 @@ namespace
       return;
 
     _polygons.clear();
       return;
 
     _polygons.clear();
-    _polygons.reserve( 10 );
+    _polygons.reserve( 20 );
 
 
-    // create polygons from quadrangles and get their nodes
+    // Create polygons from quadrangles
+    // --------------------------------
 
     _Link polyLink;
     vector< _OrientedLink > splits;
 
     _Link polyLink;
     vector< _OrientedLink > splits;
@@ -1788,6 +1810,11 @@ namespace
             _vertexNodes.push_back( quad._edgeNodes[ iP ]);
         }
       }
             _vertexNodes.push_back( quad._edgeNodes[ iP ]);
         }
       }
+#ifdef _DEBUG_
+      for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
+        quad._edgeNodes[ iP ]._isUsedInFace = false;
+#endif
+      int nbUsedEdgeNodes = 0;
 
       while ( nbSplits > 0 )
       {
 
       while ( nbSplits > 0 )
       {
@@ -1815,8 +1842,8 @@ namespace
           n1 = split.FirstNode();
           if ( n1 != n2 )
           {
           n1 = split.FirstNode();
           if ( n1 != n2 )
           {
-            // try to connect to intersections with EDGES
-            if ( quad._edgeNodes.size() > 0  &&
+            // try to connect to intersections with EDGEs
+            if ( quad._edgeNodes.size() > nbUsedEdgeNodes  &&
                  findChain( n2, n1, quad, chainNodes ))
             {
               for ( size_t i = 1; i < chainNodes.size(); ++i )
                  findChain( n2, n1, quad, chainNodes ))
             {
               for ( size_t i = 1; i < chainNodes.size(); ++i )
@@ -1825,6 +1852,13 @@ namespace
                 polyLink._nodes[1] = chainNodes[i];
                 polygon->_polyLinks.push_back( polyLink );
                 polygon->_links.push_back( _OrientedLink( &polygon->_polyLinks.back() ));
                 polyLink._nodes[1] = chainNodes[i];
                 polygon->_polyLinks.push_back( polyLink );
                 polygon->_links.push_back( _OrientedLink( &polygon->_polyLinks.back() ));
+                nbUsedEdgeNodes += polyLink._nodes[1]->_isUsedInFace;
+              }
+              if ( chainNodes.back() != n1 )
+              {
+                n2 = chainNodes.back();
+                --iS;
+                continue;
               }
             }
             // try to connect to a split ending on the same FACE
               }
             }
             // try to connect to a split ending on the same FACE
@@ -1870,7 +1904,11 @@ namespace
 
         if ( nFirst != n2 ) // close a polygon
         {
 
         if ( nFirst != n2 ) // close a polygon
         {
-          findChain( n2, nFirst, quad, chainNodes );
+          if ( !findChain( n2, nFirst, quad, chainNodes ))
+          {
+            if ( !closePolygon( polygon, chainNodes ))
+              ;//chainNodes.push_back( nFirst );
+          }
           for ( size_t i = 1; i < chainNodes.size(); ++i )
           {
             polyLink._nodes[0] = chainNodes[i-1];
           for ( size_t i = 1; i < chainNodes.size(); ++i )
           {
             polyLink._nodes[0] = chainNodes[i-1];
@@ -1892,7 +1930,8 @@ namespace
 
     }  // loop on 6 sides of a hexahedron
 
 
     }  // loop on 6 sides of a hexahedron
 
-    // create polygons closing holes in a polyhedron
+    // Create polygons closing holes in a polyhedron
+    // ----------------------------------------------
 
     // add polygons to their links
     for ( size_t iP = 0; iP < _polygons.size(); ++iP )
 
     // add polygons to their links
     for ( size_t iP = 0; iP < _polygons.size(); ++iP )
@@ -1915,7 +1954,7 @@ namespace
           freeLinks.push_back( & polygon._links[ iL ]);
     }
     int nbFreeLinks = freeLinks.size();
           freeLinks.push_back( & polygon._links[ iL ]);
     }
     int nbFreeLinks = freeLinks.size();
-    if ( 0 < nbFreeLinks && nbFreeLinks < 3 ) return;
+    if ( nbFreeLinks < 3 ) return;
 
     set<TGeomID> usedFaceIDs;
 
 
     set<TGeomID> usedFaceIDs;
 
@@ -1958,22 +1997,42 @@ namespace
         // get a remaining link to start from, one lying on minimal
         // nb of FACEs
         {
         // get a remaining link to start from, one lying on minimal
         // nb of FACEs
         {
-          map< vector< TGeomID >, int > facesOfLink;
-          map< vector< TGeomID >, int >::iterator f2l;
+          vector< pair< TGeomID, int > > facesOfLink[3];
+          pair< TGeomID, int > faceOfLink( -1, -1 );
+          vector< TGeomID > faces;
           for ( size_t iL = 0; iL < freeLinks.size(); ++iL )
             if ( freeLinks[ iL ] )
             {
           for ( size_t iL = 0; iL < freeLinks.size(); ++iL )
             if ( freeLinks[ iL ] )
             {
-              f2l = facesOfLink.insert
-                ( make_pair( freeLinks[ iL ]->GetNotUsedFace( usedFaceIDs ), iL )).first;
-              if ( f2l->first.size() == 1 )
-                break;
+              faces = freeLinks[ iL ]->GetNotUsedFace( usedFaceIDs );
+              if ( faces.size() == 1 )
+              {
+                faceOfLink = make_pair( faces[0], iL );
+                if ( !freeLinks[ iL ]->HasEdgeNodes() )
+                  break;
+                facesOfLink[0].push_back( faceOfLink );
+              }
+              else if ( facesOfLink[0].empty() )
+              {
+                faceOfLink = make_pair(( faces.empty() ? -1 : faces[0]), iL );
+                facesOfLink[ 1 + faces.empty() ].push_back( faceOfLink );
+              }
             }
             }
-          f2l = facesOfLink.begin();
-          if ( f2l->first.empty() )
-            return;
-          curFace = f2l->first[0];
-          curLink = freeLinks[ f2l->second ];
-          freeLinks[ f2l->second ] = 0;
+          for ( int i = 0; faceOfLink.second < 0 && i < 3; ++i )
+            if ( !facesOfLink[i].empty() )
+              faceOfLink = facesOfLink[i][0];
+
+          if ( faceOfLink.first < 0 ) // all faces used
+          {
+            for ( size_t i = 0; i < facesOfLink[2].size() && faceOfLink.first < 1; ++i )
+            {
+              curLink = freeLinks[ facesOfLink[2][i].second ];
+              faceOfLink.first = curLink->FirstNode()->IsLinked( curLink->FirstNode()->_intPoint );
+            }
+            usedFaceIDs.clear();
+          }
+          curFace = faceOfLink.first;
+          curLink = freeLinks[ faceOfLink.second ];
+          freeLinks[ faceOfLink.second ] = 0;
         }
         usedFaceIDs.insert( curFace );
         polygon._links.push_back( *curLink );
         }
         usedFaceIDs.insert( curFace );
         polygon._links.push_back( *curLink );
@@ -2059,6 +2118,17 @@ namespace
 
       if ( polygon._links.size() == 2 )
       {
 
       if ( polygon._links.size() == 2 )
       {
+        if ( freeLinks.back() == &polygon._links.back() )
+        {
+          freeLinks.back() = 0;
+          --nbFreeLinks;
+        }
+        vector< _Face*>& polygs1 = polygon._links.front()._link->_faces;
+        vector< _Face*>& polygs2 = polygon._links.back()._link->_faces;
+        _Face* polyg1 = ( polygs1.empty() ? 0 : polygs1[0] );
+        _Face* polyg2 = ( polygs2.empty() ? 0 : polygs2[0] );
+        if ( polyg1 ) polygs2.push_back( polyg1 );
+        if ( polyg2 ) polygs1.push_back( polyg2 );
         _polygons.pop_back();
       }
       else
         _polygons.pop_back();
       }
       else
@@ -2131,7 +2201,7 @@ namespace
         multiset< F_IntersectPoint >::const_iterator ip = line._intPoints.begin();
         for ( ; ip != line._intPoints.end(); ++ip )
         {
         multiset< F_IntersectPoint >::const_iterator ip = line._intPoints.begin();
         for ( ; ip != line._intPoints.end(); ++ip )
         {
-          //if ( !ip->_node ) continue;
+          // if ( !ip->_node ) continue; // intersection at a grid node
           lineInd.SetIndexOnLine( ip->_indexOnLine );
           for ( int iL = 0; iL < 4; ++iL ) // loop on 4 cells sharing a link
           {
           lineInd.SetIndexOnLine( ip->_indexOnLine );
           for ( int iL = 0; iL < 4; ++iL ) // loop on 4 cells sharing a link
           {
@@ -2173,14 +2243,16 @@ namespace
       if ( hex )
       {
         intHexInd[ nbIntHex++ ] = i;
       if ( hex )
       {
         intHexInd[ nbIntHex++ ] = i;
-        if ( hex->_nbIntNodes > 0 ) continue; // treat intersected hex later
+        if ( hex->_nbIntNodes > 0 || ! hex->_edgeIntPnts.empty())
+          continue; // treat intersected hex later
         this->init( hex->_i, hex->_j, hex->_k );
       }
       else
       {    
         this->init( i );
       }
         this->init( hex->_i, hex->_j, hex->_k );
       }
       else
       {    
         this->init( i );
       }
-      if ( _nbCornerNodes == 8 && ( _nbBndNodes < _nbCornerNodes || !isInHole() ))
+      if (( _nbCornerNodes == 8 ) &&
+          ( _nbBndNodes < _nbCornerNodes || !isInHole() ))
       {
         // order of _hexNodes is defined by enum SMESH_Block::TShapeID
         SMDS_MeshElement* el =
       {
         // order of _hexNodes is defined by enum SMESH_Block::TShapeID
         SMDS_MeshElement* el =
@@ -2557,24 +2629,123 @@ namespace
   {
     chn.clear();
     chn.push_back( n1 );
   {
     chn.clear();
     chn.push_back( n1 );
-    bool found = false;
+    for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
+      if ( !quad._edgeNodes[ iP ]._isUsedInFace &&
+           n1->IsLinked( quad._edgeNodes[ iP ]._intPoint ) &&
+           n2->IsLinked( quad._edgeNodes[ iP ]._intPoint ))
+      {
+        chn.push_back( & quad._edgeNodes[ iP ]);
+        chn.push_back( n2 );
+        quad._edgeNodes[ iP ]._isUsedInFace = true;
+        return true;
+      }
+    bool found;
     do
     {
       found = false;
       for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
     do
     {
       found = false;
       for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
-        if (( std::find( ++chn.begin(), chn.end(), & quad._edgeNodes[iP]) == chn.end()) &&
-            chn.back()->IsLinked( quad._edgeNodes[ iP ]._intPoint ))
+        if ( !quad._edgeNodes[ iP ]._isUsedInFace &&
+             chn.back()->IsLinked( quad._edgeNodes[ iP ]._intPoint ))
         {
           chn.push_back( & quad._edgeNodes[ iP ]);
         {
           chn.push_back( & quad._edgeNodes[ iP ]);
-          found = true;
+          found = quad._edgeNodes[ iP ]._isUsedInFace = true;
           break;
         }
           break;
         }
-    } while ( found && chn.back() != n2 );
+    } while ( found && ! chn.back()->IsLinked( n2->_intPoint ) );
 
 
-    if ( chn.back() != n2 )
+    if ( chn.back() != n2 && chn.back()->IsLinked( n2->_intPoint ))
       chn.push_back( n2 );
 
       chn.push_back( n2 );
 
-    return chn.size() > 2;
+    return chn.size() > 1;
+  }
+  //================================================================================
+  /*!
+   * \brief Try to heal a polygon whose ends are not connected
+   */
+  bool Hexahedron::closePolygon( _Face* polygon, vector<_Node*>& chainNodes ) const
+  {
+    int i = -1, nbLinks = polygon->_links.size();
+    if ( nbLinks < 3 )
+      return false;
+    vector< _OrientedLink > newLinks;
+    // find a node lying on the same FACE as the last one
+    _Node*   node = polygon->_links.back().LastNode();
+    int avoidFace = node->IsLinked( polygon->_links.back().FirstNode()->_intPoint );
+    for ( i = nbLinks - 2; i >= 0; --i )
+      if ( node->IsLinked( polygon->_links[i].FirstNode()->_intPoint, avoidFace ))
+        break;
+    if ( i >= 0 )
+    {
+      for ( ; i < nbLinks; ++i )
+        newLinks.push_back( polygon->_links[i] );
+    }
+    else
+    {
+      // find a node lying on the same FACE as the first one
+      node      = polygon->_links[0].FirstNode();
+      avoidFace = node->IsLinked( polygon->_links[0].LastNode()->_intPoint );
+      for ( i = 1; i < nbLinks; ++i )
+        if ( node->IsLinked( polygon->_links[i].LastNode()->_intPoint, avoidFace ))
+          break;
+      if ( i < nbLinks )
+        for ( nbLinks = i + 1, i = 0; i < nbLinks; ++i )
+          newLinks.push_back( polygon->_links[i] );
+    }
+    if ( newLinks.size() > 1 )
+    {
+      polygon->_links.swap( newLinks );
+      chainNodes.clear();
+      chainNodes.push_back( polygon->_links.back().LastNode() );
+      chainNodes.push_back( polygon->_links[0].FirstNode() );
+      return true;
+    }
+    return false;
+  }
+  //================================================================================
+  /*!
+   * \brief Checks transition at the 1st node of a link
+   */
+  bool Hexahedron::is1stNodeOut( int iLink ) const
+  {
+    if ( !_hexLinks[ iLink ]._nodes[0]->Node() ) // no node
+      return true;
+    if ( !_hexLinks[ iLink ]._nodes[0]->_intPoint ) // no intersection with geometry
+      return false;
+    switch ( _hexLinks[ iLink ]._nodes[0]->FaceIntPnt()->_transition ) {
+    case Trans_OUT: return true;
+    case Trans_IN : return false;
+    default: ; // tangent transition
+    }
+
+    // ijk of a GridLine corresponding to the link
+    int   iDir = iLink / 4;
+    int indSub = iLink % 4;
+    LineIndexer li = _grid->GetLineIndexer( iDir );
+    li.SetIJK( _i,_j,_k );
+    size_t lineIndex[4] = { li.LineIndex  (),
+                            li.LineIndex10(),
+                            li.LineIndex01(),
+                            li.LineIndex11() };
+    GridLine& line = _grid->_lines[ iDir ][ lineIndex[ indSub ]];
+
+    // analyze transition of previous ip
+    bool isOut = true;
+    multiset< F_IntersectPoint >::const_iterator ip = line._intPoints.begin();
+    for ( ; ip != line._intPoints.end(); ++ip )
+    {
+      if ( &(*ip) == _hexLinks[ iLink ]._nodes[0]->_intPoint )
+        break;
+      switch ( ip->_transition ) {
+      case Trans_OUT: isOut = true;
+      case Trans_IN : isOut = false;
+      default:;
+      }
+    }
+#ifdef _DEBUG_
+    if ( ip == line._intPoints.end() )
+      cout << "BUG: Wrong GridLine. IKJ = ( "<< _i << " " << _j << " " << _k << " )" << endl;
+#endif
+    return isOut;
   }
   //================================================================================
   /*!
   }
   //================================================================================
   /*!
@@ -2728,7 +2899,9 @@ namespace
 
       // find a top node above the base node
       _Link* link = _polygons[0]._links[iL]._link;
 
       // find a top node above the base node
       _Link* link = _polygons[0]._links[iL]._link;
-      ASSERT( link->_faces.size() > 1 );
+      //ASSERT( link->_faces.size() > 1 );
+      if ( link->_faces.size() < 2 )
+        return debugDumpLink( link );
       // a quadrangle sharing <link> with _polygons[0]
       _Face* quad = link->_faces[ bool( link->_faces[0] == & _polygons[0] )];
       for ( int i = 0; i < 4; ++i )
       // a quadrangle sharing <link> with _polygons[0]
       _Face* quad = link->_faces[ bool( link->_faces[0] == & _polygons[0] )];
       for ( int i = 0; i < 4; ++i )
@@ -2757,7 +2930,9 @@ namespace
     nodes[2] = _polygons[0]._links[2].FirstNode();
 
     _Link* link = _polygons[0]._links[0]._link;
     nodes[2] = _polygons[0]._links[2].FirstNode();
 
     _Link* link = _polygons[0]._links[0]._link;
-    ASSERT( link->_faces.size() > 1 );
+    //ASSERT( link->_faces.size() > 1 );
+    if ( link->_faces.size() < 2 )
+      return debugDumpLink( link );
 
     // a triangle sharing <link> with _polygons[0]
     _Face* tria = link->_faces[ bool( link->_faces[0] == & _polygons[0] )];
 
     // a triangle sharing <link> with _polygons[0]
     _Face* tria = link->_faces[ bool( link->_faces[0] == & _polygons[0] )];
@@ -2795,7 +2970,9 @@ namespace
 
       // find a top node above the base node
       _Link* link = _polygons[ iTri ]._links[iL]._link;
 
       // find a top node above the base node
       _Link* link = _polygons[ iTri ]._links[iL]._link;
-      ASSERT( link->_faces.size() > 1 );
+      //ASSERT( link->_faces.size() > 1 );
+      if ( link->_faces.size() < 2 )
+        return debugDumpLink( link );
       // a quadrangle sharing <link> with a base triangle
       _Face* quad = link->_faces[ bool( link->_faces[0] == & _polygons[ iTri ] )];
       if ( quad->_links.size() != 4 ) return false;
       // a quadrangle sharing <link> with a base triangle
       _Face* quad = link->_faces[ bool( link->_faces[0] == & _polygons[ iTri ] )];
       if ( quad->_links.size() != 4 ) return false;
@@ -2835,6 +3012,8 @@ namespace
 
     _Link* link = _polygons[iQuad]._links[0]._link;
     ASSERT( link->_faces.size() > 1 );
 
     _Link* link = _polygons[iQuad]._links[0]._link;
     ASSERT( link->_faces.size() > 1 );
+    if ( link->_faces.size() < 2 )
+      return debugDumpLink( link );
 
     // a triangle sharing <link> with a base quadrangle
     _Face* tria = link->_faces[ bool( link->_faces[0] == & _polygons[ iQuad ] )];
 
     // a triangle sharing <link> with a base quadrangle
     _Face* tria = link->_faces[ bool( link->_faces[0] == & _polygons[ iQuad ] )];
@@ -2849,6 +3028,20 @@ namespace
 
     return false;
   }
 
     return false;
   }
+  //================================================================================
+  /*!
+   * \brief Dump a link and return \c false
+   */
+  bool Hexahedron::debugDumpLink( Hexahedron::_Link* link )
+  {
+#ifdef _DEBUG_
+    gp_Pnt p1 = link->_nodes[0]->Point(), p2 = link->_nodes[1]->Point();
+    cout << "BUG: not shared link. IKJ = ( "<< _i << " " << _j << " " << _k << " )" << endl
+         << "n1 (" << p1.X() << ", "<< p1.Y() << ", "<< p1.Z() << " )" << endl
+         << "n2 (" << p2.X() << ", "<< p2.Y() << ", "<< p2.Z() << " )" << endl;
+#endif
+    return false;
+  }
 
   //================================================================================
   /*!
 
   //================================================================================
   /*!
@@ -2964,6 +3157,8 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh &         theMesh,
 
   _computeCanceled = false;
 
 
   _computeCanceled = false;
 
+  SMESH_MesherHelper helper( theMesh );
+
   try
   {
     Grid grid;
   try
   {
     Grid grid;
@@ -2992,12 +3187,16 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh &         theMesh,
       shapeBox.Add( facesItersectors[i].GetFaceBndBox() );
 
       if ( _hyp->GetToAddEdges() )
       shapeBox.Add( facesItersectors[i].GetFaceBndBox() );
 
       if ( _hyp->GetToAddEdges() )
+      {
+        helper.SetSubShape( faceVec[i] );
         for ( eExp.Init( faceVec[i], TopAbs_EDGE ); eExp.More(); eExp.Next() )
         {
           const TopoDS_Edge& edge = TopoDS::Edge( eExp.Current() );
         for ( eExp.Init( faceVec[i], TopAbs_EDGE ); eExp.More(); eExp.Next() )
         {
           const TopoDS_Edge& edge = TopoDS::Edge( eExp.Current() );
-          if ( !SMESH_Algo::isDegenerated( edge ))
+          if ( !SMESH_Algo::isDegenerated( edge ) &&
+               !helper.IsRealSeam( edge ))
             edge2faceIDsMap[ grid._shapes.Add( edge )].push_back( facesItersectors[i]._faceID );
         }
             edge2faceIDsMap[ grid._shapes.Add( edge )].push_back( facesItersectors[i]._faceID );
         }
+      }
     }
 
     getExactBndBox( faceVec, _hyp->GetAxisDirs(), shapeBox );
     }
 
     getExactBndBox( faceVec, _hyp->GetAxisDirs(), shapeBox );
@@ -3037,7 +3236,6 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh &         theMesh,
     for ( size_t i = 0; i < facesItersectors.size(); ++i )
       facesItersectors[i].StoreIntersections();
 
     for ( size_t i = 0; i < facesItersectors.size(); ++i )
       facesItersectors[i].StoreIntersections();
 
-    SMESH_MesherHelper helper( theMesh );
     TopExp_Explorer solidExp (theShape, TopAbs_SOLID);
     helper.SetSubShape( solidExp.Current() );
     helper.SetElementsOnShape( true );
     TopExp_Explorer solidExp (theShape, TopAbs_SOLID);
     helper.SetSubShape( solidExp.Current() );
     helper.SetElementsOnShape( true );