Salome HOME
0022360: EDF SMESH: Body Fitting algorithm: incorporate edges
[modules/smesh.git] / src / StdMeshers / StdMeshers_Cartesian_3D.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : StdMeshers_Cartesian_3D.cxx
23 //  Module : SMESH
24 //
25 #include "StdMeshers_Cartesian_3D.hxx"
26
27 #include "SMDS_MeshNode.hxx"
28 #include "SMESH_Block.hxx"
29 #include "SMESH_Comment.hxx"
30 #include "SMESH_Mesh.hxx"
31 #include "SMESH_MesherHelper.hxx"
32 #include "SMESH_subMesh.hxx"
33 #include "SMESH_subMeshEventListener.hxx"
34 #include "StdMeshers_CartesianParameters3D.hxx"
35
36 #include <utilities.h>
37 #include <Utils_ExceptHandlers.hxx>
38 #include <Basics_OCCTVersion.hxx>
39
40 #include <GEOMUtils.hxx>
41
42 #include <BRepAdaptor_Curve.hxx>
43 #include <BRepAdaptor_Surface.hxx>
44 #include <BRepBndLib.hxx>
45 #include <BRepBuilderAPI_Copy.hxx>
46 #include <BRepBuilderAPI_MakeFace.hxx>
47 #include <BRepTools.hxx>
48 #include <BRep_Builder.hxx>
49 #include <BRep_Tool.hxx>
50 #include <Bnd_B3d.hxx>
51 #include <Bnd_Box.hxx>
52 #include <ElSLib.hxx>
53 #include <GCPnts_UniformDeflection.hxx>
54 #include <Geom2d_BSplineCurve.hxx>
55 #include <Geom2d_BezierCurve.hxx>
56 #include <Geom2d_TrimmedCurve.hxx>
57 #include <GeomAPI_ProjectPointOnSurf.hxx>
58 #include <GeomLib.hxx>
59 #include <Geom_BSplineCurve.hxx>
60 #include <Geom_BSplineSurface.hxx>
61 #include <Geom_BezierCurve.hxx>
62 #include <Geom_BezierSurface.hxx>
63 #include <Geom_RectangularTrimmedSurface.hxx>
64 #include <Geom_TrimmedCurve.hxx>
65 #include <IntAna_IntConicQuad.hxx>
66 #include <IntAna_IntLinTorus.hxx>
67 #include <IntAna_Quadric.hxx>
68 #include <IntCurveSurface_TransitionOnCurve.hxx>
69 #include <IntCurvesFace_Intersector.hxx>
70 #include <Poly_Triangulation.hxx>
71 #include <Precision.hxx>
72 #include <TopExp.hxx>
73 #include <TopExp_Explorer.hxx>
74 #include <TopLoc_Location.hxx>
75 #include <TopTools_MapOfShape.hxx>
76 #include <TopoDS.hxx>
77 #include <TopoDS_Compound.hxx>
78 #include <TopoDS_Face.hxx>
79 #include <TopoDS_TShape.hxx>
80 #include <gp_Cone.hxx>
81 #include <gp_Cylinder.hxx>
82 #include <gp_Lin.hxx>
83 #include <gp_Pln.hxx>
84 #include <gp_Pnt2d.hxx>
85 #include <gp_Sphere.hxx>
86 #include <gp_Torus.hxx>
87
88 #undef WITH_TBB
89 #ifdef WITH_TBB
90 #include <tbb/parallel_for.h>
91 //#include <tbb/enumerable_thread_specific.h>
92 #endif
93
94 using namespace std;
95
96 #ifdef _DEBUG_
97 //#define _MY_DEBUG_
98 #endif
99
100 #if OCC_VERSION_LARGE <= 0x06050300
101 // workaround is required only for OCCT6.5.3 and older (see OCC22809)
102 #define ELLIPSOLID_WORKAROUND
103 #endif
104
105 #ifdef ELLIPSOLID_WORKAROUND
106 #include <BRepIntCurveSurface_Inter.hxx>
107 #include <BRepTopAdaptor_TopolTool.hxx>
108 #include <BRepAdaptor_HSurface.hxx>
109 #endif
110
111 //=============================================================================
112 /*!
113  * Constructor
114  */
115 //=============================================================================
116
117 StdMeshers_Cartesian_3D::StdMeshers_Cartesian_3D(int hypId, int studyId, SMESH_Gen * gen)
118   :SMESH_3D_Algo(hypId, studyId, gen)
119 {
120   _name = "Cartesian_3D";
121   _shapeType = (1 << TopAbs_SOLID);       // 1 bit /shape type
122   _compatibleHypothesis.push_back("CartesianParameters3D");
123
124   _onlyUnaryInput = false;          // to mesh all SOLIDs at once
125   _requireDiscreteBoundary = false; // 2D mesh not needed
126   _supportSubmeshes = false;        // do not use any existing mesh
127 }
128
129 //=============================================================================
130 /*!
131  * Check presence of a hypothesis
132  */
133 //=============================================================================
134
135 bool StdMeshers_Cartesian_3D::CheckHypothesis (SMESH_Mesh&          aMesh,
136                                                const TopoDS_Shape&  aShape,
137                                                Hypothesis_Status&   aStatus)
138 {
139   aStatus = SMESH_Hypothesis::HYP_MISSING;
140
141   const list<const SMESHDS_Hypothesis*>& hyps = GetUsedHypothesis(aMesh, aShape);
142   list <const SMESHDS_Hypothesis* >::const_iterator h = hyps.begin();
143   if ( h == hyps.end())
144   {
145     return false;
146   }
147
148   for ( ; h != hyps.end(); ++h )
149   {
150     if (( _hyp = dynamic_cast<const StdMeshers_CartesianParameters3D*>( *h )))
151     {
152       aStatus = _hyp->IsDefined() ? HYP_OK : HYP_BAD_PARAMETER;
153       break;
154     }
155   }
156
157   return aStatus == HYP_OK;
158 }
159
160 namespace
161 {
162   typedef int TGeomID;
163
164   //=============================================================================
165   // Definitions of internal utils
166   // --------------------------------------------------------------------------
167   enum Transition {
168     Trans_TANGENT = IntCurveSurface_Tangent,
169     Trans_IN      = IntCurveSurface_In,
170     Trans_OUT     = IntCurveSurface_Out,
171     Trans_APEX
172   };
173   // --------------------------------------------------------------------------
174   /*!
175    * \brief Common data of any intersection between a Grid and a shape
176    */
177   struct B_IntersectPoint
178   {
179     mutable const SMDS_MeshNode* _node;
180     mutable vector< TGeomID >    _faceIDs;
181
182     B_IntersectPoint(): _node(NULL) {}
183     void Add( const vector< TGeomID >& fIDs, const SMDS_MeshNode* n=0 ) const;
184     int HasCommonFace( const B_IntersectPoint * other, int avoidFace=-1 ) const;
185     bool IsOnFace( int faceID ) const;
186     virtual ~B_IntersectPoint() {}
187   };
188   // --------------------------------------------------------------------------
189   /*!
190    * \brief Data of intersection between a GridLine and a TopoDS_Face
191    */
192   struct F_IntersectPoint : public B_IntersectPoint
193   {
194     double             _paramOnLine;
195     mutable Transition _transition;
196     mutable size_t     _indexOnLine;
197
198     bool operator< ( const F_IntersectPoint& o ) const { return _paramOnLine < o._paramOnLine; }
199   };
200   // --------------------------------------------------------------------------
201   /*!
202    * \brief Data of intersection between GridPlanes and a TopoDS_EDGE
203    */
204   struct E_IntersectPoint : public B_IntersectPoint
205   {
206     gp_Pnt  _point;
207     double  _uvw[3];
208     TGeomID _shapeID;
209   };
210   // --------------------------------------------------------------------------
211   /*!
212    * \brief A line of the grid and its intersections with 2D geometry
213    */
214   struct GridLine
215   {
216     gp_Lin _line;
217     double _length; // line length
218     multiset< F_IntersectPoint > _intPoints;
219
220     void RemoveExcessIntPoints( const double tol );
221     bool GetIsOutBefore( multiset< F_IntersectPoint >::iterator ip, bool prevIsOut );
222   };
223   // --------------------------------------------------------------------------
224   /*!
225    * \brief Planes of the grid used to find intersections of an EDGE with a hexahedron
226    */
227   struct GridPlanes
228   {
229     gp_XYZ _uNorm, _vNorm, _zNorm;
230     vector< gp_XYZ > _origins; // origin points of all planes in one direction
231     vector< double > _zProjs;  // projections of origins to _zNorm
232   };
233   // --------------------------------------------------------------------------
234   /*!
235    * \brief Iterator on the parallel grid lines of one direction
236    */
237   struct LineIndexer
238   {
239     size_t _size  [3];
240     size_t _curInd[3];
241     size_t _iVar1, _iVar2, _iConst;
242     string _name1, _name2, _nameConst;
243     LineIndexer() {}
244     LineIndexer( size_t sz1, size_t sz2, size_t sz3,
245                  size_t iv1, size_t iv2, size_t iConst,
246                  const string& nv1, const string& nv2, const string& nConst )
247     {
248       _size[0] = sz1; _size[1] = sz2; _size[2] = sz3;
249       _curInd[0] = _curInd[1] = _curInd[2] = 0;
250       _iVar1 = iv1; _iVar2 = iv2; _iConst = iConst; 
251       _name1 = nv1; _name2 = nv2; _nameConst = nConst;
252     }
253
254     size_t I() const { return _curInd[0]; }
255     size_t J() const { return _curInd[1]; }
256     size_t K() const { return _curInd[2]; }
257     void SetIJK( size_t i, size_t j, size_t k )
258     {
259       _curInd[0] = i; _curInd[1] = j; _curInd[2] = k;
260     }
261     void operator++()
262     {
263       if ( ++_curInd[_iVar1] == _size[_iVar1] )
264         _curInd[_iVar1] = 0, ++_curInd[_iVar2];
265     }
266     bool More() const { return _curInd[_iVar2] < _size[_iVar2]; }
267     size_t LineIndex   () const { return _curInd[_iVar1] + _curInd[_iVar2]* _size[_iVar1]; }
268     size_t LineIndex10 () const { return (_curInd[_iVar1] + 1 ) + _curInd[_iVar2]* _size[_iVar1]; }
269     size_t LineIndex01 () const { return _curInd[_iVar1] + (_curInd[_iVar2] + 1 )* _size[_iVar1]; }
270     size_t LineIndex11 () const { return (_curInd[_iVar1] + 1 ) + (_curInd[_iVar2] + 1 )* _size[_iVar1]; }
271     void SetIndexOnLine (size_t i)  { _curInd[ _iConst ] = i; }
272     size_t NbLines() const { return _size[_iVar1] * _size[_iVar2]; }
273   };
274   // --------------------------------------------------------------------------
275   /*!
276    * \brief Container of GridLine's
277    */
278   struct Grid
279   {
280     vector< double >   _coords[3]; // coordinates of grid nodes
281     gp_XYZ             _axes  [3]; // axis directions
282     vector< GridLine > _lines [3]; //    in 3 directions
283     double             _tol, _minCellSize;
284     gp_XYZ             _origin;
285     gp_Mat             _invB; // inverted basis of _axes
286     //bool               _isOrthogonalAxes;
287
288     vector< const SMDS_MeshNode* >    _nodes; // mesh nodes at grid nodes
289     vector< const F_IntersectPoint* > _gridIntP; // grid node intersection with geometry
290
291     list< E_IntersectPoint >          _edgeIntP; // intersections with EDGEs
292     TopTools_IndexedMapOfShape        _shapes;
293
294     SMESH_MesherHelper*               _helper;
295
296     size_t CellIndex( size_t i, size_t j, size_t k ) const
297     {
298       return i + j*(_coords[0].size()-1) + k*(_coords[0].size()-1)*(_coords[1].size()-1);
299     }
300     size_t NodeIndex( size_t i, size_t j, size_t k ) const
301     {
302       return i + j*_coords[0].size() + k*_coords[0].size()*_coords[1].size();
303     }
304     size_t NodeIndexDX() const { return 1; }
305     size_t NodeIndexDY() const { return _coords[0].size(); }
306     size_t NodeIndexDZ() const { return _coords[0].size() * _coords[1].size(); }
307
308     LineIndexer GetLineIndexer(size_t iDir) const;
309
310     void SetCoordinates(const vector<double>& xCoords,
311                         const vector<double>& yCoords,
312                         const vector<double>& zCoords,
313                         const double*         axesDirs,
314                         const Bnd_Box&        bndBox );
315     void ComputeUVW(const gp_XYZ& p, double uvw[3]);
316     void ComputeNodes(SMESH_MesherHelper& helper);
317   };
318 #ifdef ELLIPSOLID_WORKAROUND
319   // --------------------------------------------------------------------------
320   /*!
321    * \brief struct temporary replacing IntCurvesFace_Intersector until
322    *        OCCT bug 0022809 is fixed
323    *        http://tracker.dev.opencascade.org/view.php?id=22809
324    */
325   struct TMP_IntCurvesFace_Intersector
326   {
327     BRepAdaptor_Surface                       _surf;
328     double                                    _tol;
329     BRepIntCurveSurface_Inter                 _intcs;
330     vector<IntCurveSurface_IntersectionPoint> _points;
331     BRepTopAdaptor_TopolTool                  _clsf;
332
333     TMP_IntCurvesFace_Intersector(const TopoDS_Face& face, const double tol)
334       :_surf( face ), _tol( tol ), _clsf( new BRepAdaptor_HSurface(_surf) ) {}
335     Bnd_Box Bounding() const { Bnd_Box b; BRepBndLib::Add (_surf.Face(), b); return b; }
336     void Perform( const gp_Lin& line, const double w0, const double w1 )
337     {
338       _points.clear();
339       for ( _intcs.Init( _surf.Face(), line, _tol ); _intcs.More(); _intcs.Next() )
340         if ( w0 <= _intcs.W() && _intcs.W() <= w1 )
341           _points.push_back( _intcs.Point() );
342     }
343     bool IsDone() const { return true; }
344     int  NbPnt()  const { return _points.size(); }
345     IntCurveSurface_TransitionOnCurve Transition( const int i ) const { return _points[ i-1 ].Transition(); }
346     double       WParameter( const int i ) const { return _points[ i-1 ].W(); }
347     TopAbs_State ClassifyUVPoint(const gp_Pnt2d& p) { return _clsf.Classify( p, _tol ); }
348   };
349 #define __IntCurvesFace_Intersector TMP_IntCurvesFace_Intersector
350 #else
351 #define __IntCurvesFace_Intersector IntCurvesFace_Intersector
352 #endif
353   // --------------------------------------------------------------------------
354   /*!
355    * \brief Intersector of TopoDS_Face with all GridLine's
356    */
357   struct FaceGridIntersector
358   {
359     TopoDS_Face _face;
360     TGeomID     _faceID;
361     Grid*       _grid;
362     Bnd_Box     _bndBox;
363     __IntCurvesFace_Intersector* _surfaceInt;
364     vector< std::pair< GridLine*, F_IntersectPoint > > _intersections;
365
366     FaceGridIntersector(): _grid(0), _surfaceInt(0) {}
367     void Intersect();
368     bool IsInGrid(const Bnd_Box& gridBox);
369
370     void StoreIntersections()
371     {
372       for ( size_t i = 0; i < _intersections.size(); ++i )
373       {
374         multiset< F_IntersectPoint >::iterator ip = 
375           _intersections[i].first->_intPoints.insert( _intersections[i].second );
376         ip->_faceIDs.reserve( 1 );
377         ip->_faceIDs.push_back( _faceID );
378       }
379     }
380     const Bnd_Box& GetFaceBndBox()
381     {
382       GetCurveFaceIntersector();
383       return _bndBox;
384     }
385     __IntCurvesFace_Intersector* GetCurveFaceIntersector()
386     {
387       if ( !_surfaceInt )
388       {
389         _surfaceInt = new __IntCurvesFace_Intersector( _face, Precision::PConfusion() );
390         _bndBox     = _surfaceInt->Bounding();
391         if ( _bndBox.IsVoid() )
392           BRepBndLib::Add (_face, _bndBox);
393       }
394       return _surfaceInt;
395     }
396     bool IsThreadSafe(set< const Standard_Transient* >& noSafeTShapes) const;
397   };
398   // --------------------------------------------------------------------------
399   /*!
400    * \brief Intersector of a surface with a GridLine
401    */
402   struct FaceLineIntersector
403   {
404     double      _tol;
405     double      _u, _v, _w; // params on the face and the line
406     Transition  _transition; // transition of at intersection (see IntCurveSurface.cdl)
407     Transition  _transIn, _transOut; // IN and OUT transitions depending of face orientation
408
409     gp_Pln      _plane;
410     gp_Cylinder _cylinder;
411     gp_Cone     _cone;
412     gp_Sphere   _sphere;
413     gp_Torus    _torus;
414     __IntCurvesFace_Intersector* _surfaceInt;
415
416     vector< F_IntersectPoint > _intPoints;
417
418     void IntersectWithPlane   (const GridLine& gridLine);
419     void IntersectWithCylinder(const GridLine& gridLine);
420     void IntersectWithCone    (const GridLine& gridLine);
421     void IntersectWithSphere  (const GridLine& gridLine);
422     void IntersectWithTorus   (const GridLine& gridLine);
423     void IntersectWithSurface (const GridLine& gridLine);
424
425     bool UVIsOnFace() const;
426     void addIntPoint(const bool toClassify=true);
427     bool isParamOnLineOK( const double linLength )
428     {
429       return -_tol < _w && _w < linLength + _tol;
430     }
431     FaceLineIntersector():_surfaceInt(0) {}
432     ~FaceLineIntersector() { if (_surfaceInt ) delete _surfaceInt; _surfaceInt = 0; }
433   };
434   // --------------------------------------------------------------------------
435   /*!
436    * \brief Class representing topology of the hexahedron and creating a mesh
437    *        volume basing on analysis of hexahedron intersection with geometry
438    */
439   class Hexahedron
440   {
441     // --------------------------------------------------------------------------------
442     struct _Face;
443     struct _Link;
444     // --------------------------------------------------------------------------------
445     struct _Node //!< node either at a hexahedron corner or at intersection
446     {
447       const SMDS_MeshNode*       _node; // mesh node at hexahedron corner
448       const B_IntersectPoint* _intPoint;
449       bool                _isUsedInFace;
450
451       _Node(const SMDS_MeshNode* n=0, const B_IntersectPoint* ip=0)
452         :_node(n), _intPoint(ip), _isUsedInFace(0) {} 
453       const SMDS_MeshNode*    Node() const
454       { return ( _intPoint && _intPoint->_node ) ? _intPoint->_node : _node; }
455       const F_IntersectPoint* FaceIntPnt() const
456       { return static_cast< const F_IntersectPoint* >( _intPoint ); }
457       const E_IntersectPoint* EdgeIntPnt() const
458       { return static_cast< const E_IntersectPoint* >( _intPoint ); }
459       void Add( const E_IntersectPoint* ip )
460       {
461         if ( !_intPoint ) {
462           _intPoint = ip;
463         }
464         else if ( !_intPoint->_node ) {
465           ip->Add( _intPoint->_faceIDs );
466           _intPoint = ip;
467         }
468         else  {
469           _intPoint->Add( ip->_faceIDs );
470         }
471       }
472       int IsLinked( const B_IntersectPoint* other,
473                     int                     avoidFace=-1 ) const // returns id of a common face
474       {
475         return _intPoint ? _intPoint->HasCommonFace( other, avoidFace ) : 0;
476       }
477       bool IsOnFace( int faceID ) const // returns true if faceID is found
478       {
479         return _intPoint ? _intPoint->IsOnFace( faceID ) : false;
480       }
481       gp_Pnt Point() const
482       {
483         if ( const SMDS_MeshNode* n = Node() )
484           return SMESH_TNodeXYZ( n );
485         if ( const E_IntersectPoint* eip =
486              dynamic_cast< const E_IntersectPoint* >( _intPoint ))
487           return eip->_point;
488         return gp_Pnt( 1e100, 0, 0 );
489       }
490     };
491     // --------------------------------------------------------------------------------
492     struct _Link // link connecting two _Node's
493     {
494       _Node* _nodes[2];
495       vector< _Node > _intNodes; // _Node's at GridLine intersections
496       vector< _Link > _splits;
497       vector< _Face*> _faces;
498     };
499     // --------------------------------------------------------------------------------
500     struct _OrientedLink
501     {
502       _Link* _link;
503       bool   _reverse;
504       _OrientedLink( _Link* link=0, bool reverse=false ): _link(link), _reverse(reverse) {}
505       void Reverse() { _reverse = !_reverse; }
506       int NbResultLinks() const { return _link->_splits.size(); }
507       _OrientedLink ResultLink(int i) const
508       {
509         return _OrientedLink(&_link->_splits[_reverse ? NbResultLinks()-i-1 : i],_reverse);
510       }
511       _Node* FirstNode() const { return _link->_nodes[ _reverse ]; }
512       _Node* LastNode()  const { return _link->_nodes[ !_reverse ]; }
513       operator bool() const { return _link; }
514       vector< TGeomID > GetNotUsedFace(const set<TGeomID>& usedIDs ) const // returns supporting FACEs
515       {
516         vector< TGeomID > faces;
517         const B_IntersectPoint *ip0, *ip1;
518         if (( ip0 = _link->_nodes[0]->_intPoint ) &&
519             ( ip1 = _link->_nodes[1]->_intPoint ))
520         {
521           for ( size_t i = 0; i < ip0->_faceIDs.size(); ++i )
522             if ( ip1->IsOnFace ( ip0->_faceIDs[i] ) &&
523                  !usedIDs.count( ip0->_faceIDs[i] ) )
524               faces.push_back( ip0->_faceIDs[i] );
525         }
526         return faces;
527       }
528       bool HasEdgeNodes() const
529       {
530         return ( dynamic_cast< const E_IntersectPoint* >( _link->_nodes[0]->_intPoint ) ||
531                  dynamic_cast< const E_IntersectPoint* >( _link->_nodes[1]->_intPoint ));
532       }
533     };
534     // --------------------------------------------------------------------------------
535     struct _Face
536     {
537       vector< _OrientedLink > _links;       // links on GridLine's
538       vector< _Link >         _polyLinks;   // links added to close a polygonal face
539       vector< _Node >         _edgeNodes;   // nodes at intersection with EDGEs
540     };
541     // --------------------------------------------------------------------------------
542     struct _volumeDef // holder of nodes of a volume mesh element
543     {
544       //vector< const SMDS_MeshNode* > _nodes;
545       vector< _Node* > _nodes;
546       vector< int >    _quantities;
547       typedef boost::shared_ptr<_volumeDef> Ptr;
548       void set( const vector< _Node* >& nodes,
549                 const vector< int >&    quant = vector< int >() )
550       { _nodes = nodes; _quantities = quant; }
551       // static Ptr New( const vector< const SMDS_MeshNode* >& nodes,
552       //                 const vector< int > quant = vector< int >() )
553       // {
554       //   _volumeDef* def = new _volumeDef;
555       //   def->_nodes = nodes;
556       //   def->_quantities = quant;
557       //   return Ptr( def );
558       // }
559     };
560
561     // topology of a hexahedron
562     int   _nodeShift[8];
563     _Node _hexNodes [8];
564     _Link _hexLinks [12];
565     _Face _hexQuads [6];
566
567     // faces resulted from hexahedron intersection
568     vector< _Face > _polygons;
569
570     // intresections with EDGEs
571     vector< const E_IntersectPoint* > _edgeIntPnts;
572
573     // nodes inside the hexahedron (at VERTEXes)
574     vector< _Node > _vertexNodes;
575
576     // computed volume elements
577     //vector< _volumeDef::Ptr > _volumeDefs;
578     _volumeDef _volumeDefs;
579
580     Grid*       _grid;
581     double      _sizeThreshold, _sideLength[3];
582     int         _nbCornerNodes, _nbIntNodes, _nbBndNodes;
583     int         _origNodeInd; // index of _hexNodes[0] node within the _grid
584     size_t      _i,_j,_k;
585
586   public:
587     Hexahedron(const double sizeThreshold, Grid* grid);
588     int MakeElements(SMESH_MesherHelper&                      helper,
589                      const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap);
590     void ComputeElements();
591     void Init() { init( _i, _j, _k ); }
592
593   private:
594     Hexahedron(const Hexahedron& other );
595     void init( size_t i, size_t j, size_t k );
596     void init( size_t i );
597     void addEdges(SMESH_MesherHelper&                      helper,
598                   vector< Hexahedron* >&                   intersectedHex,
599                   const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap);
600     gp_Pnt findIntPoint( double u1, double proj1, double u2, double proj2,
601                          double proj, BRepAdaptor_Curve& curve,
602                          const gp_XYZ& axis, const gp_XYZ& origin );
603     int  getEntity( const E_IntersectPoint* ip, int* facets, int& sub );
604     bool addIntersection( const E_IntersectPoint& ip,
605                           vector< Hexahedron* >&  hexes,
606                           int ijk[], int dIJK[] );
607     bool findChain( _Node* n1, _Node* n2, _Face& quad, vector<_Node*>& chainNodes );
608     bool closePolygon( _Face* polygon, vector<_Node*>& chainNodes ) const;
609     int  addElements(SMESH_MesherHelper& helper);
610     bool is1stNodeOut( _Link& link ) const;
611     bool isInHole() const;
612     bool checkPolyhedronSize() const;
613     bool addHexa ();
614     bool addTetra();
615     bool addPenta();
616     bool addPyra ();
617     bool debugDumpLink( _Link* link );
618     _Node* FindEqualNode( vector< _Node >&        nodes,
619                           const E_IntersectPoint* ip,
620                           const double            tol2 )
621     {
622       for ( size_t i = 0; i < nodes.size(); ++i )
623         if ( nodes[i].Point().SquareDistance( ip->_point ) <= tol2 )
624           return & nodes[i];
625       return 0;
626     }
627   };
628
629 #ifdef WITH_TBB
630   // --------------------------------------------------------------------------
631   /*!
632    * \brief Hexahedron computing volumes in one thread
633    */
634   struct ParallelHexahedron
635   {
636     vector< Hexahedron* >& _hexVec;
637     vector<int>&           _index;
638     ParallelHexahedron( vector< Hexahedron* >& hv, vector<int>& ind): _hexVec(hv), _index(ind) {}
639     void operator() ( const tbb::blocked_range<size_t>& r ) const
640     {
641       for ( size_t i = r.begin(); i != r.end(); ++i )
642         if ( Hexahedron* hex = _hexVec[ _index[i]] )
643           hex->ComputeElements();
644     }
645   };
646   // --------------------------------------------------------------------------
647   /*!
648    * \brief Structure intersecting certain nb of faces with GridLine's in one thread
649    */
650   struct ParallelIntersector
651   {
652     vector< FaceGridIntersector >& _faceVec;
653     ParallelIntersector( vector< FaceGridIntersector >& faceVec): _faceVec(faceVec){}
654     void operator() ( const tbb::blocked_range<size_t>& r ) const
655     {
656       for ( size_t i = r.begin(); i != r.end(); ++i )
657         _faceVec[i].Intersect();
658     }
659   };
660 #endif
661
662   //=============================================================================
663   // Implementation of internal utils
664   //=============================================================================
665   /*!
666    * \brief adjust \a i to have \a val between values[i] and values[i+1]
667    */
668   inline void locateValue( int & i, double val, const vector<double>& values,
669                            int& di, double tol )
670   {
671     //val += values[0]; // input \a val is measured from 0.
672     if ( i > values.size()-2 )
673       i = values.size()-2;
674     else
675       while ( i+2 < values.size() && val > values[ i+1 ])
676         ++i;
677     while ( i > 0 && val < values[ i ])
678       --i;
679
680     if ( i > 0 && val - values[ i ] < tol )
681       di = -1;
682     else if ( i+2 < values.size() && values[ i+1 ] - val < tol )
683       di = 1;
684     else
685       di = 0;
686   }
687   //=============================================================================
688   /*
689    * Remove coincident intersection points
690    */
691   void GridLine::RemoveExcessIntPoints( const double tol )
692   {
693     if ( _intPoints.size() < 2 ) return;
694
695     set< Transition > tranSet;
696     multiset< F_IntersectPoint >::iterator ip1, ip2 = _intPoints.begin();
697     while ( ip2 != _intPoints.end() )
698     {
699       tranSet.clear();
700       ip1 = ip2++;
701       while ( ip2 != _intPoints.end() && ip2->_paramOnLine - ip1->_paramOnLine <= tol )
702       {
703         tranSet.insert( ip1->_transition );
704         tranSet.insert( ip2->_transition );
705         ip2->Add( ip1->_faceIDs );
706         _intPoints.erase( ip1 );
707         ip1 = ip2++;
708       }
709       if ( tranSet.size() > 1 ) // points with different transition coincide
710       {
711         bool isIN  = tranSet.count( Trans_IN );
712         bool isOUT = tranSet.count( Trans_OUT );
713         if ( isIN && isOUT )
714           (*ip1)._transition = Trans_TANGENT;
715         else
716           (*ip1)._transition = isIN ? Trans_IN : Trans_OUT;
717       }
718     }
719   }
720   //================================================================================
721   /*
722    * Return "is OUT" state for nodes before the given intersection point
723    */
724   bool GridLine::GetIsOutBefore( multiset< F_IntersectPoint >::iterator ip, bool prevIsOut )
725   {
726     if ( ip->_transition == Trans_IN )
727       return true;
728     if ( ip->_transition == Trans_OUT )
729       return false;
730     if ( ip->_transition == Trans_APEX )
731     {
732       // singularity point (apex of a cone)
733       if ( _intPoints.size() == 1 || ip == _intPoints.begin() )
734         return true;
735       multiset< F_IntersectPoint >::iterator ipBef = ip, ipAft = ++ip;
736       if ( ipAft == _intPoints.end() )
737         return false;
738       --ipBef;
739       if ( ipBef->_transition != ipAft->_transition )
740         return ( ipBef->_transition == Trans_OUT );
741       return ( ipBef->_transition != Trans_OUT );
742     }
743     // _transition == Trans_TANGENT
744     return !prevIsOut;
745   }
746   //================================================================================
747   /*
748    * Adds face IDs
749    */
750   void B_IntersectPoint::Add( const vector< TGeomID >& fIDs,
751                               const SMDS_MeshNode*     n) const
752   {
753     if ( _faceIDs.empty() )
754       _faceIDs = fIDs;
755     else
756       for ( size_t i = 0; i < fIDs.size(); ++i )
757       {
758         vector< TGeomID >::iterator it =
759           std::find( _faceIDs.begin(), _faceIDs.end(), fIDs[i] );
760         if ( it == _faceIDs.end() )
761           _faceIDs.push_back( fIDs[i] );
762       }
763     if ( !_node )
764       _node = n;
765   }
766   //================================================================================
767   /*
768    * Returns index of a common face if any, else zero
769    */
770   int B_IntersectPoint::HasCommonFace( const B_IntersectPoint * other, int avoidFace ) const
771   {
772     if ( other )
773       for ( size_t i = 0; i < other->_faceIDs.size(); ++i )
774         if ( avoidFace != other->_faceIDs[i] &&
775              IsOnFace   ( other->_faceIDs[i] ))
776           return other->_faceIDs[i];
777     return 0;
778   }
779   //================================================================================
780   /*
781    * Returns \c true if \a faceID in in this->_faceIDs
782    */
783   bool B_IntersectPoint::IsOnFace( int faceID ) const // returns true if faceID is found
784   {
785     vector< TGeomID >::const_iterator it =
786       std::find( _faceIDs.begin(), _faceIDs.end(), faceID );
787     return ( it != _faceIDs.end() );
788   }
789   //================================================================================
790   /*
791    * Return an iterator on GridLine's in a given direction
792    */
793   LineIndexer Grid::GetLineIndexer(size_t iDir) const
794   {
795     const size_t indices[] = { 1,2,0, 0,2,1, 0,1,2 };
796     const string s      [] = { "X", "Y", "Z" };
797     LineIndexer li( _coords[0].size(),  _coords[1].size(),    _coords[2].size(),
798                     indices[iDir*3],    indices[iDir*3+1],    indices[iDir*3+2],
799                     s[indices[iDir*3]], s[indices[iDir*3+1]], s[indices[iDir*3+2]]);
800     return li;
801   }
802   //=============================================================================
803   /*
804    * Creates GridLine's of the grid
805    */
806   void Grid::SetCoordinates(const vector<double>& xCoords,
807                             const vector<double>& yCoords,
808                             const vector<double>& zCoords,
809                             const double*         axesDirs,
810                             const Bnd_Box&        shapeBox)
811   {
812     _coords[0] = xCoords;
813     _coords[1] = yCoords;
814     _coords[2] = zCoords;
815
816     _axes[0].SetCoord( axesDirs[0],
817                        axesDirs[1],
818                        axesDirs[2]);
819     _axes[1].SetCoord( axesDirs[3],
820                        axesDirs[4],
821                        axesDirs[5]);
822     _axes[2].SetCoord( axesDirs[6],
823                        axesDirs[7],
824                        axesDirs[8]);
825     _axes[0].Normalize();
826     _axes[1].Normalize();
827     _axes[2].Normalize();
828
829     _invB.SetCols( _axes[0], _axes[1], _axes[2] );
830     _invB.Invert();
831
832     // _isOrthogonalAxes = ( Abs( _axes[0] * _axes[1] ) < 1e-20 &&
833     //                       Abs( _axes[1] * _axes[2] ) < 1e-20 &&
834     //                       Abs( _axes[2] * _axes[0] ) < 1e-20 );
835
836     // compute tolerance
837     _minCellSize = Precision::Infinite();
838     for ( int iDir = 0; iDir < 3; ++iDir ) // loop on 3 line directions
839     {
840       for ( size_t i = 1; i < _coords[ iDir ].size(); ++i )
841       {
842         double cellLen = _coords[ iDir ][ i ] - _coords[ iDir ][ i-1 ];
843         if ( cellLen < _minCellSize )
844           _minCellSize = cellLen;
845       }
846     }
847     if ( _minCellSize < Precision::Confusion() )
848       throw SMESH_ComputeError (COMPERR_ALGO_FAILED,
849                                 SMESH_Comment("Too small cell size: ") << _minCellSize );
850     _tol = _minCellSize / 1000.;
851
852     // attune grid extremities to shape bounding box
853
854     double sP[6]; // aXmin, aYmin, aZmin, aXmax, aYmax, aZmax
855     shapeBox.Get(sP[0],sP[1],sP[2],sP[3],sP[4],sP[5]);
856     double* cP[6] = { &_coords[0].front(), &_coords[1].front(), &_coords[2].front(),
857                       &_coords[0].back(),  &_coords[1].back(),  &_coords[2].back() };
858     for ( int i = 0; i < 6; ++i )
859       if ( fabs( sP[i] - *cP[i] ) < _tol )
860         *cP[i] = sP[i];// + _tol/1000. * ( i < 3 ? +1 : -1 );
861
862     for ( int iDir = 0; iDir < 3; ++iDir )
863     {
864       if ( _coords[iDir][0] - sP[iDir] > _tol )
865       {
866         _minCellSize = Min( _minCellSize, _coords[iDir][0] - sP[iDir] );
867         _coords[iDir].insert( _coords[iDir].begin(), sP[iDir] + _tol/1000.);
868       }
869       if ( sP[iDir+3] - _coords[iDir].back() > _tol  )
870       {
871         _minCellSize = Min( _minCellSize, sP[iDir+3] - _coords[iDir].back() );
872         _coords[iDir].push_back( sP[iDir+3] - _tol/1000.);
873       }
874     }
875     _tol = _minCellSize / 1000.;
876
877     _origin = ( _coords[0][0] * _axes[0] +
878                 _coords[1][0] * _axes[1] +
879                 _coords[2][0] * _axes[2] );
880
881     // create lines
882     for ( int iDir = 0; iDir < 3; ++iDir ) // loop on 3 line directions
883     {
884       LineIndexer li = GetLineIndexer( iDir );
885       _lines[iDir].resize( li.NbLines() );
886       double len = _coords[ iDir ].back() - _coords[iDir].front();
887       for ( ; li.More(); ++li )
888       {
889         GridLine& gl = _lines[iDir][ li.LineIndex() ];
890         gl._line.SetLocation( _coords[0][li.I()] * _axes[0] +
891                               _coords[1][li.J()] * _axes[1] +
892                               _coords[2][li.K()] * _axes[2] );
893         gl._line.SetDirection( _axes[ iDir ]);
894         gl._length = len;
895       }
896     }
897   }
898   //================================================================================
899   /*
900    * Computes coordinates of a point in the grid CS
901    */
902   void Grid::ComputeUVW(const gp_XYZ& P, double UVW[3])
903   {
904     // gp_XYZ p = P - _origin;
905     // UVW[ 0 ] = p.X() * _invB( 1, 1 ) + p.Y() * _invB( 1, 2 ) + p.Z() * _invB( 1, 3 );
906     // UVW[ 1 ] = p.X() * _invB( 2, 1 ) + p.Y() * _invB( 2, 2 ) + p.Z() * _invB( 2, 3 );
907     // UVW[ 2 ] = p.X() * _invB( 3, 1 ) + p.Y() * _invB( 3, 2 ) + p.Z() * _invB( 3, 3 );
908     // UVW[ 0 ] += _coords[0][0];
909     // UVW[ 1 ] += _coords[1][0];
910     // UVW[ 2 ] += _coords[2][0];
911     gp_XYZ p = P * _invB;
912     p.Coord( UVW[0], UVW[1], UVW[2] );
913   }
914   //================================================================================
915   /*
916    * Creates all nodes
917    */
918   void Grid::ComputeNodes(SMESH_MesherHelper& helper)
919   {
920     // state of each node of the grid relative to the geometry
921     const size_t nbGridNodes = _coords[0].size() * _coords[1].size() * _coords[2].size();
922     vector< bool > isNodeOut( nbGridNodes, false );
923     _nodes.resize( nbGridNodes, 0 );
924     _gridIntP.resize( nbGridNodes, NULL );
925
926     for ( int iDir = 0; iDir < 3; ++iDir ) // loop on 3 line directions
927     {
928       LineIndexer li = GetLineIndexer( iDir );
929
930       // find out a shift of node index while walking along a GridLine in this direction
931       li.SetIndexOnLine( 0 );
932       size_t nIndex0 = NodeIndex( li.I(), li.J(), li.K() );
933       li.SetIndexOnLine( 1 );
934       const size_t nShift = NodeIndex( li.I(), li.J(), li.K() ) - nIndex0;
935       
936       const vector<double> & coords = _coords[ iDir ];
937       for ( ; li.More(); ++li ) // loop on lines in iDir
938       {
939         li.SetIndexOnLine( 0 );
940         nIndex0 = NodeIndex( li.I(), li.J(), li.K() );
941
942         GridLine& line = _lines[ iDir ][ li.LineIndex() ];
943         const gp_XYZ lineLoc = line._line.Location().XYZ();
944         const gp_XYZ lineDir = line._line.Direction().XYZ();
945         line.RemoveExcessIntPoints( _tol );
946         multiset< F_IntersectPoint >& intPnts = _lines[ iDir ][ li.LineIndex() ]._intPoints;
947         multiset< F_IntersectPoint >::iterator ip = intPnts.begin();
948
949         bool isOut = true;
950         const double* nodeCoord = & coords[0];
951         const double* coord0    = nodeCoord;
952         const double* coordEnd  = coord0 + coords.size();
953         double nodeParam = 0;
954         for ( ; ip != intPnts.end(); ++ip )
955         {
956           // set OUT state or just skip IN nodes before ip
957           if ( nodeParam < ip->_paramOnLine - _tol )
958           {
959             isOut = line.GetIsOutBefore( ip, isOut );
960
961             while ( nodeParam < ip->_paramOnLine - _tol )
962             {
963               if ( isOut )
964                 isNodeOut[ nIndex0 + nShift * ( nodeCoord-coord0 ) ] = isOut;
965               if ( ++nodeCoord <  coordEnd )
966                 nodeParam = *nodeCoord - *coord0;
967               else
968                 break;
969             }
970             if ( nodeCoord == coordEnd ) break;
971           }
972           // create a mesh node on a GridLine at ip if it does not coincide with a grid node
973           if ( nodeParam > ip->_paramOnLine + _tol )
974           {
975             // li.SetIndexOnLine( 0 );
976             // double xyz[3] = { _coords[0][ li.I() ], _coords[1][ li.J() ], _coords[2][ li.K() ]};
977             // xyz[ li._iConst ] += ip->_paramOnLine;
978             gp_XYZ xyz = lineLoc + ip->_paramOnLine * lineDir;
979             ip->_node = helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() );
980             ip->_indexOnLine = nodeCoord-coord0-1;
981           }
982           // create a mesh node at ip concident with a grid node
983           else
984           {
985             int nodeIndex = nIndex0 + nShift * ( nodeCoord-coord0 );
986             if ( !_nodes[ nodeIndex ] )
987             {
988               //li.SetIndexOnLine( nodeCoord-coord0 );
989               //double xyz[3] = { _coords[0][ li.I() ], _coords[1][ li.J() ], _coords[2][ li.K() ]};
990               gp_XYZ xyz = lineLoc + nodeParam * lineDir;
991               _nodes   [ nodeIndex ] = helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() );
992               _gridIntP[ nodeIndex ] = & * ip;
993             }
994             if ( _gridIntP[ nodeIndex ] )
995               _gridIntP[ nodeIndex ]->Add( ip->_faceIDs );
996             else
997               _gridIntP[ nodeIndex ] = & * ip;
998             // ip->_node        = _nodes[ nodeIndex ]; -- to differ from ip on links
999             ip->_indexOnLine = nodeCoord-coord0;
1000             if ( ++nodeCoord < coordEnd )
1001               nodeParam = *nodeCoord - *coord0;
1002           }
1003         }
1004         // set OUT state to nodes after the last ip
1005         for ( ; nodeCoord < coordEnd; ++nodeCoord )
1006           isNodeOut[ nIndex0 + nShift * ( nodeCoord-coord0 ) ] = true;
1007       }
1008     }
1009
1010     // Create mesh nodes at !OUT nodes of the grid
1011
1012     for ( size_t z = 0; z < _coords[2].size(); ++z )
1013       for ( size_t y = 0; y < _coords[1].size(); ++y )
1014         for ( size_t x = 0; x < _coords[0].size(); ++x )
1015         {
1016           size_t nodeIndex = NodeIndex( x, y, z );
1017           if ( !isNodeOut[ nodeIndex ] && !_nodes[ nodeIndex] )
1018           {
1019             //_nodes[ nodeIndex ] = helper.AddNode( _coords[0][x], _coords[1][y], _coords[2][z] );
1020             gp_XYZ xyz = ( _coords[0][x] * _axes[0] +
1021                            _coords[1][y] * _axes[1] +
1022                            _coords[2][z] * _axes[2] );
1023             _nodes[ nodeIndex ] = helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() );
1024           }
1025         }
1026
1027 #ifdef _MY_DEBUG_
1028     // check validity of transitions
1029     const char* trName[] = { "TANGENT", "IN", "OUT", "APEX" };
1030     for ( int iDir = 0; iDir < 3; ++iDir ) // loop on 3 line directions
1031     {
1032       LineIndexer li = GetLineIndexer( iDir );
1033       for ( ; li.More(); ++li )
1034       {
1035         multiset< F_IntersectPoint >& intPnts = _lines[ iDir ][ li.LineIndex() ]._intPoints;
1036         if ( intPnts.empty() ) continue;
1037         if ( intPnts.size() == 1 )
1038         {
1039           if ( intPnts.begin()->_transition != Trans_TANGENT &&
1040                intPnts.begin()->_transition != Trans_APEX )
1041           throw SMESH_ComputeError (COMPERR_ALGO_FAILED,
1042                                     SMESH_Comment("Wrong SOLE transition of GridLine (")
1043                                     << li._curInd[li._iVar1] << ", " << li._curInd[li._iVar2]
1044                                     << ") along " << li._nameConst
1045                                     << ": " << trName[ intPnts.begin()->_transition] );
1046         }
1047         else
1048         {
1049           if ( intPnts.begin()->_transition == Trans_OUT )
1050             throw SMESH_ComputeError (COMPERR_ALGO_FAILED,
1051                                       SMESH_Comment("Wrong START transition of GridLine (")
1052                                       << li._curInd[li._iVar1] << ", " << li._curInd[li._iVar2]
1053                                       << ") along " << li._nameConst
1054                                       << ": " << trName[ intPnts.begin()->_transition ]);
1055           if ( intPnts.rbegin()->_transition == Trans_IN )
1056             throw SMESH_ComputeError (COMPERR_ALGO_FAILED,
1057                                       SMESH_Comment("Wrong END transition of GridLine (")
1058                                       << li._curInd[li._iVar1] << ", " << li._curInd[li._iVar2]
1059                                       << ") along " << li._nameConst
1060                                     << ": " << trName[ intPnts.rbegin()->_transition ]);
1061         }
1062       }
1063     }
1064 #endif
1065   }
1066
1067   //=============================================================================
1068   /*
1069    * Checks if the face is encosed by the grid
1070    */
1071   bool FaceGridIntersector::IsInGrid(const Bnd_Box& gridBox)
1072   {
1073     // double x0,y0,z0, x1,y1,z1;
1074     // const Bnd_Box& faceBox = GetFaceBndBox();
1075     // faceBox.Get(x0,y0,z0, x1,y1,z1);
1076
1077     // if ( !gridBox.IsOut( gp_Pnt( x0,y0,z0 )) &&
1078     //      !gridBox.IsOut( gp_Pnt( x1,y1,z1 )))
1079     //   return true;
1080
1081     // double X0,Y0,Z0, X1,Y1,Z1;
1082     // gridBox.Get(X0,Y0,Z0, X1,Y1,Z1);
1083     // double faceP[6] = { x0,y0,z0, x1,y1,z1 };
1084     // double gridP[6] = { X0,Y0,Z0, X1,Y1,Z1 };
1085     // gp_Dir axes[3]  = { gp::DX(), gp::DY(), gp::DZ() };
1086     // for ( int iDir = 0; iDir < 6; ++iDir )
1087     // {
1088     //   if ( iDir < 3  && gridP[ iDir ] <= faceP[ iDir ] ) continue;
1089     //   if ( iDir >= 3 && gridP[ iDir ] >= faceP[ iDir ] ) continue;
1090
1091     //   // check if the face intersects a side of a gridBox
1092
1093     //   gp_Pnt p = iDir < 3 ? gp_Pnt( X0,Y0,Z0 ) : gp_Pnt( X1,Y1,Z1 );
1094     //   gp_Ax1 norm( p, axes[ iDir % 3 ] );
1095     //   if ( iDir < 3 ) norm.Reverse();
1096
1097     //   gp_XYZ O = norm.Location().XYZ(), N = norm.Direction().XYZ();
1098
1099     //   TopLoc_Location loc = _face.Location();
1100     //   Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(_face,loc);
1101     //   if ( !aPoly.IsNull() )
1102     //   {
1103     //     if ( !loc.IsIdentity() )
1104     //     {
1105     //       norm.Transform( loc.Transformation().Inverted() );
1106     //       O = norm.Location().XYZ(), N = norm.Direction().XYZ();
1107     //     }
1108     //     const double deflection = aPoly->Deflection();
1109
1110     //     const TColgp_Array1OfPnt& nodes = aPoly->Nodes();
1111     //     for ( int i = nodes.Lower(); i <= nodes.Upper(); ++i )
1112     //       if (( nodes( i ).XYZ() - O ) * N > _grid->_tol + deflection )
1113     //         return false;
1114     //   }
1115     //   else
1116     //   {
1117     //     BRepAdaptor_Surface surf( _face );
1118     //     double u0, u1, v0, v1, du, dv, u, v;
1119     //     BRepTools::UVBounds( _face, u0, u1, v0, v1);
1120     //     if ( surf.GetType() == GeomAbs_Plane ) {
1121     //       du = u1 - u0, dv = v1 - v0;
1122     //     }
1123     //     else {
1124     //       du = surf.UResolution( _grid->_minCellSize / 10. );
1125     //       dv = surf.VResolution( _grid->_minCellSize / 10. );
1126     //     }
1127     //     for ( u = u0, v = v0; u <= u1 && v <= v1; u += du, v += dv )
1128     //     {
1129     //       gp_Pnt p = surf.Value( u, v );
1130     //       if (( p.XYZ() - O ) * N > _grid->_tol )
1131     //       {
1132     //         TopAbs_State state = GetCurveFaceIntersector()->ClassifyUVPoint(gp_Pnt2d( u, v ));
1133     //         if ( state == TopAbs_IN || state == TopAbs_ON )
1134     //           return false;
1135     //       }
1136     //     }
1137     //   }
1138     // }
1139     return true;
1140   }
1141   //=============================================================================
1142   /*
1143    * Intersects TopoDS_Face with all GridLine's
1144    */
1145   void FaceGridIntersector::Intersect()
1146   {
1147     FaceLineIntersector intersector;
1148     intersector._surfaceInt = GetCurveFaceIntersector();
1149     intersector._tol        = _grid->_tol;
1150     intersector._transOut   = _face.Orientation() == TopAbs_REVERSED ? Trans_IN : Trans_OUT;
1151     intersector._transIn    = _face.Orientation() == TopAbs_REVERSED ? Trans_OUT : Trans_IN;
1152
1153     typedef void (FaceLineIntersector::* PIntFun )(const GridLine& gridLine);
1154     PIntFun interFunction;
1155
1156     BRepAdaptor_Surface surf( _face );
1157     switch ( surf.GetType() ) {
1158     case GeomAbs_Plane:
1159       intersector._plane = surf.Plane();
1160       interFunction = &FaceLineIntersector::IntersectWithPlane;
1161       break;
1162     case GeomAbs_Cylinder:
1163       intersector._cylinder = surf.Cylinder();
1164       interFunction = &FaceLineIntersector::IntersectWithCylinder;
1165       break;
1166     case GeomAbs_Cone:
1167       intersector._cone = surf.Cone();
1168       interFunction = &FaceLineIntersector::IntersectWithCone;
1169       break;
1170     case GeomAbs_Sphere:
1171       intersector._sphere = surf.Sphere();
1172       interFunction = &FaceLineIntersector::IntersectWithSphere;
1173       break;
1174     case GeomAbs_Torus:
1175       intersector._torus = surf.Torus();
1176       interFunction = &FaceLineIntersector::IntersectWithTorus;
1177       break;
1178     default:
1179       interFunction = &FaceLineIntersector::IntersectWithSurface;
1180     }
1181
1182     _intersections.clear();
1183     for ( int iDir = 0; iDir < 3; ++iDir ) // loop on 3 line directions
1184     {
1185       if ( surf.GetType() == GeomAbs_Plane )
1186       {
1187         // check if all lines in this direction are parallel to a plane
1188         if ( intersector._plane.Axis().IsNormal( _grid->_lines[iDir][0]._line.Position(),
1189                                                  Precision::Angular()))
1190           continue;
1191         // find out a transition, that is the same for all lines of a direction
1192         gp_Dir plnNorm = intersector._plane.Axis().Direction();
1193         gp_Dir lineDir = _grid->_lines[iDir][0]._line.Direction();
1194         intersector._transition =
1195           ( plnNorm * lineDir < 0 ) ? intersector._transIn : intersector._transOut;
1196       }
1197       if ( surf.GetType() == GeomAbs_Cylinder )
1198       {
1199         // check if all lines in this direction are parallel to a cylinder
1200         if ( intersector._cylinder.Axis().IsParallel( _grid->_lines[iDir][0]._line.Position(),
1201                                                       Precision::Angular()))
1202           continue;
1203       }
1204
1205       // intersect the grid lines with the face
1206       for ( size_t iL = 0; iL < _grid->_lines[iDir].size(); ++iL )
1207       {
1208         GridLine& gridLine = _grid->_lines[iDir][iL];
1209         if ( _bndBox.IsOut( gridLine._line )) continue;
1210
1211         intersector._intPoints.clear();
1212         (intersector.*interFunction)( gridLine ); // <- intersection with gridLine
1213         for ( size_t i = 0; i < intersector._intPoints.size(); ++i )
1214           _intersections.push_back( make_pair( &gridLine, intersector._intPoints[i] ));
1215       }
1216     }
1217   }
1218   //================================================================================
1219   /*
1220    * Return true if (_u,_v) is on the face
1221    */
1222   bool FaceLineIntersector::UVIsOnFace() const
1223   {
1224     TopAbs_State state = _surfaceInt->ClassifyUVPoint(gp_Pnt2d( _u,_v ));
1225     return ( state == TopAbs_IN || state == TopAbs_ON );
1226   }
1227   //================================================================================
1228   /*
1229    * Store an intersection if it is IN or ON the face
1230    */
1231   void FaceLineIntersector::addIntPoint(const bool toClassify)
1232   {
1233     if ( !toClassify || UVIsOnFace() )
1234     {
1235       F_IntersectPoint p;
1236       p._paramOnLine = _w;
1237       p._transition  = _transition;
1238       _intPoints.push_back( p );
1239     }
1240   }
1241   //================================================================================
1242   /*
1243    * Intersect a line with a plane
1244    */
1245   void FaceLineIntersector::IntersectWithPlane   (const GridLine& gridLine)
1246   {
1247     IntAna_IntConicQuad linPlane( gridLine._line, _plane, Precision::Angular());
1248     _w = linPlane.ParamOnConic(1);
1249     if ( isParamOnLineOK( gridLine._length ))
1250     {
1251       ElSLib::Parameters(_plane, linPlane.Point(1) ,_u,_v);
1252       addIntPoint();
1253     }
1254   }
1255   //================================================================================
1256   /*
1257    * Intersect a line with a cylinder
1258    */
1259   void FaceLineIntersector::IntersectWithCylinder(const GridLine& gridLine)
1260   {
1261     IntAna_IntConicQuad linCylinder( gridLine._line, _cylinder );
1262     if ( linCylinder.IsDone() && linCylinder.NbPoints() > 0 )
1263     {
1264       _w = linCylinder.ParamOnConic(1);
1265       if ( linCylinder.NbPoints() == 1 )
1266         _transition = Trans_TANGENT;
1267       else
1268         _transition = _w < linCylinder.ParamOnConic(2) ? _transIn : _transOut;
1269       if ( isParamOnLineOK( gridLine._length ))
1270       {
1271         ElSLib::Parameters(_cylinder, linCylinder.Point(1) ,_u,_v);
1272         addIntPoint();
1273       }
1274       if ( linCylinder.NbPoints() > 1 )
1275       {
1276         _w = linCylinder.ParamOnConic(2);
1277         if ( isParamOnLineOK( gridLine._length ))
1278         {
1279           ElSLib::Parameters(_cylinder, linCylinder.Point(2) ,_u,_v);
1280           _transition = ( _transition == Trans_OUT ) ? Trans_IN : Trans_OUT;
1281           addIntPoint();
1282         }
1283       }
1284     }
1285   }
1286   //================================================================================
1287   /*
1288    * Intersect a line with a cone
1289    */
1290   void FaceLineIntersector::IntersectWithCone (const GridLine& gridLine)
1291   {
1292     IntAna_IntConicQuad linCone(gridLine._line,_cone);
1293     if ( !linCone.IsDone() ) return;
1294     gp_Pnt P;
1295     gp_Vec du, dv, norm;
1296     for ( int i = 1; i <= linCone.NbPoints(); ++i )
1297     {
1298       _w = linCone.ParamOnConic( i );
1299       if ( !isParamOnLineOK( gridLine._length )) continue;
1300       ElSLib::Parameters(_cone, linCone.Point(i) ,_u,_v);
1301       if ( UVIsOnFace() )
1302       {
1303         ElSLib::D1( _u, _v, _cone, P, du, dv );
1304         norm = du ^ dv;
1305         double normSize2 = norm.SquareMagnitude();
1306         if ( normSize2 > Precision::Angular() * Precision::Angular() )
1307         {
1308           double cos = norm.XYZ() * gridLine._line.Direction().XYZ();
1309           cos /= sqrt( normSize2 );
1310           if ( cos < -Precision::Angular() )
1311             _transition = _transIn;
1312           else if ( cos > Precision::Angular() )
1313             _transition = _transOut;
1314           else
1315             _transition = Trans_TANGENT;
1316         }
1317         else
1318         {
1319           _transition = Trans_APEX;
1320         }
1321         addIntPoint( /*toClassify=*/false);
1322       }
1323     }
1324   }
1325   //================================================================================
1326   /*
1327    * Intersect a line with a sphere
1328    */
1329   void FaceLineIntersector::IntersectWithSphere  (const GridLine& gridLine)
1330   {
1331     IntAna_IntConicQuad linSphere(gridLine._line,_sphere);
1332     if ( linSphere.IsDone() && linSphere.NbPoints() > 0 )
1333     {
1334       _w = linSphere.ParamOnConic(1);
1335       if ( linSphere.NbPoints() == 1 )
1336         _transition = Trans_TANGENT;
1337       else
1338         _transition = _w < linSphere.ParamOnConic(2) ? _transIn : _transOut;
1339       if ( isParamOnLineOK( gridLine._length ))
1340       {
1341         ElSLib::Parameters(_sphere, linSphere.Point(1) ,_u,_v);
1342         addIntPoint();
1343       }
1344       if ( linSphere.NbPoints() > 1 )
1345       {
1346         _w = linSphere.ParamOnConic(2);
1347         if ( isParamOnLineOK( gridLine._length ))
1348         {
1349           ElSLib::Parameters(_sphere, linSphere.Point(2) ,_u,_v);
1350           _transition = ( _transition == Trans_OUT ) ? Trans_IN : Trans_OUT;
1351           addIntPoint();
1352         }
1353       }
1354     }
1355   }
1356   //================================================================================
1357   /*
1358    * Intersect a line with a torus
1359    */
1360   void FaceLineIntersector::IntersectWithTorus   (const GridLine& gridLine)
1361   {
1362     IntAna_IntLinTorus linTorus(gridLine._line,_torus);
1363     if ( !linTorus.IsDone()) return;
1364     gp_Pnt P;
1365     gp_Vec du, dv, norm;
1366     for ( int i = 1; i <= linTorus.NbPoints(); ++i )
1367     {
1368       _w = linTorus.ParamOnLine( i );
1369       if ( !isParamOnLineOK( gridLine._length )) continue;
1370       linTorus.ParamOnTorus( i, _u,_v );
1371       if ( UVIsOnFace() )
1372       {
1373         ElSLib::D1( _u, _v, _torus, P, du, dv );
1374         norm = du ^ dv;
1375         double normSize = norm.Magnitude();
1376         double cos = norm.XYZ() * gridLine._line.Direction().XYZ();
1377         cos /= normSize;
1378         if ( cos < -Precision::Angular() )
1379           _transition = _transIn;
1380         else if ( cos > Precision::Angular() )
1381           _transition = _transOut;
1382         else
1383           _transition = Trans_TANGENT;
1384         addIntPoint( /*toClassify=*/false);
1385       }
1386     }
1387   }
1388   //================================================================================
1389   /*
1390    * Intersect a line with a non-analytical surface
1391    */
1392   void FaceLineIntersector::IntersectWithSurface (const GridLine& gridLine)
1393   {
1394     _surfaceInt->Perform( gridLine._line, 0.0, gridLine._length );
1395     if ( !_surfaceInt->IsDone() ) return;
1396     for ( int i = 1; i <= _surfaceInt->NbPnt(); ++i )
1397     {
1398       _transition = Transition( _surfaceInt->Transition( i ) );
1399       _w = _surfaceInt->WParameter( i );
1400       addIntPoint(/*toClassify=*/false);
1401     }
1402   }
1403   //================================================================================
1404   /*
1405    * check if its face can be safely intersected in a thread
1406    */
1407   bool FaceGridIntersector::IsThreadSafe(set< const Standard_Transient* >& noSafeTShapes) const
1408   {
1409     bool isSafe = true;
1410
1411     // check surface
1412     TopLoc_Location loc;
1413     Handle(Geom_Surface) surf = BRep_Tool::Surface( _face, loc );
1414     Handle(Geom_RectangularTrimmedSurface) ts =
1415       Handle(Geom_RectangularTrimmedSurface)::DownCast( surf );
1416     while( !ts.IsNull() ) {
1417       surf = ts->BasisSurface();
1418       ts = Handle(Geom_RectangularTrimmedSurface)::DownCast(surf);
1419     }
1420     if ( surf->IsKind( STANDARD_TYPE(Geom_BSplineSurface )) ||
1421          surf->IsKind( STANDARD_TYPE(Geom_BezierSurface )))
1422       if ( !noSafeTShapes.insert((const Standard_Transient*) _face.TShape() ).second )
1423         isSafe = false;
1424
1425     double f, l;
1426     TopExp_Explorer exp( _face, TopAbs_EDGE );
1427     for ( ; exp.More(); exp.Next() )
1428     {
1429       bool edgeIsSafe = true;
1430       const TopoDS_Edge& e = TopoDS::Edge( exp.Current() );
1431       // check 3d curve
1432       {
1433         Handle(Geom_Curve) c = BRep_Tool::Curve( e, loc, f, l);
1434         if ( !c.IsNull() )
1435         {
1436           Handle(Geom_TrimmedCurve) tc = Handle(Geom_TrimmedCurve)::DownCast(c);
1437           while( !tc.IsNull() ) {
1438             c = tc->BasisCurve();
1439             tc = Handle(Geom_TrimmedCurve)::DownCast(c);
1440           }
1441           if ( c->IsKind( STANDARD_TYPE(Geom_BSplineCurve )) ||
1442                c->IsKind( STANDARD_TYPE(Geom_BezierCurve )))
1443             edgeIsSafe = false;
1444         }
1445       }
1446       // check 2d curve
1447       if ( edgeIsSafe )
1448       {
1449         Handle(Geom2d_Curve) c2 = BRep_Tool::CurveOnSurface( e, surf, loc, f, l);
1450         if ( !c2.IsNull() )
1451         {
1452           Handle(Geom2d_TrimmedCurve) tc = Handle(Geom2d_TrimmedCurve)::DownCast(c2);
1453           while( !tc.IsNull() ) {
1454             c2 = tc->BasisCurve();
1455             tc = Handle(Geom2d_TrimmedCurve)::DownCast(c2);
1456           }
1457           if ( c2->IsKind( STANDARD_TYPE(Geom2d_BSplineCurve )) ||
1458                c2->IsKind( STANDARD_TYPE(Geom2d_BezierCurve )))
1459             edgeIsSafe = false;
1460         }
1461       }
1462       if ( !edgeIsSafe && !noSafeTShapes.insert((const Standard_Transient*) e.TShape() ).second )
1463         isSafe = false;
1464     }
1465     return isSafe;
1466   }
1467   //================================================================================
1468   /*!
1469    * \brief Creates topology of the hexahedron
1470    */
1471   Hexahedron::Hexahedron(const double sizeThreshold, Grid* grid)
1472     : _grid( grid ), _sizeThreshold( sizeThreshold ), _nbIntNodes(0)
1473   {
1474     _polygons.reserve(100); // to avoid reallocation;
1475
1476     //set nodes shift within grid->_nodes from the node 000 
1477     size_t dx = _grid->NodeIndexDX();
1478     size_t dy = _grid->NodeIndexDY();
1479     size_t dz = _grid->NodeIndexDZ();
1480     size_t i000 = 0;
1481     size_t i100 = i000 + dx;
1482     size_t i010 = i000 + dy;
1483     size_t i110 = i010 + dx;
1484     size_t i001 = i000 + dz;
1485     size_t i101 = i100 + dz;
1486     size_t i011 = i010 + dz;
1487     size_t i111 = i110 + dz;
1488     _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V000 )] = i000;
1489     _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V100 )] = i100;
1490     _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V010 )] = i010;
1491     _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V110 )] = i110;
1492     _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V001 )] = i001;
1493     _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V101 )] = i101;
1494     _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V011 )] = i011;
1495     _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V111 )] = i111;
1496
1497     vector< int > idVec;
1498     // set nodes to links
1499     for ( int linkID = SMESH_Block::ID_Ex00; linkID <= SMESH_Block::ID_E11z; ++linkID )
1500     {
1501       SMESH_Block::GetEdgeVertexIDs( linkID, idVec );
1502       _Link& link = _hexLinks[ SMESH_Block::ShapeIndex( linkID )];
1503       link._nodes[0] = &_hexNodes[ SMESH_Block::ShapeIndex( idVec[0] )];
1504       link._nodes[1] = &_hexNodes[ SMESH_Block::ShapeIndex( idVec[1] )];
1505       link._intNodes.reserve( 10 ); // to avoid reallocation
1506       link._splits.reserve( 10 );
1507     }
1508
1509     // set links to faces
1510     int interlace[4] = { 0, 3, 1, 2 }; // to walk by links around a face: { u0, 1v, u1, 0v }
1511     for ( int faceID = SMESH_Block::ID_Fxy0; faceID <= SMESH_Block::ID_F1yz; ++faceID )
1512     {
1513       SMESH_Block::GetFaceEdgesIDs( faceID, idVec );
1514       _Face& quad = _hexQuads[ SMESH_Block::ShapeIndex( faceID )];
1515       bool revFace = ( faceID == SMESH_Block::ID_Fxy0 ||
1516                        faceID == SMESH_Block::ID_Fx1z ||
1517                        faceID == SMESH_Block::ID_F0yz );
1518       quad._links.resize(4);
1519       vector<_OrientedLink>::iterator         frwLinkIt = quad._links.begin();
1520       vector<_OrientedLink>::reverse_iterator revLinkIt = quad._links.rbegin();
1521       for ( int i = 0; i < 4; ++i )
1522       {
1523         bool revLink = revFace;
1524         if ( i > 1 ) // reverse links u1 and v0
1525           revLink = !revLink;
1526         _OrientedLink& link = revFace ? *revLinkIt++ : *frwLinkIt++;
1527         link = _OrientedLink( & _hexLinks[ SMESH_Block::ShapeIndex( idVec[interlace[i]] )],
1528                               revLink );
1529       }
1530     }
1531   }
1532   //================================================================================
1533   /*!
1534    * \brief Copy constructor
1535    */
1536   Hexahedron::Hexahedron( const Hexahedron& other )
1537     :_grid( other._grid ), _sizeThreshold( other._sizeThreshold ), _nbIntNodes(0)
1538   {
1539     _polygons.reserve(100); // to avoid reallocation;
1540
1541     for ( int i = 0; i < 8; ++i )
1542       _nodeShift[i] = other._nodeShift[i];
1543
1544     for ( int i = 0; i < 12; ++i )
1545     {
1546       const _Link& srcLink = other._hexLinks[ i ];
1547       _Link&       tgtLink = this->_hexLinks[ i ];
1548       tgtLink._nodes[0] = _hexNodes + ( srcLink._nodes[0] - other._hexNodes );
1549       tgtLink._nodes[1] = _hexNodes + ( srcLink._nodes[1] - other._hexNodes );
1550       tgtLink._intNodes.reserve( 10 ); // to avoid reallocation
1551       tgtLink._splits.reserve( 10 );
1552     }
1553
1554     for ( int i = 0; i < 6; ++i )
1555     {
1556       const _Face& srcQuad = other._hexQuads[ i ];
1557       _Face&       tgtQuad = this->_hexQuads[ i ];
1558       tgtQuad._links.resize(4);
1559       for ( int j = 0; j < 4; ++j )
1560       {
1561         const _OrientedLink& srcLink = srcQuad._links[ j ];
1562         _OrientedLink&       tgtLink = tgtQuad._links[ j ];
1563         tgtLink._reverse = srcLink._reverse;
1564         tgtLink._link    = _hexLinks + ( srcLink._link - other._hexLinks );
1565       }
1566     }
1567   }
1568   
1569   //================================================================================
1570   /*!
1571    * \brief Initializes its data by given grid cell
1572    */
1573   void Hexahedron::init( size_t i, size_t j, size_t k )
1574   {
1575     _i = i; _j = j; _k = k;
1576     // set nodes of grid to nodes of the hexahedron and
1577     // count nodes at hexahedron corners located IN and ON geometry
1578     _nbCornerNodes = _nbBndNodes = 0;
1579     _origNodeInd   = _grid->NodeIndex( i,j,k );
1580     for ( int iN = 0; iN < 8; ++iN )
1581     {
1582       _hexNodes[iN]._node     = _grid->_nodes   [ _origNodeInd + _nodeShift[iN] ];
1583       _hexNodes[iN]._intPoint = _grid->_gridIntP[ _origNodeInd + _nodeShift[iN] ];
1584       _nbCornerNodes += bool( _hexNodes[iN]._node );
1585       _nbBndNodes    += bool( _hexNodes[iN]._intPoint );
1586     }
1587
1588     _sideLength[0] = _grid->_coords[0][i+1] - _grid->_coords[0][i];
1589     _sideLength[1] = _grid->_coords[1][j+1] - _grid->_coords[1][j];
1590     _sideLength[2] = _grid->_coords[2][k+1] - _grid->_coords[2][k];
1591
1592     if ( _nbIntNodes + _edgeIntPnts.size() > 0 &&
1593          _nbIntNodes + _nbCornerNodes + _edgeIntPnts.size() > 3)
1594     {
1595       _Link split;
1596       // create sub-links (_splits) by splitting links with _intNodes
1597       for ( int iLink = 0; iLink < 12; ++iLink )
1598       {
1599         _Link& link = _hexLinks[ iLink ];
1600         link._splits.clear();
1601         split._nodes[ 0 ] = link._nodes[0];
1602         bool isOut = ( ! link._nodes[0]->Node() ); // is1stNodeOut( iLink );
1603         bool checkTransition;
1604         for ( size_t i = 0; i < link._intNodes.size(); ++i )
1605         {
1606           if ( link._intNodes[i].Node() ) // intersection non-coinsident with a grid node
1607           {
1608             if ( split._nodes[ 0 ]->Node() && !isOut )
1609             {
1610               split._nodes[ 1 ] = &link._intNodes[i];
1611               link._splits.push_back( split );
1612             }
1613             split._nodes[ 0 ] = &link._intNodes[i];
1614             checkTransition = true;
1615           }
1616           else // FACE intersection coinsident with a grid node
1617           {
1618             checkTransition = ( link._nodes[0]->Node() );
1619           }
1620           if ( checkTransition )
1621           {
1622             switch ( link._intNodes[i].FaceIntPnt()->_transition ) {
1623             case Trans_OUT: isOut = true; break;
1624             case Trans_IN : isOut = false; break;
1625             default:
1626               if ( !link._intNodes[i].Node() && i == 0 )
1627                 isOut = is1stNodeOut( link );
1628               else
1629                   ; // isOut remains the same
1630             }
1631           }
1632         }
1633         if ( link._nodes[ 1 ]->Node() && split._nodes[ 0 ]->Node() && !isOut )
1634         {
1635           split._nodes[ 1 ] = link._nodes[1];
1636           link._splits.push_back( split );
1637         }
1638       }
1639
1640       // Create _Node's at intersections with EDGEs.
1641
1642       const double tol2 = _grid->_tol * _grid->_tol;
1643       int facets[3], nbFacets, subEntity;
1644
1645       for ( size_t iP = 0; iP < _edgeIntPnts.size(); ++iP )
1646       {
1647         nbFacets = getEntity( _edgeIntPnts[iP], facets, subEntity );
1648         _Node* equalNode = 0;
1649         switch( nbFacets ) {
1650         case 1: // in a _Face
1651         {
1652           _Face& quad = _hexQuads[ facets[0] - SMESH_Block::ID_FirstF ];
1653           equalNode = FindEqualNode( quad._edgeNodes, _edgeIntPnts[ iP ], tol2 );
1654           if ( equalNode ) {
1655             equalNode->Add( _edgeIntPnts[ iP ] );
1656           }
1657           else {
1658             quad._edgeNodes.push_back( _Node( 0, _edgeIntPnts[ iP ]));
1659             ++_nbIntNodes;
1660           }
1661           break;
1662         }
1663         case 2: // on a _Link
1664         {
1665           _Link& link = _hexLinks[ subEntity - SMESH_Block::ID_FirstE ];
1666           if ( link._splits.size() > 0 )
1667           {
1668             equalNode = FindEqualNode( link._intNodes, _edgeIntPnts[ iP ], tol2 );
1669             if ( equalNode )
1670               equalNode->Add( _edgeIntPnts[ iP ] );
1671           }
1672           else
1673           {
1674             for ( int iF = 0; iF < 2; ++iF )
1675             {
1676               _Face& quad = _hexQuads[ facets[iF] - SMESH_Block::ID_FirstF ];
1677               equalNode = FindEqualNode( quad._edgeNodes, _edgeIntPnts[ iP ], tol2 );
1678               if ( equalNode ) {
1679                 equalNode->Add( _edgeIntPnts[ iP ] );
1680               }
1681               else {
1682                 quad._edgeNodes.push_back( _Node( 0, _edgeIntPnts[ iP ]));
1683                 ++_nbIntNodes;
1684               }
1685             }
1686           }
1687           break;
1688         }
1689         case 3: // at a corner
1690         {
1691           _Node& node = _hexNodes[ subEntity - SMESH_Block::ID_FirstV ];
1692           if ( node.Node() > 0 )
1693           {
1694             if ( node._intPoint )
1695               node._intPoint->Add( _edgeIntPnts[ iP ]->_faceIDs, _edgeIntPnts[ iP ]->_node );
1696           }
1697           else
1698           {
1699             for ( int iF = 0; iF < 3; ++iF )
1700             {
1701               _Face& quad = _hexQuads[ facets[iF] - SMESH_Block::ID_FirstF ];
1702               equalNode = FindEqualNode( quad._edgeNodes, _edgeIntPnts[ iP ], tol2 );
1703               if ( equalNode ) {
1704                 equalNode->Add( _edgeIntPnts[ iP ] );
1705               }
1706               else {
1707                 quad._edgeNodes.push_back( _Node( 0, _edgeIntPnts[ iP ]));
1708                 ++_nbIntNodes;
1709               }
1710             }
1711           }
1712           break;
1713         }
1714         } // switch( nbFacets )
1715
1716         if ( nbFacets == 0 ||
1717              _grid->_shapes( _edgeIntPnts[ iP ]->_shapeID ).ShapeType() == TopAbs_VERTEX )
1718         {
1719           equalNode = FindEqualNode( _vertexNodes, _edgeIntPnts[ iP ], tol2 );
1720           if ( equalNode ) {
1721             equalNode->Add( _edgeIntPnts[ iP ] );
1722           }
1723           else {
1724             _vertexNodes.push_back( _Node( 0, _edgeIntPnts[iP] ));
1725             ++_nbIntNodes;
1726           }
1727         }
1728       } // loop on _edgeIntPnts
1729     }
1730     else if ( 3 < _nbCornerNodes && _nbCornerNodes < 8 ) // _nbIntNodes == 0
1731     {
1732       _Link split;
1733       // create sub-links (_splits) of whole links
1734       for ( int iLink = 0; iLink < 12; ++iLink )
1735       {
1736         _Link& link = _hexLinks[ iLink ];
1737         link._splits.clear();
1738         if ( link._nodes[ 0 ]->Node() && link._nodes[ 1 ]->Node() )
1739         {
1740           split._nodes[ 0 ] = link._nodes[0];
1741           split._nodes[ 1 ] = link._nodes[1];
1742           link._splits.push_back( split );
1743         }
1744       }
1745     }
1746
1747   }
1748   //================================================================================
1749   /*!
1750    * \brief Initializes its data by given grid cell (countered from zero)
1751    */
1752   void Hexahedron::init( size_t iCell )
1753   {
1754     size_t iNbCell = _grid->_coords[0].size() - 1;
1755     size_t jNbCell = _grid->_coords[1].size() - 1;
1756     _i = iCell % iNbCell;
1757     _j = ( iCell % ( iNbCell * jNbCell )) / iNbCell;
1758     _k = iCell / iNbCell / jNbCell;
1759     init( _i, _j, _k );
1760   }
1761
1762   //================================================================================
1763   /*!
1764    * \brief Compute mesh volumes resulted from intersection of the Hexahedron
1765    */
1766   void Hexahedron::ComputeElements()
1767   {
1768     Init();
1769
1770     if ( _nbCornerNodes + _nbIntNodes < 4 )
1771       return;
1772
1773     if ( _nbBndNodes == _nbCornerNodes && _nbIntNodes == 0 && isInHole() )
1774       return;
1775
1776     _polygons.clear();
1777     _polygons.reserve( 20 );
1778
1779     // Create polygons from quadrangles
1780     // --------------------------------
1781
1782     _Link polyLink;
1783     vector< _OrientedLink > splits;
1784     vector<_Node*> chainNodes;
1785
1786     bool hasEdgeIntersections = !_edgeIntPnts.empty();
1787
1788     for ( int iF = 0; iF < 6; ++iF ) // loop on 6 sides of a hexahedron
1789     {
1790       _Face& quad = _hexQuads[ iF ] ;
1791
1792       _polygons.resize( _polygons.size() + 1 );
1793       _Face* polygon = &_polygons.back();
1794       polygon->_polyLinks.reserve( 20 );
1795
1796       splits.clear();
1797       for ( int iE = 0; iE < 4; ++iE ) // loop on 4 sides of a quadrangle
1798         for ( int iS = 0; iS < quad._links[ iE ].NbResultLinks(); ++iS )
1799           splits.push_back( quad._links[ iE ].ResultLink( iS ));
1800
1801       // add splits of links to a polygon and add _polyLinks to make
1802       // polygon's boundary closed
1803
1804       int nbSplits = splits.size();
1805       if ( nbSplits < 2 && quad._edgeNodes.empty() )
1806         nbSplits = 0;
1807
1808       if ( nbSplits == 0 && !quad._edgeNodes.empty() )
1809       {
1810         // make _vertexNodes from _edgeNodes of an empty quad
1811         const double tol2 = _grid->_tol * _grid->_tol;
1812         for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
1813         {
1814           _Node* equalNode =
1815             FindEqualNode( _vertexNodes, quad._edgeNodes[ iP ].EdgeIntPnt(), tol2 );
1816           if ( equalNode )
1817             equalNode->Add( quad._edgeNodes[ iP ].EdgeIntPnt() );
1818           else
1819             _vertexNodes.push_back( quad._edgeNodes[ iP ]);
1820         }
1821       }
1822 #ifdef _DEBUG_
1823       for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
1824         quad._edgeNodes[ iP ]._isUsedInFace = false;
1825 #endif
1826       int nbUsedEdgeNodes = 0;
1827
1828       while ( nbSplits > 0 )
1829       {
1830         size_t iS = 0;
1831         while ( !splits[ iS ] )
1832           ++iS;
1833
1834         if ( !polygon->_links.empty() )
1835         {
1836           _polygons.resize( _polygons.size() + 1 );
1837           polygon = &_polygons.back();
1838           polygon->_polyLinks.reserve( 20 );
1839         }
1840         polygon->_links.push_back( splits[ iS ] );
1841         splits[ iS++ ]._link = 0;
1842         --nbSplits;
1843
1844         _Node* nFirst = polygon->_links.back().FirstNode();
1845         _Node *n1,*n2 = polygon->_links.back().LastNode();
1846         for ( ; nFirst != n2 && iS < splits.size(); ++iS )
1847         {
1848           _OrientedLink& split = splits[ iS ];
1849           if ( !split ) continue;
1850
1851           n1 = split.FirstNode();
1852           if ( n1 != n2 )
1853           {
1854             // try to connect to intersections with EDGEs
1855             if ( quad._edgeNodes.size() > nbUsedEdgeNodes  &&
1856                  findChain( n2, n1, quad, chainNodes ))
1857             {
1858               for ( size_t i = 1; i < chainNodes.size(); ++i )
1859               {
1860                 polyLink._nodes[0] = chainNodes[i-1];
1861                 polyLink._nodes[1] = chainNodes[i];
1862                 polygon->_polyLinks.push_back( polyLink );
1863                 polygon->_links.push_back( _OrientedLink( &polygon->_polyLinks.back() ));
1864                 nbUsedEdgeNodes += polyLink._nodes[1]->_isUsedInFace;
1865               }
1866               if ( chainNodes.back() != n1 )
1867               {
1868                 n2 = chainNodes.back();
1869                 --iS;
1870                 continue;
1871               }
1872             }
1873             // try to connect to a split ending on the same FACE
1874             else
1875             {
1876               _OrientedLink foundSplit;
1877               for ( int i = iS; i < splits.size() && !foundSplit; ++i )
1878                 if (( foundSplit = splits[ i ]) &&
1879                     ( n2->IsLinked( foundSplit.FirstNode()->_intPoint )))
1880                 {
1881                   polyLink._nodes[0] = n2;
1882                   polyLink._nodes[1] = foundSplit.FirstNode();
1883                   polygon->_polyLinks.push_back( polyLink );
1884                   polygon->_links.push_back( _OrientedLink( &polygon->_polyLinks.back() ));
1885                   iS = i - 1;
1886                 }
1887                 else
1888                 {
1889                   foundSplit._link = 0;
1890                 }
1891               if ( foundSplit )
1892               {
1893                 n2 = foundSplit.FirstNode();
1894                 continue;
1895               }
1896               else
1897               {
1898                 if ( n2->IsLinked( nFirst->_intPoint ))
1899                   break;
1900                 polyLink._nodes[0] = n2;
1901                 polyLink._nodes[1] = n1;
1902                 polygon->_polyLinks.push_back( polyLink );
1903                 polygon->_links.push_back( _OrientedLink( &polygon->_polyLinks.back() ));
1904               }
1905             }
1906           }
1907           polygon->_links.push_back( split );
1908           split._link = 0;
1909           --nbSplits;
1910           n2 = polygon->_links.back().LastNode();
1911
1912         } // loop on splits
1913
1914         if ( nFirst != n2 ) // close a polygon
1915         {
1916           if ( !findChain( n2, nFirst, quad, chainNodes ))
1917           {
1918             if ( !closePolygon( polygon, chainNodes ))
1919               chainNodes.push_back( nFirst );
1920           }
1921           for ( size_t i = 1; i < chainNodes.size(); ++i )
1922           {
1923             polyLink._nodes[0] = chainNodes[i-1];
1924             polyLink._nodes[1] = chainNodes[i];
1925             polygon->_polyLinks.push_back( polyLink );
1926             polygon->_links.push_back( _OrientedLink( &polygon->_polyLinks.back() ));
1927           }
1928         }
1929
1930         if ( polygon->_links.size() < 3 && nbSplits > 0 )
1931         {
1932           polygon->_polyLinks.clear();
1933           polygon->_links.clear();
1934         }
1935       } // while ( nbSplits > 0 )
1936
1937       if ( polygon->_links.size() < 3 )
1938         _polygons.pop_back();
1939
1940     }  // loop on 6 sides of a hexahedron
1941
1942     // Create polygons closing holes in a polyhedron
1943     // ----------------------------------------------
1944
1945     // add polygons to their links
1946     for ( size_t iP = 0; iP < _polygons.size(); ++iP )
1947     {
1948       _Face& polygon = _polygons[ iP ];
1949       for ( size_t iL = 0; iL < polygon._links.size(); ++iL )
1950       {
1951         polygon._links[ iL ]._link->_faces.reserve( 2 );
1952         polygon._links[ iL ]._link->_faces.push_back( &polygon );
1953       }
1954     }
1955     // find free links
1956     vector< _OrientedLink* > freeLinks;
1957     freeLinks.reserve(20);
1958     for ( size_t iP = 0; iP < _polygons.size(); ++iP )
1959     {
1960       _Face& polygon = _polygons[ iP ];
1961       for ( size_t iL = 0; iL < polygon._links.size(); ++iL )
1962         if ( polygon._links[ iL ]._link->_faces.size() < 2 )
1963           freeLinks.push_back( & polygon._links[ iL ]);
1964     }
1965     int nbFreeLinks = freeLinks.size();
1966     if ( nbFreeLinks > 0 && nbFreeLinks < 3 ) return;
1967
1968     set<TGeomID> usedFaceIDs;
1969
1970     // make closed chains of free links
1971     while ( nbFreeLinks > 0 )
1972     {
1973       _polygons.resize( _polygons.size() + 1 );
1974       _Face& polygon = _polygons.back();
1975       polygon._polyLinks.reserve( 20 );
1976       polygon._links.reserve( 20 );
1977
1978       _OrientedLink* curLink = 0;
1979       _Node*         curNode;
1980       if (( !hasEdgeIntersections ) ||
1981           ( nbFreeLinks < 4 && _vertexNodes.empty() ))
1982       {
1983         // get a remaining link to start from
1984         for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL )
1985           if (( curLink = freeLinks[ iL ] ))
1986             freeLinks[ iL ] = 0;
1987         polygon._links.push_back( *curLink );
1988         --nbFreeLinks;
1989         do
1990         {
1991           // find all links connected to curLink
1992           curNode = curLink->FirstNode();
1993           curLink = 0;
1994           for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL )
1995             if ( freeLinks[ iL ] && freeLinks[ iL ]->LastNode() == curNode )
1996             {
1997               curLink = freeLinks[ iL ];
1998               freeLinks[ iL ] = 0;
1999               --nbFreeLinks;
2000               polygon._links.push_back( *curLink );
2001             }
2002         } while ( curLink );
2003       }
2004       else // there are intersections with EDGEs
2005       {
2006         TGeomID curFace;
2007         // get a remaining link to start from, one lying on minimal
2008         // nb of FACEs
2009         {
2010           vector< pair< TGeomID, int > > facesOfLink[3];
2011           pair< TGeomID, int > faceOfLink( -1, -1 );
2012           vector< TGeomID > faces;
2013           for ( size_t iL = 0; iL < freeLinks.size(); ++iL )
2014             if ( freeLinks[ iL ] )
2015             {
2016               faces = freeLinks[ iL ]->GetNotUsedFace( usedFaceIDs );
2017               if ( faces.size() == 1 )
2018               {
2019                 faceOfLink = make_pair( faces[0], iL );
2020                 if ( !freeLinks[ iL ]->HasEdgeNodes() )
2021                   break;
2022                 facesOfLink[0].push_back( faceOfLink );
2023               }
2024               else if ( facesOfLink[0].empty() )
2025               {
2026                 faceOfLink = make_pair(( faces.empty() ? -1 : faces[0]), iL );
2027                 facesOfLink[ 1 + faces.empty() ].push_back( faceOfLink );
2028               }
2029             }
2030           for ( int i = 0; faceOfLink.second < 0 && i < 3; ++i )
2031             if ( !facesOfLink[i].empty() )
2032               faceOfLink = facesOfLink[i][0];
2033
2034           if ( faceOfLink.first < 0 ) // all faces used
2035           {
2036             for ( size_t i = 0; i < facesOfLink[2].size() && faceOfLink.first < 1; ++i )
2037             {
2038               curLink = freeLinks[ facesOfLink[2][i].second ];
2039               faceOfLink.first = curLink->FirstNode()->IsLinked( curLink->FirstNode()->_intPoint );
2040             }
2041             usedFaceIDs.clear();
2042           }
2043           curFace = faceOfLink.first;
2044           curLink = freeLinks[ faceOfLink.second ];
2045           freeLinks[ faceOfLink.second ] = 0;
2046         }
2047         usedFaceIDs.insert( curFace );
2048         polygon._links.push_back( *curLink );
2049         --nbFreeLinks;
2050
2051         // find all links bounding a FACE of curLink
2052         do
2053         {
2054           // go forward from curLink
2055           curNode = curLink->LastNode();
2056           curLink = 0;
2057           for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL )
2058             if ( freeLinks[ iL ] &&
2059                  freeLinks[ iL ]->FirstNode() == curNode &&
2060                  freeLinks[ iL ]->LastNode()->IsOnFace( curFace ))
2061             {
2062               curLink = freeLinks[ iL ];
2063               freeLinks[ iL ] = 0;
2064               polygon._links.push_back( *curLink );
2065               --nbFreeLinks;
2066             }
2067         } while ( curLink );
2068
2069         std::reverse( polygon._links.begin(), polygon._links.end() );
2070
2071         curLink = & polygon._links.back();
2072         do
2073         {
2074           // go backward from curLink
2075           curNode = curLink->FirstNode();
2076           curLink = 0;
2077           for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL )
2078             if ( freeLinks[ iL ] &&
2079                  freeLinks[ iL ]->LastNode() == curNode &&
2080                  freeLinks[ iL ]->FirstNode()->IsOnFace( curFace ))
2081             {
2082               curLink = freeLinks[ iL ];
2083               freeLinks[ iL ] = 0;
2084               polygon._links.push_back( *curLink );
2085               --nbFreeLinks;
2086             }
2087         } while ( curLink );
2088
2089         curNode = polygon._links.back().FirstNode();
2090
2091         if ( polygon._links[0].LastNode() != curNode )
2092         {
2093           if ( !_vertexNodes.empty() )
2094           {
2095             // add links with _vertexNodes if not already used
2096             for ( size_t iN = 0; iN < _vertexNodes.size(); ++iN )
2097               if ( _vertexNodes[ iN ].IsOnFace( curFace ))
2098               {
2099                 bool used = ( curNode == &_vertexNodes[ iN ] );
2100                 for ( size_t iL = 0; iL < polygon._links.size() && !used; ++iL )
2101                   used = ( &_vertexNodes[ iN ] ==  polygon._links[ iL ].LastNode() );
2102                 if ( !used )
2103                 {
2104                   polyLink._nodes[0] = &_vertexNodes[ iN ];
2105                   polyLink._nodes[1] = curNode;
2106                   polygon._polyLinks.push_back( polyLink );
2107                   polygon._links.push_back( _OrientedLink( &polygon._polyLinks.back() ));
2108                   freeLinks.push_back( &polygon._links.back() );
2109                   ++nbFreeLinks;
2110                   curNode = &_vertexNodes[ iN ];
2111                 }
2112                 // TODO: to reorder _vertexNodes within polygon, if there are several ones
2113               }
2114           }
2115           // if ( polygon._links.size() > 1 )
2116           {
2117             polyLink._nodes[0] = polygon._links[0].LastNode();
2118             polyLink._nodes[1] = curNode;
2119             polygon._polyLinks.push_back( polyLink );
2120             polygon._links.push_back( _OrientedLink( &polygon._polyLinks.back() ));
2121             freeLinks.push_back( &polygon._links.back() );
2122             ++nbFreeLinks;
2123           }
2124         }
2125
2126       } // if there are intersections with EDGEs
2127
2128       if ( polygon._links.size() < 2 ||
2129            polygon._links[0].LastNode() != polygon._links.back().FirstNode() )
2130         return; // closed polygon not found -> invalid polyhedron
2131
2132       if ( polygon._links.size() == 2 )
2133       {
2134         if ( freeLinks.back() == &polygon._links.back() )
2135         {
2136           freeLinks.back() = 0;
2137           --nbFreeLinks;
2138         }
2139         vector< _Face*>& polygs1 = polygon._links.front()._link->_faces;
2140         vector< _Face*>& polygs2 = polygon._links.back()._link->_faces;
2141         _Face* polyg1 = ( polygs1.empty() ? 0 : polygs1[0] );
2142         _Face* polyg2 = ( polygs2.empty() ? 0 : polygs2[0] );
2143         if ( polyg1 ) polygs2.push_back( polyg1 );
2144         if ( polyg2 ) polygs1.push_back( polyg2 );
2145         _polygons.pop_back();
2146       }
2147       else
2148       {
2149         // add polygon to its links
2150         for ( size_t iL = 0; iL < polygon._links.size(); ++iL )
2151         {
2152           polygon._links[ iL ]._link->_faces.reserve( 2 );
2153           polygon._links[ iL ]._link->_faces.push_back( &polygon );
2154           polygon._links[ iL ].Reverse();
2155         }
2156       }
2157     } // while ( nbFreeLinks > 0 )
2158
2159     if ( ! checkPolyhedronSize() )
2160     {
2161       return;
2162     }
2163
2164     // create a classic cell if possible
2165     const int nbNodes = _nbCornerNodes + _nbIntNodes;
2166     bool isClassicElem = false;
2167     if (      nbNodes == 8 && _polygons.size() == 6 ) isClassicElem = addHexa();
2168     else if ( nbNodes == 4 && _polygons.size() == 4 ) isClassicElem = addTetra();
2169     else if ( nbNodes == 6 && _polygons.size() == 5 ) isClassicElem = addPenta();
2170     else if ( nbNodes == 5 && _polygons.size() == 5 ) isClassicElem = addPyra ();
2171     if ( !isClassicElem )
2172     {
2173       _volumeDefs._nodes.clear();
2174       _volumeDefs._quantities.clear();
2175
2176       for ( size_t iF = 0; iF < _polygons.size(); ++iF )
2177       {
2178         const size_t nbLinks = _polygons[ iF ]._links.size();
2179         _volumeDefs._quantities.push_back( nbLinks );
2180         for ( size_t iL = 0; iL < nbLinks; ++iL )
2181           _volumeDefs._nodes.push_back( _polygons[ iF ]._links[ iL ].FirstNode() );
2182       }
2183     }
2184   }
2185   //================================================================================
2186   /*!
2187    * \brief Create elements in the mesh
2188    */
2189   int Hexahedron::MakeElements(SMESH_MesherHelper&                      helper,
2190                                const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap)
2191   {
2192     SMESHDS_Mesh* mesh = helper.GetMeshDS();
2193
2194     size_t nbCells[3] = { _grid->_coords[0].size() - 1,
2195                           _grid->_coords[1].size() - 1,
2196                           _grid->_coords[2].size() - 1 };
2197     const size_t nbGridCells = nbCells[0] * nbCells[1] * nbCells[2];
2198     vector< Hexahedron* > intersectedHex( nbGridCells, 0 );
2199     int nbIntHex = 0;
2200
2201     // set intersection nodes from GridLine's to links of intersectedHex
2202     int i,j,k, iDirOther[3][2] = {{ 1,2 },{ 0,2 },{ 0,1 }};
2203     for ( int iDir = 0; iDir < 3; ++iDir )
2204     {
2205       int dInd[4][3] = { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} };
2206       dInd[1][ iDirOther[iDir][0] ] = -1;
2207       dInd[2][ iDirOther[iDir][1] ] = -1;
2208       dInd[3][ iDirOther[iDir][0] ] = -1; dInd[3][ iDirOther[iDir][1] ] = -1;
2209       // loop on GridLine's parallel to iDir
2210       LineIndexer lineInd = _grid->GetLineIndexer( iDir );
2211       for ( ; lineInd.More(); ++lineInd )
2212       {
2213         GridLine& line = _grid->_lines[ iDir ][ lineInd.LineIndex() ];
2214         multiset< F_IntersectPoint >::const_iterator ip = line._intPoints.begin();
2215         for ( ; ip != line._intPoints.end(); ++ip )
2216         {
2217           // if ( !ip->_node ) continue; // intersection at a grid node
2218           lineInd.SetIndexOnLine( ip->_indexOnLine );
2219           for ( int iL = 0; iL < 4; ++iL ) // loop on 4 cells sharing a link
2220           {
2221             i = int(lineInd.I()) + dInd[iL][0];
2222             j = int(lineInd.J()) + dInd[iL][1];
2223             k = int(lineInd.K()) + dInd[iL][2];
2224             if ( i < 0 || i >= nbCells[0] ||
2225                  j < 0 || j >= nbCells[1] ||
2226                  k < 0 || k >= nbCells[2] ) continue;
2227
2228             const size_t hexIndex = _grid->CellIndex( i,j,k );
2229             Hexahedron *& hex = intersectedHex[ hexIndex ];
2230             if ( !hex)
2231             {
2232               hex = new Hexahedron( *this );
2233               hex->_i = i;
2234               hex->_j = j;
2235               hex->_k = k;
2236               ++nbIntHex;
2237             }
2238             const int iLink = iL + iDir * 4;
2239             hex->_hexLinks[iLink]._intNodes.push_back( _Node( 0, &(*ip) ));
2240             hex->_nbIntNodes += bool( ip->_node );
2241           }
2242         }
2243       }
2244     }
2245
2246     // implement geom edges into the mesh
2247     addEdges( helper, intersectedHex, edge2faceIDsMap );
2248
2249     // add not split hexadrons to the mesh
2250     int nbAdded = 0;
2251     vector<int> intHexInd( nbIntHex );
2252     nbIntHex = 0;
2253     for ( size_t i = 0; i < intersectedHex.size(); ++i )
2254     {
2255       Hexahedron * & hex = intersectedHex[ i ];
2256       if ( hex )
2257       {
2258         intHexInd[ nbIntHex++ ] = i;
2259         if ( hex->_nbIntNodes > 0 || ! hex->_edgeIntPnts.empty())
2260           continue; // treat intersected hex later
2261         this->init( hex->_i, hex->_j, hex->_k );
2262       }
2263       else
2264       {    
2265         this->init( i );
2266       }
2267       if (( _nbCornerNodes == 8 ) &&
2268           ( _nbBndNodes < _nbCornerNodes || !isInHole() ))
2269       {
2270         // order of _hexNodes is defined by enum SMESH_Block::TShapeID
2271         SMDS_MeshElement* el =
2272           mesh->AddVolume( _hexNodes[0].Node(), _hexNodes[2].Node(),
2273                            _hexNodes[3].Node(), _hexNodes[1].Node(),
2274                            _hexNodes[4].Node(), _hexNodes[6].Node(),
2275                            _hexNodes[7].Node(), _hexNodes[5].Node() );
2276         mesh->SetMeshElementOnShape( el, helper.GetSubShapeID() );
2277         ++nbAdded;
2278         if ( hex )
2279         {
2280           delete hex;
2281           intersectedHex[ i ] = 0;
2282           --nbIntHex;
2283         }
2284       }
2285       else if ( _nbCornerNodes > 3  && !hex )
2286       {
2287         // all intersection of hex with geometry are at grid nodes
2288         hex = new Hexahedron( *this );
2289         //hex->init( i );
2290         hex->_i = _i;
2291         hex->_j = _j;
2292         hex->_k = _k;
2293         intHexInd.push_back(0);
2294         intHexInd[ nbIntHex++ ] = i;
2295       }
2296     }
2297
2298     // add elements resulted from hexadron intersection
2299 #ifdef WITH_TBB
2300     intHexInd.resize( nbIntHex );
2301     tbb::parallel_for ( tbb::blocked_range<size_t>( 0, nbIntHex ),
2302                         ParallelHexahedron( intersectedHex, intHexInd ),
2303                         tbb::simple_partitioner()); // ComputeElements() is called here
2304     for ( size_t i = 0; i < intHexInd.size(); ++i )
2305       if ( Hexahedron * hex = intersectedHex[ intHexInd[ i ]] )
2306         nbAdded += hex->addElements( helper );
2307 #else
2308     for ( size_t i = 0; i < intHexInd.size(); ++i )
2309       if ( Hexahedron * hex = intersectedHex[ intHexInd[ i ]] )
2310       {
2311         hex->ComputeElements();
2312         nbAdded += hex->addElements( helper );
2313       }
2314 #endif
2315
2316     for ( size_t i = 0; i < intersectedHex.size(); ++i )
2317       if ( intersectedHex[ i ] )
2318         delete intersectedHex[ i ];
2319
2320     return nbAdded;
2321   }
2322
2323   //================================================================================
2324   /*!
2325    * \brief Implements geom edges into the mesh
2326    */
2327   void Hexahedron::addEdges(SMESH_MesherHelper&                      helper,
2328                             vector< Hexahedron* >&                   hexes,
2329                             const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap)
2330   {
2331     if ( edge2faceIDsMap.empty() ) return;
2332
2333     // Prepare planes for intersecting with EDGEs
2334     GridPlanes pln[3];
2335     {
2336       for ( int iDirZ = 0; iDirZ < 3; ++iDirZ ) // iDirZ gives normal direction to planes
2337       {
2338         GridPlanes& planes = pln[ iDirZ ];
2339         int iDirX = ( iDirZ + 1 ) % 3;
2340         int iDirY = ( iDirZ + 2 ) % 3;
2341         // planes._uNorm  = ( _grid->_axes[ iDirY ] ^ _grid->_axes[ iDirZ ] ).Normalized();
2342         // planes._vNorm  = ( _grid->_axes[ iDirZ ] ^ _grid->_axes[ iDirX ] ).Normalized();
2343         planes._zNorm  = ( _grid->_axes[ iDirX ] ^ _grid->_axes[ iDirY ] ).Normalized();
2344         planes._zProjs.resize ( _grid->_coords[ iDirZ ].size() );
2345         planes._zProjs [0] = 0;
2346         const double       zFactor = _grid->_axes[ iDirZ ] * planes._zNorm;
2347         const vector< double > & u = _grid->_coords[ iDirZ ];
2348         for ( int i = 1; i < planes._zProjs.size(); ++i )
2349         {
2350           planes._zProjs [i] = zFactor * ( u[i] - u[0] );
2351         }
2352       }
2353     }
2354     const double deflection = _grid->_minCellSize / 20.;
2355     const double tol        = _grid->_tol;
2356     E_IntersectPoint ip;
2357
2358     // Intersect EDGEs with the planes
2359     map< TGeomID, vector< TGeomID > >::const_iterator e2fIt = edge2faceIDsMap.begin();
2360     for ( ; e2fIt != edge2faceIDsMap.end(); ++e2fIt )
2361     {
2362       const TGeomID  edgeID = e2fIt->first;
2363       const TopoDS_Edge & E = TopoDS::Edge( _grid->_shapes( edgeID ));
2364       BRepAdaptor_Curve curve( E );
2365       TopoDS_Vertex v1 = helper.IthVertex( 0, E, false ); 
2366       TopoDS_Vertex v2 = helper.IthVertex( 1, E, false ); 
2367
2368       ip._faceIDs = e2fIt->second;
2369       ip._shapeID = edgeID;
2370
2371       // discretize the EGDE
2372       GCPnts_UniformDeflection discret( curve, deflection, true );
2373       if ( !discret.IsDone() || discret.NbPoints() < 2 )
2374         continue;
2375
2376       // perform intersection
2377       for ( int iDirZ = 0; iDirZ < 3; ++iDirZ )
2378       {
2379         GridPlanes& planes = pln[ iDirZ ];
2380         int      iDirX = ( iDirZ + 1 ) % 3;
2381         int      iDirY = ( iDirZ + 2 ) % 3;
2382         double    xLen = _grid->_coords[ iDirX ].back() - _grid->_coords[ iDirX ][0];
2383         double    yLen = _grid->_coords[ iDirY ].back() - _grid->_coords[ iDirY ][0];
2384         double    zLen = _grid->_coords[ iDirZ ].back() - _grid->_coords[ iDirZ ][0];
2385         //double zFactor = _grid->_axes[ iDirZ ] * planes._zNorm;
2386         int dIJK[3], d000[3] = { 0,0,0 };
2387         double o[3] = { _grid->_coords[0][0],
2388                         _grid->_coords[1][0],
2389                         _grid->_coords[2][0] };
2390
2391         // locate the 1st point of a segment within the grid
2392         gp_XYZ p1     = discret.Value( 1 ).XYZ();
2393         double u1     = discret.Parameter( 1 );
2394         double zProj1 = planes._zNorm * ( p1 - _grid->_origin );
2395
2396         _grid->ComputeUVW( p1, ip._uvw );
2397         int iX1 = int(( ip._uvw[iDirX] - o[iDirX]) / xLen * (_grid->_coords[ iDirX ].size() - 1));
2398         int iY1 = int(( ip._uvw[iDirY] - o[iDirY]) / yLen * (_grid->_coords[ iDirY ].size() - 1));
2399         int iZ1 = int(( ip._uvw[iDirZ] - o[iDirZ]) / zLen * (_grid->_coords[ iDirZ ].size() - 1));
2400         locateValue( iX1, ip._uvw[iDirX], _grid->_coords[ iDirX ], dIJK[ iDirX ], tol );
2401         locateValue( iY1, ip._uvw[iDirY], _grid->_coords[ iDirY ], dIJK[ iDirY ], tol );
2402         locateValue( iZ1, ip._uvw[iDirZ], _grid->_coords[ iDirZ ], dIJK[ iDirZ ], tol );
2403
2404         int ijk[3]; // grid index where a segment intersect a plane
2405         ijk[ iDirX ] = iX1;
2406         ijk[ iDirY ] = iY1;
2407         ijk[ iDirZ ] = iZ1;
2408
2409         // add the 1st vertex point to a hexahedron
2410         if ( iDirZ == 0 )
2411         {
2412           ip._point   = p1;
2413           ip._shapeID = _grid->_shapes.Add( v1 );
2414           _grid->_edgeIntP.push_back( ip );
2415           if ( !addIntersection( _grid->_edgeIntP.back(), hexes, ijk, d000 ))
2416             _grid->_edgeIntP.pop_back();
2417           ip._shapeID = edgeID;
2418         }
2419         for ( int iP = 2; iP <= discret.NbPoints(); ++iP )
2420         {
2421           // locate the 2nd point of a segment within the grid
2422           gp_XYZ p2     = discret.Value( iP ).XYZ();
2423           double u2     = discret.Parameter( iP );
2424           double zProj2 = planes._zNorm * ( p2 - _grid->_origin );
2425           int iZ2       = iZ1;
2426           locateValue( iZ2, zProj2, planes._zProjs, dIJK[ iDirZ ], tol );
2427
2428           // treat intersections with planes between 2 end points of a segment
2429           int dZ = ( iZ1 <= iZ2 ) ? +1 : -1;
2430           int iZ = iZ1 + ( iZ1 < iZ2 );
2431           for ( int i = 0, nb = Abs( iZ1 - iZ2 ); i < nb; ++i, iZ += dZ )
2432           {
2433             ip._point = findIntPoint( u1, zProj1, u2, zProj2,
2434                                       planes._zProjs[ iZ ],
2435                                       curve, planes._zNorm, _grid->_origin );
2436             _grid->ComputeUVW( ip._point.XYZ(), ip._uvw );
2437             locateValue( ijk[iDirX], ip._uvw[iDirX], _grid->_coords[iDirX], dIJK[iDirX], tol );
2438             locateValue( ijk[iDirY], ip._uvw[iDirY], _grid->_coords[iDirY], dIJK[iDirY], tol );
2439             ijk[ iDirZ ] = iZ;
2440
2441             // add ip to hex "above" the plane
2442             _grid->_edgeIntP.push_back( ip );
2443             dIJK[ iDirZ ] = 0;
2444             bool added = addIntersection(_grid->_edgeIntP.back(), hexes, ijk, dIJK);
2445
2446             // add ip to hex "below" the plane
2447             ijk[ iDirZ ] = iZ-1;
2448             if ( !addIntersection( _grid->_edgeIntP.back(), hexes, ijk, dIJK ) &&
2449                  !added)
2450               _grid->_edgeIntP.pop_back();
2451           }
2452           iZ1    = iZ2;
2453           p1     = p2;
2454           u1     = u2;
2455           zProj1 = zProj2;
2456         }
2457         // add the 2nd vertex point to a hexahedron
2458         if ( iDirZ == 0 )
2459         {
2460           ip._shapeID = _grid->_shapes.Add( v2 );
2461           ip._point = p1;
2462           _grid->ComputeUVW( p1, ip._uvw );
2463           locateValue( ijk[iDirX], ip._uvw[iDirX], _grid->_coords[iDirX], dIJK[iDirX], tol );
2464           locateValue( ijk[iDirY], ip._uvw[iDirY], _grid->_coords[iDirY], dIJK[iDirY], tol );
2465           ijk[ iDirZ ] = iZ1;
2466           _grid->_edgeIntP.push_back( ip );
2467           if ( !addIntersection( _grid->_edgeIntP.back(), hexes, ijk, d000 ))
2468             _grid->_edgeIntP.pop_back();
2469           ip._shapeID = edgeID;
2470         }
2471       } // loop on 3 grid directions
2472     } // loop on EDGEs
2473
2474     // Create nodes at found intersections
2475     // const E_IntersectPoint* eip;
2476     // for ( size_t i = 0; i < hexes.size(); ++i )
2477     // {
2478     //   Hexahedron* h = hexes[i];
2479     //   if ( !h ) continue;
2480     //   for ( int iF = 0; iF < 6; ++iF )
2481     //   {
2482     //     _Face& quad = h->_hexQuads[ iF ];
2483     //     for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
2484     //       if ( !quad._edgeNodes[ iP ]._node )
2485     //         if (( eip = quad._edgeNodes[ iP ].EdgeIntPnt() ))
2486     //           quad._edgeNodes[ iP ]._intPoint->_node = helper.AddNode( eip->_point.X(),
2487     //                                                                    eip->_point.Y(),
2488     //                                                                    eip->_point.Z() );
2489     //   }
2490     //   for ( size_t iP = 0; iP < hexes[i]->_vertexNodes.size(); ++iP )
2491     //     if (( eip = h->_vertexNodes[ iP ].EdgeIntPnt() ))
2492     //       h->_vertexNodes[ iP ]._intPoint->_node = helper.AddNode( eip->_point.X(),
2493     //                                                                eip->_point.Y(),
2494     //                                                                eip->_point.Z() );
2495     // }
2496   }
2497
2498   //================================================================================
2499   /*!
2500    * \brief Finds intersection of a curve with a plane
2501    *  \param [in] u1 - parameter of one curve point
2502    *  \param [in] proj1 - projection of the curve point to the plane normal
2503    *  \param [in] u2 - parameter of another curve point
2504    *  \param [in] proj2 - projection of the other curve point to the plane normal
2505    *  \param [in] proj - projection of a point where the curve intersects the plane
2506    *  \param [in] curve - the curve
2507    *  \param [in] axis - the plane normal
2508    *  \param [in] origin - the plane origin
2509    *  \return gp_Pnt - the found intersection point
2510    */
2511   gp_Pnt Hexahedron::findIntPoint( double u1, double proj1,
2512                                    double u2, double proj2,
2513                                    double proj,
2514                                    BRepAdaptor_Curve& curve,
2515                                    const gp_XYZ& axis,
2516                                    const gp_XYZ& origin)
2517   {
2518     double r = (( proj - proj1 ) / ( proj2 - proj1 ));
2519     double u = u1 * ( 1 - r ) + u2 * r;
2520     gp_Pnt p = curve.Value( u );
2521     double newProj =  axis * ( p.XYZ() - origin );
2522     if ( Abs( proj - newProj ) > _grid->_tol / 10. )
2523     {
2524       if ( r > 0.5 )
2525         return findIntPoint( u2, proj2, u, newProj, proj, curve, axis, origin );
2526       else
2527         return findIntPoint( u1, proj2, u, newProj, proj, curve, axis, origin );
2528     }
2529     return p;
2530   }
2531
2532   //================================================================================
2533   /*!
2534    * \brief Returns indices of a hexahedron sub-entities holding a point
2535    *  \param [in] ip - intersection point
2536    *  \param [out] facets - 0-3 facets holding a point
2537    *  \param [out] sub - index of a vertex or an edge holding a point
2538    *  \return int - number of facets holding a point
2539    */
2540   int Hexahedron::getEntity( const E_IntersectPoint* ip, int* facets, int& sub )
2541   {
2542     enum { X = 1, Y = 2, Z = 4 }; // == 001, 010, 100
2543     int nbFacets = 0;
2544     int vertex = 0, egdeMask = 0;
2545
2546     if ( Abs( _grid->_coords[0][ _i   ] - ip->_uvw[0] ) < _grid->_tol ) {
2547       facets[ nbFacets++ ] = SMESH_Block::ID_F0yz;
2548       egdeMask |= X;
2549     }
2550     else if ( Abs( _grid->_coords[0][ _i+1 ] - ip->_uvw[0] ) < _grid->_tol ) {
2551       facets[ nbFacets++ ] = SMESH_Block::ID_F1yz;
2552       vertex   |= X;
2553       egdeMask |= X;
2554     }
2555     if ( Abs( _grid->_coords[1][ _j   ] - ip->_uvw[1] ) < _grid->_tol ) {
2556       facets[ nbFacets++ ] = SMESH_Block::ID_Fx0z;
2557       egdeMask |= Y;
2558     }
2559     else if ( Abs( _grid->_coords[1][ _j+1 ] - ip->_uvw[1] ) < _grid->_tol ) {
2560       facets[ nbFacets++ ] = SMESH_Block::ID_Fx1z;
2561       vertex   |= Y;
2562       egdeMask |= Y;
2563     }
2564     if ( Abs( _grid->_coords[2][ _k   ] - ip->_uvw[2] ) < _grid->_tol ) {
2565       facets[ nbFacets++ ] = SMESH_Block::ID_Fxy0;
2566       egdeMask |= Z;
2567     }
2568     else if ( Abs( _grid->_coords[2][ _k+1 ] - ip->_uvw[2] ) < _grid->_tol ) {
2569       facets[ nbFacets++ ] = SMESH_Block::ID_Fxy1;
2570       vertex   |= Z;
2571       egdeMask |= Z;
2572     }
2573
2574     switch ( nbFacets )
2575     {
2576     case 0: sub = 0;         break;
2577     case 1: sub = facets[0]; break;
2578     case 2: {
2579       const int edge [3][8] = {
2580         { SMESH_Block::ID_E00z, SMESH_Block::ID_E10z,
2581           SMESH_Block::ID_E01z, SMESH_Block::ID_E11z },
2582         { SMESH_Block::ID_E0y0, SMESH_Block::ID_E1y0, 0, 0,
2583           SMESH_Block::ID_E0y1, SMESH_Block::ID_E1y1 },
2584         { SMESH_Block::ID_Ex00, 0, SMESH_Block::ID_Ex10, 0,
2585           SMESH_Block::ID_Ex01, 0, SMESH_Block::ID_Ex11 }
2586       };
2587       switch ( egdeMask ) {
2588       case X | Y: sub = edge[ 0 ][ vertex ]; break;
2589       case X | Z: sub = edge[ 1 ][ vertex ]; break;
2590       default:    sub = edge[ 2 ][ vertex ];
2591       }
2592       break;
2593     }
2594     //case 3:
2595     default:
2596       sub = vertex + SMESH_Block::ID_FirstV;
2597     }
2598
2599     return nbFacets;
2600   }
2601   //================================================================================
2602   /*!
2603    * \brief Adds intersection with an EDGE
2604    */
2605   bool Hexahedron::addIntersection( const E_IntersectPoint& ip,
2606                                     vector< Hexahedron* >&  hexes,
2607                                     int ijk[], int dIJK[] )
2608   {
2609     bool added = false;
2610
2611     size_t hexIndex[4] = {
2612       _grid->CellIndex( ijk[0], ijk[1], ijk[2] ),
2613       dIJK[0] ? _grid->CellIndex( ijk[0]+dIJK[0], ijk[1], ijk[2] ) : -1,
2614       dIJK[1] ? _grid->CellIndex( ijk[0], ijk[1]+dIJK[1], ijk[2] ) : -1,
2615       dIJK[2] ? _grid->CellIndex( ijk[0], ijk[1], ijk[2]+dIJK[2] ) : -1
2616     };
2617     for ( int i = 0; i < 4; ++i )
2618     {
2619       if ( /*0 <= hexIndex[i] &&*/ hexIndex[i] < hexes.size() && hexes[ hexIndex[i] ] )
2620       {
2621         Hexahedron* h = hexes[ hexIndex[i] ];
2622         // check if ip is really inside the hex
2623 #ifdef _DEBUG_
2624         if (( _grid->_coords[0][ h->_i   ] - _grid->_tol > ip._uvw[0] ) ||
2625             ( _grid->_coords[0][ h->_i+1 ] + _grid->_tol < ip._uvw[0] ) ||
2626             ( _grid->_coords[1][ h->_j   ] - _grid->_tol > ip._uvw[1] ) ||
2627             ( _grid->_coords[1][ h->_j+1 ] + _grid->_tol < ip._uvw[1] ) ||
2628             ( _grid->_coords[2][ h->_k   ] - _grid->_tol > ip._uvw[2] ) ||
2629             ( _grid->_coords[2][ h->_k+1 ] + _grid->_tol < ip._uvw[2] ))
2630           throw SALOME_Exception("ip outside a hex");
2631 #endif
2632         h->_edgeIntPnts.push_back( & ip );
2633         added = true;
2634       }
2635     }
2636     return added;
2637   }
2638   //================================================================================
2639   /*!
2640    * \brief Finds nodes at a path from one node to another via intersections with EDGEs
2641    */
2642   bool Hexahedron::findChain( _Node*          n1,
2643                               _Node*          n2,
2644                               _Face&          quad,
2645                               vector<_Node*>& chn )
2646   {
2647     chn.clear();
2648     chn.push_back( n1 );
2649     for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
2650       if ( !quad._edgeNodes[ iP ]._isUsedInFace &&
2651            n1->IsLinked( quad._edgeNodes[ iP ]._intPoint ) &&
2652            n2->IsLinked( quad._edgeNodes[ iP ]._intPoint ))
2653       {
2654         chn.push_back( & quad._edgeNodes[ iP ]);
2655         chn.push_back( n2 );
2656         quad._edgeNodes[ iP ]._isUsedInFace = true;
2657         return true;
2658       }
2659     bool found;
2660     do
2661     {
2662       found = false;
2663       for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
2664         if ( !quad._edgeNodes[ iP ]._isUsedInFace &&
2665              chn.back()->IsLinked( quad._edgeNodes[ iP ]._intPoint ))
2666         {
2667           chn.push_back( & quad._edgeNodes[ iP ]);
2668           found = quad._edgeNodes[ iP ]._isUsedInFace = true;
2669           break;
2670         }
2671     } while ( found && ! chn.back()->IsLinked( n2->_intPoint ) );
2672
2673     if ( chn.back() != n2 && chn.back()->IsLinked( n2->_intPoint ))
2674       chn.push_back( n2 );
2675
2676     return chn.size() > 1;
2677   }
2678   //================================================================================
2679   /*!
2680    * \brief Try to heal a polygon whose ends are not connected
2681    */
2682   bool Hexahedron::closePolygon( _Face* polygon, vector<_Node*>& chainNodes ) const
2683   {
2684     int i = -1, nbLinks = polygon->_links.size();
2685     if ( nbLinks < 3 )
2686       return false;
2687     vector< _OrientedLink > newLinks;
2688     // find a node lying on the same FACE as the last one
2689     _Node*   node = polygon->_links.back().LastNode();
2690     int avoidFace = node->IsLinked( polygon->_links.back().FirstNode()->_intPoint );
2691     for ( i = nbLinks - 2; i >= 0; --i )
2692       if ( node->IsLinked( polygon->_links[i].FirstNode()->_intPoint, avoidFace ))
2693         break;
2694     if ( i >= 0 )
2695     {
2696       for ( ; i < nbLinks; ++i )
2697         newLinks.push_back( polygon->_links[i] );
2698     }
2699     else
2700     {
2701       // find a node lying on the same FACE as the first one
2702       node      = polygon->_links[0].FirstNode();
2703       avoidFace = node->IsLinked( polygon->_links[0].LastNode()->_intPoint );
2704       for ( i = 1; i < nbLinks; ++i )
2705         if ( node->IsLinked( polygon->_links[i].LastNode()->_intPoint, avoidFace ))
2706           break;
2707       if ( i < nbLinks )
2708         for ( nbLinks = i + 1, i = 0; i < nbLinks; ++i )
2709           newLinks.push_back( polygon->_links[i] );
2710     }
2711     if ( newLinks.size() > 1 )
2712     {
2713       polygon->_links.swap( newLinks );
2714       chainNodes.clear();
2715       chainNodes.push_back( polygon->_links.back().LastNode() );
2716       chainNodes.push_back( polygon->_links[0].FirstNode() );
2717       return true;
2718     }
2719     return false;
2720   }
2721   //================================================================================
2722   /*!
2723    * \brief Checks transition at the 1st node of a link
2724    */
2725   bool Hexahedron::is1stNodeOut( _Link& link /*int iLink*/ ) const
2726   {
2727     // new version is for the case: tangent transition at the 1st node
2728     bool isOut = false;
2729     if ( link._intNodes.size() > 1 )
2730     {
2731       // check transition at the next intersection
2732       switch ( link._intNodes[1].FaceIntPnt()->_transition ) {
2733       case Trans_OUT: return false;
2734       case Trans_IN : return true;
2735       default: ; // tangent transition
2736       }
2737     }
2738     gp_Pnt p1 = link._nodes[0]->Point();
2739     gp_Pnt p2 = link._nodes[1]->Point();
2740     gp_Pnt testPnt = 0.8 * p1.XYZ() + 0.2 * p2.XYZ();
2741
2742     TGeomID          faceID = link._intNodes[0]._intPoint->_faceIDs[0];
2743     const TopoDS_Face& face = TopoDS::Face( _grid->_shapes( faceID ));
2744     TopLoc_Location loc;
2745     GeomAPI_ProjectPointOnSurf& proj =
2746       _grid->_helper->GetProjector( face, loc, 0.1*_grid->_tol );
2747     testPnt.Transform( loc );
2748     proj.Perform( testPnt );
2749     if ( proj.IsDone() &&
2750          proj.NbPoints() > 0 &&
2751          proj.LowerDistance() > _grid->_tol )
2752     {
2753       Quantity_Parameter u,v;
2754       proj.LowerDistanceParameters( u,v );
2755       gp_Dir normal;
2756       if ( GeomLib::NormEstim( BRep_Tool::Surface( face, loc ),
2757                                gp_Pnt2d( u,v ),
2758                                0.1*_grid->_tol,
2759                                normal ) < 3 )
2760       {
2761         if ( face.Orientation() == TopAbs_REVERSED )
2762           normal.Reverse();
2763         gp_Vec v( proj.NearestPoint(), testPnt );
2764         return v * normal > 0;
2765       }
2766     }
2767     //     if ( !_hexLinks[ iLink ]._nodes[0]->Node() ) // no node
2768     //       return true;
2769     //     if ( !_hexLinks[ iLink ]._nodes[0]->_intPoint ) // no intersection with geometry
2770     //       return false;
2771     //     switch ( _hexLinks[ iLink ]._nodes[0]->FaceIntPnt()->_transition ) {
2772     //     case Trans_OUT: return true;
2773     //     case Trans_IN : return false;
2774     //     default: ; // tangent transition
2775     //     }
2776
2777 //     // ijk of a GridLine corresponding to the link
2778 //     int   iDir = iLink / 4;
2779 //     int indSub = iLink % 4;
2780 //     LineIndexer li = _grid->GetLineIndexer( iDir );
2781 //     li.SetIJK( _i,_j,_k );
2782 //     size_t lineIndex[4] = { li.LineIndex  (),
2783 //                             li.LineIndex10(),
2784 //                             li.LineIndex01(),
2785 //                             li.LineIndex11() };
2786 //     GridLine& line = _grid->_lines[ iDir ][ lineIndex[ indSub ]];
2787
2788 //     // analyze transition of previous ip
2789 //     bool isOut = true;
2790 //     multiset< F_IntersectPoint >::const_iterator ip = line._intPoints.begin();
2791 //     for ( ; ip != line._intPoints.end(); ++ip )
2792 //     {
2793 //       if ( &(*ip) == _hexLinks[ iLink ]._nodes[0]->_intPoint )
2794 //         break;
2795 //       switch ( ip->_transition ) {
2796 //       case Trans_OUT: isOut = true;
2797 //       case Trans_IN : isOut = false;
2798 //       default:;
2799 //       }
2800 //     }
2801 // #ifdef _DEBUG_
2802 //     if ( ip == line._intPoints.end() )
2803 //       cout << "BUG: Wrong GridLine. IKJ = ( "<< _i << " " << _j << " " << _k << " )" << endl;
2804 // #endif
2805     return isOut;
2806   }
2807   //================================================================================
2808   /*!
2809    * \brief Adds computed elements to the mesh
2810    */
2811   int Hexahedron::addElements(SMESH_MesherHelper& helper)
2812   {
2813     int nbAdded = 0;
2814     // add elements resulted from hexahedron intersection
2815     //for ( size_t i = 0; i < _volumeDefs.size(); ++i )
2816     {
2817       vector< const SMDS_MeshNode* > nodes( _volumeDefs._nodes.size() );
2818       for ( size_t iN = 0; iN < nodes.size(); ++iN )
2819         if ( !( nodes[iN] = _volumeDefs._nodes[iN]->Node() ))
2820         {
2821           if ( const E_IntersectPoint* eip = _volumeDefs._nodes[iN]->EdgeIntPnt() )
2822             nodes[iN] = _volumeDefs._nodes[iN]->_intPoint->_node =
2823               helper.AddNode( eip->_point.X(),
2824                               eip->_point.Y(),
2825                               eip->_point.Z() );
2826           else
2827             throw SALOME_Exception("Bug: no node at intersection point");
2828         }
2829
2830       if ( !_volumeDefs._quantities.empty() )
2831       {
2832         helper.AddPolyhedralVolume( nodes, _volumeDefs._quantities );
2833       }
2834       else
2835       {
2836         switch ( nodes.size() )
2837         {
2838         case 8: helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3],
2839                                   nodes[4],nodes[5],nodes[6],nodes[7] );
2840           break;
2841         case 4: helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3] );
2842           break;
2843         case 6: helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3], nodes[4],nodes[5] );
2844           break;
2845         case 5:
2846           helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3],nodes[4] );
2847           break;
2848         }
2849       }
2850       nbAdded += int ( _volumeDefs._nodes.size() > 0 );
2851     }
2852
2853     return nbAdded;
2854   }
2855   //================================================================================
2856   /*!
2857    * \brief Return true if the element is in a hole
2858    */
2859   bool Hexahedron::isInHole() const
2860   {
2861     if ( !_vertexNodes.empty() )
2862       return false;
2863
2864     const int ijk[3] = { _i, _j, _k };
2865     F_IntersectPoint curIntPnt;
2866
2867     // consider a cell to be in a hole if all links in any direction
2868     // comes OUT of geometry
2869     for ( int iDir = 0; iDir < 3; ++iDir )
2870     {
2871       const vector<double>& coords = _grid->_coords[ iDir ];
2872       LineIndexer               li = _grid->GetLineIndexer( iDir );
2873       li.SetIJK( _i,_j,_k );
2874       size_t lineIndex[4] = { li.LineIndex  (),
2875                               li.LineIndex10(),
2876                               li.LineIndex01(),
2877                               li.LineIndex11() };
2878       bool allLinksOut = true, hasLinks = false;
2879       for ( int iL = 0; iL < 4 && allLinksOut; ++iL ) // loop on 4 links parallel to iDir
2880       {
2881         const _Link& link = _hexLinks[ iL + 4*iDir ];
2882         // check transition of the first node of a link
2883         const F_IntersectPoint* firstIntPnt = 0;
2884         if ( link._nodes[0]->Node() ) // 1st node is a hexa corner
2885         {
2886           curIntPnt._paramOnLine = coords[ ijk[ iDir ]] - coords[0];
2887           const GridLine& line = _grid->_lines[ iDir ][ lineIndex[ iL ]];
2888           multiset< F_IntersectPoint >::const_iterator ip =
2889             line._intPoints.upper_bound( curIntPnt );
2890           --ip;
2891           firstIntPnt = &(*ip);
2892         }
2893         else if ( !link._intNodes.empty() )
2894         {
2895           firstIntPnt = link._intNodes[0].FaceIntPnt();
2896         }
2897
2898         if ( firstIntPnt )
2899         {
2900           hasLinks = true;
2901           allLinksOut = ( firstIntPnt->_transition == Trans_OUT );
2902         }
2903       }
2904       if ( hasLinks && allLinksOut )
2905         return true;
2906     }
2907     return false;
2908   }
2909
2910   //================================================================================
2911   /*!
2912    * \brief Return true if a polyhedron passes _sizeThreshold criterion
2913    */
2914   bool Hexahedron::checkPolyhedronSize() const
2915   {
2916     double volume = 0;
2917     for ( size_t iP = 0; iP < _polygons.size(); ++iP )
2918     {
2919       const _Face& polygon = _polygons[iP];
2920       gp_XYZ area (0,0,0);
2921       gp_XYZ p1 = polygon._links[ 0 ].FirstNode()->Point().XYZ();
2922       for ( size_t iL = 0; iL < polygon._links.size(); ++iL )
2923       {
2924         gp_XYZ p2 = polygon._links[ iL ].LastNode()->Point().XYZ();
2925         area += p1 ^ p2;
2926         p1 = p2;
2927       }
2928       volume += p1 * area;
2929     }
2930     volume /= 6;
2931
2932     double initVolume = _sideLength[0] * _sideLength[1] * _sideLength[2];
2933
2934     return volume > initVolume / _sizeThreshold;
2935   }
2936   //================================================================================
2937   /*!
2938    * \brief Tries to create a hexahedron
2939    */
2940   bool Hexahedron::addHexa()
2941   {
2942     if ( _polygons[0]._links.size() != 4 ||
2943          _polygons[1]._links.size() != 4 ||
2944          _polygons[2]._links.size() != 4 ||
2945          _polygons[3]._links.size() != 4 ||
2946          _polygons[4]._links.size() != 4 ||
2947          _polygons[5]._links.size() != 4   )
2948       return false;
2949     _Node* nodes[8];
2950     int nbN = 0;
2951     for ( int iL = 0; iL < 4; ++iL )
2952     {
2953       // a base node
2954       nodes[iL] = _polygons[0]._links[iL].FirstNode();
2955       ++nbN;
2956
2957       // find a top node above the base node
2958       _Link* link = _polygons[0]._links[iL]._link;
2959       //ASSERT( link->_faces.size() > 1 );
2960       if ( link->_faces.size() < 2 )
2961         return debugDumpLink( link );
2962       // a quadrangle sharing <link> with _polygons[0]
2963       _Face* quad = link->_faces[ bool( link->_faces[0] == & _polygons[0] )];
2964       for ( int i = 0; i < 4; ++i )
2965         if ( quad->_links[i]._link == link )
2966         {
2967           // 1st node of a link opposite to <link> in <quad>
2968           nodes[iL+4] = quad->_links[(i+2)%4].FirstNode();
2969           ++nbN;
2970           break;
2971         }
2972     }
2973     if ( nbN == 8 )
2974       _volumeDefs.set( vector< _Node* >( nodes, nodes+8 ));
2975
2976     return nbN == 8;
2977   }
2978   //================================================================================
2979   /*!
2980    * \brief Tries to create a tetrahedron
2981    */
2982   bool Hexahedron::addTetra()
2983   {
2984     _Node* nodes[4];
2985     nodes[0] = _polygons[0]._links[0].FirstNode();
2986     nodes[1] = _polygons[0]._links[1].FirstNode();
2987     nodes[2] = _polygons[0]._links[2].FirstNode();
2988
2989     _Link* link = _polygons[0]._links[0]._link;
2990     //ASSERT( link->_faces.size() > 1 );
2991     if ( link->_faces.size() < 2 )
2992       return debugDumpLink( link );
2993
2994     // a triangle sharing <link> with _polygons[0]
2995     _Face* tria = link->_faces[ bool( link->_faces[0] == & _polygons[0] )];
2996     for ( int i = 0; i < 3; ++i )
2997       if ( tria->_links[i]._link == link )
2998       {
2999         nodes[3] = tria->_links[(i+1)%3].LastNode();
3000         _volumeDefs.set( vector< _Node* >( nodes, nodes+4 ));
3001         return true;
3002       }
3003
3004     return false;
3005   }
3006   //================================================================================
3007   /*!
3008    * \brief Tries to create a pentahedron
3009    */
3010   bool Hexahedron::addPenta()
3011   {
3012     // find a base triangular face
3013     int iTri = -1;
3014     for ( int iF = 0; iF < 5 && iTri < 0; ++iF )
3015       if ( _polygons[ iF ]._links.size() == 3 )
3016         iTri = iF;
3017     if ( iTri < 0 ) return false;
3018
3019     // find nodes
3020     _Node* nodes[6];
3021     int nbN = 0;
3022     for ( int iL = 0; iL < 3; ++iL )
3023     {
3024       // a base node
3025       nodes[iL] = _polygons[ iTri ]._links[iL].FirstNode();
3026       ++nbN;
3027
3028       // find a top node above the base node
3029       _Link* link = _polygons[ iTri ]._links[iL]._link;
3030       //ASSERT( link->_faces.size() > 1 );
3031       if ( link->_faces.size() < 2 )
3032         return debugDumpLink( link );
3033       // a quadrangle sharing <link> with a base triangle
3034       _Face* quad = link->_faces[ bool( link->_faces[0] == & _polygons[ iTri ] )];
3035       if ( quad->_links.size() != 4 ) return false;
3036       for ( int i = 0; i < 4; ++i )
3037         if ( quad->_links[i]._link == link )
3038         {
3039           // 1st node of a link opposite to <link> in <quad>
3040           nodes[iL+3] = quad->_links[(i+2)%4].FirstNode();
3041           ++nbN;
3042           break;
3043         }
3044     }
3045     if ( nbN == 6 )
3046       _volumeDefs.set( vector< _Node* >( nodes, nodes+6 ));
3047
3048     return ( nbN == 6 );
3049   }
3050   //================================================================================
3051   /*!
3052    * \brief Tries to create a pyramid
3053    */
3054   bool Hexahedron::addPyra()
3055   {
3056     // find a base quadrangle
3057     int iQuad = -1;
3058     for ( int iF = 0; iF < 5 && iQuad < 0; ++iF )
3059       if ( _polygons[ iF ]._links.size() == 4 )
3060         iQuad = iF;
3061     if ( iQuad < 0 ) return false;
3062
3063     // find nodes
3064     _Node* nodes[5];
3065     nodes[0] = _polygons[iQuad]._links[0].FirstNode();
3066     nodes[1] = _polygons[iQuad]._links[1].FirstNode();
3067     nodes[2] = _polygons[iQuad]._links[2].FirstNode();
3068     nodes[3] = _polygons[iQuad]._links[3].FirstNode();
3069
3070     _Link* link = _polygons[iQuad]._links[0]._link;
3071     ASSERT( link->_faces.size() > 1 );
3072     if ( link->_faces.size() < 2 )
3073       return debugDumpLink( link );
3074
3075     // a triangle sharing <link> with a base quadrangle
3076     _Face* tria = link->_faces[ bool( link->_faces[0] == & _polygons[ iQuad ] )];
3077     if ( tria->_links.size() != 3 ) return false;
3078     for ( int i = 0; i < 3; ++i )
3079       if ( tria->_links[i]._link == link )
3080       {
3081         nodes[4] = tria->_links[(i+1)%3].LastNode();
3082         _volumeDefs.set( vector< _Node* >( nodes, nodes+5 ));
3083         return true;
3084       }
3085
3086     return false;
3087   }
3088   //================================================================================
3089   /*!
3090    * \brief Dump a link and return \c false
3091    */
3092   bool Hexahedron::debugDumpLink( Hexahedron::_Link* link )
3093   {
3094 #ifdef _DEBUG_
3095     gp_Pnt p1 = link->_nodes[0]->Point(), p2 = link->_nodes[1]->Point();
3096     cout << "BUG: not shared link. IKJ = ( "<< _i << " " << _j << " " << _k << " )" << endl
3097          << "n1 (" << p1.X() << ", "<< p1.Y() << ", "<< p1.Z() << " )" << endl
3098          << "n2 (" << p2.X() << ", "<< p2.Y() << ", "<< p2.Z() << " )" << endl;
3099 #endif
3100     return false;
3101   }
3102
3103   //================================================================================
3104   /*!
3105    * \brief computes exact bounding box with axes parallel to given ones
3106    */
3107   //================================================================================
3108
3109   void getExactBndBox( const vector< TopoDS_Shape >& faceVec,
3110                        const double*                 axesDirs,
3111                        Bnd_Box&                      shapeBox )
3112   {
3113     BRep_Builder b;
3114     TopoDS_Compound allFacesComp;
3115     b.MakeCompound( allFacesComp );
3116     for ( size_t iF = 0; iF < faceVec.size(); ++iF )
3117       b.Add( allFacesComp, faceVec[ iF ] );
3118
3119     double sP[6]; // aXmin, aYmin, aZmin, aXmax, aYmax, aZmax
3120     shapeBox.Get(sP[0],sP[1],sP[2],sP[3],sP[4],sP[5]);
3121     double farDist = 0;
3122     for ( int i = 0; i < 6; ++i )
3123       farDist = Max( farDist, 10 * sP[i] );
3124
3125     gp_XYZ axis[3] = { gp_XYZ( axesDirs[0], axesDirs[1], axesDirs[2] ),
3126                        gp_XYZ( axesDirs[3], axesDirs[4], axesDirs[5] ),
3127                        gp_XYZ( axesDirs[6], axesDirs[7], axesDirs[8] ) };
3128     axis[0].Normalize();
3129     axis[1].Normalize();
3130     axis[2].Normalize();
3131
3132     gp_Mat basis( axis[0], axis[1], axis[2] );
3133     gp_Mat bi = basis.Inverted();
3134
3135     gp_Pnt pMin, pMax;
3136     for ( int iDir = 0; iDir < 3; ++iDir )
3137     {
3138       gp_XYZ axis0 = axis[ iDir ];
3139       gp_XYZ axis1 = axis[ ( iDir + 1 ) % 3 ];
3140       gp_XYZ axis2 = axis[ ( iDir + 2 ) % 3 ];
3141       for ( int isMax = 0; isMax < 2; ++isMax )
3142       {
3143         double shift = isMax ? farDist : -farDist;
3144         gp_XYZ orig = shift * axis0;
3145         gp_XYZ norm = axis1 ^ axis2;
3146         gp_Pln pln( orig, norm );
3147         norm = pln.Axis().Direction().XYZ();
3148         BRepBuilderAPI_MakeFace plane( pln, -farDist, farDist, -farDist, farDist );
3149
3150         gp_Pnt& pAxis = isMax ? pMax : pMin;
3151         gp_Pnt pPlane, pFaces;
3152         double dist = GEOMUtils::GetMinDistance( plane, allFacesComp, pPlane, pFaces );
3153         if ( dist < 0 )
3154         {
3155           Bnd_B3d bb;
3156           gp_XYZ corner;
3157           for ( int i = 0; i < 2; ++i ) {
3158             corner.SetCoord( 1, sP[ i*3 ]);
3159             for ( int j = 0; j < 2; ++j ) {
3160               corner.SetCoord( 2, sP[ i*3 + 1 ]);
3161               for ( int k = 0; k < 2; ++k )
3162               {
3163                 corner.SetCoord( 3, sP[ i*3 + 2 ]);
3164                 corner *= bi;
3165                 bb.Add( corner );
3166               }
3167             }
3168           }
3169           corner = isMax ? bb.CornerMax() : bb.CornerMin();
3170           pAxis.SetCoord( iDir+1, corner.Coord( iDir+1 ));
3171         }
3172         else
3173         {
3174           gp_XYZ pf = pFaces.XYZ() * bi;
3175           pAxis.SetCoord( iDir+1, pf.Coord( iDir+1 ) );
3176         }
3177       }
3178     } // loop on 3 axes
3179
3180     shapeBox.SetVoid();
3181     shapeBox.Add( pMin );
3182     shapeBox.Add( pMax );
3183
3184     return;
3185   }
3186
3187 } // namespace
3188
3189 //=============================================================================
3190 /*!
3191  * \brief Generates 3D structured Cartesian mesh in the internal part of
3192  * solid shapes and polyhedral volumes near the shape boundary.
3193  *  \param theMesh - mesh to fill in
3194  *  \param theShape - a compound of all SOLIDs to mesh
3195  *  \retval bool - true in case of success
3196  */
3197 //=============================================================================
3198
3199 bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh &         theMesh,
3200                                       const TopoDS_Shape & theShape)
3201 {
3202   // The algorithm generates the mesh in following steps:
3203
3204   // 1) Intersection of grid lines with the geometry boundary.
3205   // This step allows to find out if a given node of the initial grid is
3206   // inside or outside the geometry.
3207
3208   // 2) For each cell of the grid, check how many of it's nodes are outside
3209   // of the geometry boundary. Depending on a result of this check
3210   // - skip a cell, if all it's nodes are outside
3211   // - skip a cell, if it is too small according to the size threshold
3212   // - add a hexahedron in the mesh, if all nodes are inside
3213   // - add a polyhedron in the mesh, if some nodes are inside and some outside
3214
3215   _computeCanceled = false;
3216
3217   SMESH_MesherHelper helper( theMesh );
3218
3219   try
3220   {
3221     Grid grid;
3222     grid._helper = &helper;
3223
3224     vector< TopoDS_Shape > faceVec;
3225     {
3226       TopTools_MapOfShape faceMap;
3227       TopExp_Explorer fExp;
3228       for ( fExp.Init( theShape, TopAbs_FACE ); fExp.More(); fExp.Next() )
3229         if ( !faceMap.Add( fExp.Current() ))
3230           faceMap.Remove( fExp.Current() ); // remove a face shared by two solids
3231
3232       for ( fExp.ReInit(); fExp.More(); fExp.Next() )
3233         if ( faceMap.Contains( fExp.Current() ))
3234           faceVec.push_back( fExp.Current() );
3235     }
3236     vector<FaceGridIntersector> facesItersectors( faceVec.size() );
3237     map< TGeomID, vector< TGeomID > > edge2faceIDsMap;
3238     TopExp_Explorer eExp;
3239     Bnd_Box shapeBox;
3240     for ( int i = 0; i < faceVec.size(); ++i )
3241     {
3242       facesItersectors[i]._face   = TopoDS::Face    ( faceVec[i] );
3243       facesItersectors[i]._faceID = grid._shapes.Add( faceVec[i] );
3244       facesItersectors[i]._grid   = &grid;
3245       shapeBox.Add( facesItersectors[i].GetFaceBndBox() );
3246
3247       if ( _hyp->GetToAddEdges() )
3248       {
3249         helper.SetSubShape( faceVec[i] );
3250         for ( eExp.Init( faceVec[i], TopAbs_EDGE ); eExp.More(); eExp.Next() )
3251         {
3252           const TopoDS_Edge& edge = TopoDS::Edge( eExp.Current() );
3253           if ( !SMESH_Algo::isDegenerated( edge ) &&
3254                !helper.IsRealSeam( edge ))
3255             edge2faceIDsMap[ grid._shapes.Add( edge )].push_back( facesItersectors[i]._faceID );
3256         }
3257       }
3258     }
3259
3260     getExactBndBox( faceVec, _hyp->GetAxisDirs(), shapeBox );
3261
3262     vector<double> xCoords, yCoords, zCoords;
3263     _hyp->GetCoordinates( xCoords, yCoords, zCoords, shapeBox );
3264
3265     grid.SetCoordinates( xCoords, yCoords, zCoords, _hyp->GetAxisDirs(), shapeBox );
3266
3267     if ( _computeCanceled ) return false;
3268
3269 #ifdef WITH_TBB
3270     { // copy partner faces and curves of not thread-safe types
3271       set< const Standard_Transient* > tshapes;
3272       BRepBuilderAPI_Copy copier;
3273       for ( size_t i = 0; i < facesItersectors.size(); ++i )
3274       {
3275         if ( !facesItersectors[i].IsThreadSafe(tshapes) )
3276         {
3277           copier.Perform( facesItersectors[i]._face );
3278           facesItersectors[i]._face = TopoDS::Face( copier );
3279         }
3280       }
3281     }
3282     // Intersection of grid lines with the geometry boundary.
3283     tbb::parallel_for ( tbb::blocked_range<size_t>( 0, facesItersectors.size() ),
3284                         ParallelIntersector( facesItersectors ),
3285                         tbb::simple_partitioner());
3286 #else
3287     for ( size_t i = 0; i < facesItersectors.size(); ++i )
3288       facesItersectors[i].Intersect();
3289 #endif
3290
3291     // put interesection points onto the GridLine's; this is done after intersection
3292     // to avoid contention of facesItersectors for writing into the same GridLine
3293     // in case of parallel work of facesItersectors
3294     for ( size_t i = 0; i < facesItersectors.size(); ++i )
3295       facesItersectors[i].StoreIntersections();
3296
3297     TopExp_Explorer solidExp (theShape, TopAbs_SOLID);
3298     helper.SetSubShape( solidExp.Current() );
3299     helper.SetElementsOnShape( true );
3300
3301     if ( _computeCanceled ) return false;
3302
3303     // create nodes on the geometry
3304     grid.ComputeNodes(helper);
3305
3306     if ( _computeCanceled ) return false;
3307
3308     // create volume elements
3309     Hexahedron hex( _hyp->GetSizeThreshold(), &grid );
3310     int nbAdded = hex.MakeElements( helper, edge2faceIDsMap );
3311
3312     SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
3313     if ( nbAdded > 0 )
3314     {
3315       // make all SOLIDs computed
3316       if ( SMESHDS_SubMesh* sm1 = meshDS->MeshElements( solidExp.Current()) )
3317       {
3318         SMDS_ElemIteratorPtr volIt = sm1->GetElements();
3319         for ( ; solidExp.More() && volIt->more(); solidExp.Next() )
3320         {
3321           const SMDS_MeshElement* vol = volIt->next();
3322           sm1->RemoveElement( vol, /*isElemDeleted=*/false );
3323           meshDS->SetMeshElementOnShape( vol, solidExp.Current() );
3324         }
3325       }
3326       // make other sub-shapes computed
3327       setSubmeshesComputed( theMesh, theShape );
3328     }
3329
3330     // remove free nodes
3331     if ( SMESHDS_SubMesh * smDS = meshDS->MeshElements( helper.GetSubShapeID() ))
3332     {
3333       TIDSortedNodeSet nodesToRemove;
3334       // get intersection nodes
3335       for ( int iDir = 0; iDir < 3; ++iDir )
3336       {
3337         vector< GridLine >& lines = grid._lines[ iDir ];
3338         for ( size_t i = 0; i < lines.size(); ++i )
3339         {
3340           multiset< F_IntersectPoint >::iterator ip = lines[i]._intPoints.begin();
3341           for ( ; ip != lines[i]._intPoints.end(); ++ip )
3342             if ( ip->_node && ip->_node->NbInverseElements() == 0 )
3343               nodesToRemove.insert( nodesToRemove.end(), ip->_node );
3344         }
3345       }
3346       // get grid nodes
3347       for ( size_t i = 0; i < grid._nodes.size(); ++i )
3348         if ( grid._nodes[i] && grid._nodes[i]->NbInverseElements() == 0 )
3349           nodesToRemove.insert( nodesToRemove.end(), grid._nodes[i] );
3350
3351       // do remove
3352       TIDSortedNodeSet::iterator n = nodesToRemove.begin();
3353       for ( ; n != nodesToRemove.end(); ++n )
3354         meshDS->RemoveFreeNode( *n, smDS, /*fromGroups=*/false );
3355     }
3356
3357     return nbAdded;
3358
3359   }
3360   // SMESH_ComputeError is not caught at SMESH_submesh level for an unknown reason
3361   catch ( SMESH_ComputeError& e)
3362   {
3363     return error( SMESH_ComputeErrorPtr( new SMESH_ComputeError( e )));
3364   }
3365   return false;
3366 }
3367
3368 //=============================================================================
3369 /*!
3370  *  Evaluate
3371  */
3372 //=============================================================================
3373
3374 bool StdMeshers_Cartesian_3D::Evaluate(SMESH_Mesh &         theMesh,
3375                                        const TopoDS_Shape & theShape,
3376                                        MapShapeNbElems&     theResMap)
3377 {
3378   // TODO
3379 //   std::vector<int> aResVec(SMDSEntity_Last);
3380 //   for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
3381 //   if(IsQuadratic) {
3382 //     aResVec[SMDSEntity_Quad_Cartesian] = nb2d_face0 * ( nb2d/nb1d );
3383 //     int nb1d_face0_int = ( nb2d_face0*4 - nb1d ) / 2;
3384 //     aResVec[SMDSEntity_Node] = nb0d_face0 * ( 2*nb2d/nb1d - 1 ) - nb1d_face0_int * nb2d/nb1d;
3385 //   }
3386 //   else {
3387 //     aResVec[SMDSEntity_Node] = nb0d_face0 * ( nb2d/nb1d - 1 );
3388 //     aResVec[SMDSEntity_Cartesian] = nb2d_face0 * ( nb2d/nb1d );
3389 //   }
3390 //   SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);
3391 //   aResMap.insert(std::make_pair(sm,aResVec));
3392
3393   return true;
3394 }
3395
3396 //=============================================================================
3397 namespace
3398 {
3399   /*!
3400    * \brief Event listener setting/unsetting _alwaysComputed flag to
3401    *        submeshes of inferior levels to prevent their computing
3402    */
3403   struct _EventListener : public SMESH_subMeshEventListener
3404   {
3405     string _algoName;
3406
3407     _EventListener(const string& algoName):
3408       SMESH_subMeshEventListener(/*isDeletable=*/true,"StdMeshers_Cartesian_3D::_EventListener"),
3409       _algoName(algoName)
3410     {}
3411     // --------------------------------------------------------------------------------
3412     // setting/unsetting _alwaysComputed flag to submeshes of inferior levels
3413     //
3414     static void setAlwaysComputed( const bool     isComputed,
3415                                    SMESH_subMesh* subMeshOfSolid)
3416     {
3417       SMESH_subMeshIteratorPtr smIt =
3418         subMeshOfSolid->getDependsOnIterator(/*includeSelf=*/false, /*complexShapeFirst=*/false);
3419       while ( smIt->more() )
3420       {
3421         SMESH_subMesh* sm = smIt->next();
3422         sm->SetIsAlwaysComputed( isComputed );
3423       }
3424       subMeshOfSolid->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
3425     }
3426
3427     // --------------------------------------------------------------------------------
3428     // unsetting _alwaysComputed flag if "Cartesian_3D" was removed
3429     //
3430     virtual void ProcessEvent(const int          event,
3431                               const int          eventType,
3432                               SMESH_subMesh*     subMeshOfSolid,
3433                               SMESH_subMeshEventListenerData* data,
3434                               const SMESH_Hypothesis*         hyp = 0)
3435     {
3436       if ( eventType == SMESH_subMesh::COMPUTE_EVENT )
3437       {
3438         setAlwaysComputed( subMeshOfSolid->GetComputeState() == SMESH_subMesh::COMPUTE_OK,
3439                            subMeshOfSolid );
3440       }
3441       else
3442       {
3443         SMESH_Algo* algo3D = subMeshOfSolid->GetAlgo();
3444         if ( !algo3D || _algoName != algo3D->GetName() )
3445           setAlwaysComputed( false, subMeshOfSolid );
3446       }
3447     }
3448
3449     // --------------------------------------------------------------------------------
3450     // set the event listener
3451     //
3452     static void SetOn( SMESH_subMesh* subMeshOfSolid, const string& algoName )
3453     {
3454       subMeshOfSolid->SetEventListener( new _EventListener( algoName ),
3455                                         /*data=*/0,
3456                                         subMeshOfSolid );
3457     }
3458
3459   }; // struct _EventListener
3460
3461 } // namespace
3462
3463 //================================================================================
3464 /*!
3465  * \brief Sets event listener to submeshes if necessary
3466  *  \param subMesh - submesh where algo is set
3467  * This method is called when a submesh gets HYP_OK algo_state.
3468  * After being set, event listener is notified on each event of a submesh.
3469  */
3470 //================================================================================
3471
3472 void StdMeshers_Cartesian_3D::SetEventListener(SMESH_subMesh* subMesh)
3473 {
3474   _EventListener::SetOn( subMesh, GetName() );
3475 }
3476
3477 //================================================================================
3478 /*!
3479  * \brief Set _alwaysComputed flag to submeshes of inferior levels to avoid their computing
3480  */
3481 //================================================================================
3482
3483 void StdMeshers_Cartesian_3D::setSubmeshesComputed(SMESH_Mesh&         theMesh,
3484                                                    const TopoDS_Shape& theShape)
3485 {
3486   for ( TopExp_Explorer soExp( theShape, TopAbs_SOLID ); soExp.More(); soExp.Next() )
3487     _EventListener::setAlwaysComputed( true, theMesh.GetSubMesh( soExp.Current() ));
3488 }
3489