]> SALOME platform Git repositories - modules/smesh.git/blob - src/StdMeshers/StdMeshers_Cartesian_3D.cxx
Salome HOME
ILMAB: export GEOM fields to MED file
[modules/smesh.git] / src / StdMeshers / StdMeshers_Cartesian_3D.cxx
1 // Copyright (C) 2007-2014  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, or (at your option) any later version.
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 ( quad._edgeNodes.size() > nbUsedEdgeNodes )
1938       {
1939         // make _vertexNodes from not used _edgeNodes
1940         const double tol = 0.05 * Min( Min( _sideLength[0], _sideLength[1] ), _sideLength[0] );
1941         for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
1942         {
1943           if ( quad._edgeNodes[ iP ]._isUsedInFace ) continue;
1944           _Node* equalNode =
1945             FindEqualNode( _vertexNodes, quad._edgeNodes[ iP ].EdgeIntPnt(), tol*tol );
1946           if ( equalNode )
1947             equalNode->Add( quad._edgeNodes[ iP ].EdgeIntPnt() );
1948           else
1949             _vertexNodes.push_back( quad._edgeNodes[ iP ]);
1950         }
1951       }
1952
1953       if ( polygon->_links.size() < 3 )
1954         _polygons.pop_back();
1955
1956     }  // loop on 6 sides of a hexahedron
1957
1958     // Create polygons closing holes in a polyhedron
1959     // ----------------------------------------------
1960
1961     // add polygons to their links
1962     for ( size_t iP = 0; iP < _polygons.size(); ++iP )
1963     {
1964       _Face& polygon = _polygons[ iP ];
1965       for ( size_t iL = 0; iL < polygon._links.size(); ++iL )
1966       {
1967         polygon._links[ iL ]._link->_faces.reserve( 2 );
1968         polygon._links[ iL ]._link->_faces.push_back( &polygon );
1969       }
1970     }
1971     // find free links
1972     vector< _OrientedLink* > freeLinks;
1973     freeLinks.reserve(20);
1974     for ( size_t iP = 0; iP < _polygons.size(); ++iP )
1975     {
1976       _Face& polygon = _polygons[ iP ];
1977       for ( size_t iL = 0; iL < polygon._links.size(); ++iL )
1978         if ( polygon._links[ iL ]._link->_faces.size() < 2 )
1979           freeLinks.push_back( & polygon._links[ iL ]);
1980     }
1981     int nbFreeLinks = freeLinks.size();
1982     if ( nbFreeLinks > 0 && nbFreeLinks < 3 ) return;
1983
1984     set<TGeomID> usedFaceIDs;
1985
1986     // make closed chains of free links
1987     while ( nbFreeLinks > 0 )
1988     {
1989       _polygons.resize( _polygons.size() + 1 );
1990       _Face& polygon = _polygons.back();
1991       polygon._polyLinks.reserve( 20 );
1992       polygon._links.reserve( 20 );
1993
1994       _OrientedLink* curLink = 0;
1995       _Node*         curNode;
1996       if (( !hasEdgeIntersections ) ||
1997           ( nbFreeLinks < 4 && _vertexNodes.empty() ))
1998       {
1999         // get a remaining link to start from
2000         for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL )
2001           if (( curLink = freeLinks[ iL ] ))
2002             freeLinks[ iL ] = 0;
2003         polygon._links.push_back( *curLink );
2004         --nbFreeLinks;
2005         do
2006         {
2007           // find all links connected to curLink
2008           curNode = curLink->FirstNode();
2009           curLink = 0;
2010           for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL )
2011             if ( freeLinks[ iL ] && freeLinks[ iL ]->LastNode() == curNode )
2012             {
2013               curLink = freeLinks[ iL ];
2014               freeLinks[ iL ] = 0;
2015               --nbFreeLinks;
2016               polygon._links.push_back( *curLink );
2017             }
2018         } while ( curLink );
2019       }
2020       else // there are intersections with EDGEs
2021       {
2022         TGeomID curFace;
2023         // get a remaining link to start from, one lying on minimal
2024         // nb of FACEs
2025         {
2026           vector< pair< TGeomID, int > > facesOfLink[3];
2027           pair< TGeomID, int > faceOfLink( -1, -1 );
2028           vector< TGeomID > faces;
2029           for ( size_t iL = 0; iL < freeLinks.size(); ++iL )
2030             if ( freeLinks[ iL ] )
2031             {
2032               faces = freeLinks[ iL ]->GetNotUsedFace( usedFaceIDs );
2033               if ( faces.size() == 1 )
2034               {
2035                 faceOfLink = make_pair( faces[0], iL );
2036                 if ( !freeLinks[ iL ]->HasEdgeNodes() )
2037                   break;
2038                 facesOfLink[0].push_back( faceOfLink );
2039               }
2040               else if ( facesOfLink[0].empty() )
2041               {
2042                 faceOfLink = make_pair(( faces.empty() ? -1 : faces[0]), iL );
2043                 facesOfLink[ 1 + faces.empty() ].push_back( faceOfLink );
2044               }
2045             }
2046           for ( int i = 0; faceOfLink.second < 0 && i < 3; ++i )
2047             if ( !facesOfLink[i].empty() )
2048               faceOfLink = facesOfLink[i][0];
2049
2050           if ( faceOfLink.first < 0 ) // all faces used
2051           {
2052             for ( size_t i = 0; i < facesOfLink[2].size() && faceOfLink.first < 1; ++i )
2053             {
2054               curLink = freeLinks[ facesOfLink[2][i].second ];
2055               faceOfLink.first = curLink->FirstNode()->IsLinked( curLink->FirstNode()->_intPoint );
2056             }
2057             usedFaceIDs.clear();
2058           }
2059           curFace = faceOfLink.first;
2060           curLink = freeLinks[ faceOfLink.second ];
2061           freeLinks[ faceOfLink.second ] = 0;
2062         }
2063         usedFaceIDs.insert( curFace );
2064         polygon._links.push_back( *curLink );
2065         --nbFreeLinks;
2066
2067         // find all links bounding a FACE of curLink
2068         do
2069         {
2070           // go forward from curLink
2071           curNode = curLink->LastNode();
2072           curLink = 0;
2073           for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL )
2074             if ( freeLinks[ iL ] &&
2075                  freeLinks[ iL ]->FirstNode() == curNode &&
2076                  freeLinks[ iL ]->LastNode()->IsOnFace( curFace ))
2077             {
2078               curLink = freeLinks[ iL ];
2079               freeLinks[ iL ] = 0;
2080               polygon._links.push_back( *curLink );
2081               --nbFreeLinks;
2082             }
2083         } while ( curLink );
2084
2085         std::reverse( polygon._links.begin(), polygon._links.end() );
2086
2087         curLink = & polygon._links.back();
2088         do
2089         {
2090           // go backward from curLink
2091           curNode = curLink->FirstNode();
2092           curLink = 0;
2093           for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL )
2094             if ( freeLinks[ iL ] &&
2095                  freeLinks[ iL ]->LastNode() == curNode &&
2096                  freeLinks[ iL ]->FirstNode()->IsOnFace( curFace ))
2097             {
2098               curLink = freeLinks[ iL ];
2099               freeLinks[ iL ] = 0;
2100               polygon._links.push_back( *curLink );
2101               --nbFreeLinks;
2102             }
2103         } while ( curLink );
2104
2105         curNode = polygon._links.back().FirstNode();
2106
2107         if ( polygon._links[0].LastNode() != curNode )
2108         {
2109           if ( !_vertexNodes.empty() )
2110           {
2111             // add links with _vertexNodes if not already used
2112             for ( size_t iN = 0; iN < _vertexNodes.size(); ++iN )
2113               if ( _vertexNodes[ iN ].IsOnFace( curFace ))
2114               {
2115                 bool used = ( curNode == &_vertexNodes[ iN ] );
2116                 for ( size_t iL = 0; iL < polygon._links.size() && !used; ++iL )
2117                   used = ( &_vertexNodes[ iN ] ==  polygon._links[ iL ].LastNode() );
2118                 if ( !used )
2119                 {
2120                   polyLink._nodes[0] = &_vertexNodes[ iN ];
2121                   polyLink._nodes[1] = curNode;
2122                   polygon._polyLinks.push_back( polyLink );
2123                   polygon._links.push_back( _OrientedLink( &polygon._polyLinks.back() ));
2124                   freeLinks.push_back( &polygon._links.back() );
2125                   ++nbFreeLinks;
2126                   curNode = &_vertexNodes[ iN ];
2127                 }
2128                 // TODO: to reorder _vertexNodes within polygon, if there are several ones
2129               }
2130           }
2131           // if ( polygon._links.size() > 1 )
2132           {
2133             polyLink._nodes[0] = polygon._links[0].LastNode();
2134             polyLink._nodes[1] = curNode;
2135             polygon._polyLinks.push_back( polyLink );
2136             polygon._links.push_back( _OrientedLink( &polygon._polyLinks.back() ));
2137             freeLinks.push_back( &polygon._links.back() );
2138             ++nbFreeLinks;
2139           }
2140         }
2141
2142       } // if there are intersections with EDGEs
2143
2144       if ( polygon._links.size() < 2 ||
2145            polygon._links[0].LastNode() != polygon._links.back().FirstNode() )
2146         return; // closed polygon not found -> invalid polyhedron
2147
2148       if ( polygon._links.size() == 2 )
2149       {
2150         if ( freeLinks.back() == &polygon._links.back() )
2151         {
2152           freeLinks.back() = 0;
2153           --nbFreeLinks;
2154         }
2155         vector< _Face*>& polygs1 = polygon._links.front()._link->_faces;
2156         vector< _Face*>& polygs2 = polygon._links.back()._link->_faces;
2157         _Face* polyg1 = ( polygs1.empty() ? 0 : polygs1[0] );
2158         _Face* polyg2 = ( polygs2.empty() ? 0 : polygs2[0] );
2159         if ( polyg1 ) polygs2.push_back( polyg1 );
2160         if ( polyg2 ) polygs1.push_back( polyg2 );
2161         _polygons.pop_back();
2162       }
2163       else
2164       {
2165         // add polygon to its links
2166         for ( size_t iL = 0; iL < polygon._links.size(); ++iL )
2167         {
2168           polygon._links[ iL ]._link->_faces.reserve( 2 );
2169           polygon._links[ iL ]._link->_faces.push_back( &polygon );
2170           polygon._links[ iL ].Reverse();
2171         }
2172       }
2173     } // while ( nbFreeLinks > 0 )
2174
2175     if ( ! checkPolyhedronSize() )
2176     {
2177       return;
2178     }
2179
2180     // create a classic cell if possible
2181     const int nbNodes = _nbCornerNodes + _nbIntNodes;
2182     bool isClassicElem = false;
2183     if (      nbNodes == 8 && _polygons.size() == 6 ) isClassicElem = addHexa();
2184     else if ( nbNodes == 4 && _polygons.size() == 4 ) isClassicElem = addTetra();
2185     else if ( nbNodes == 6 && _polygons.size() == 5 ) isClassicElem = addPenta();
2186     else if ( nbNodes == 5 && _polygons.size() == 5 ) isClassicElem = addPyra ();
2187     if ( !isClassicElem )
2188     {
2189       _volumeDefs._nodes.clear();
2190       _volumeDefs._quantities.clear();
2191
2192       for ( size_t iF = 0; iF < _polygons.size(); ++iF )
2193       {
2194         const size_t nbLinks = _polygons[ iF ]._links.size();
2195         _volumeDefs._quantities.push_back( nbLinks );
2196         for ( size_t iL = 0; iL < nbLinks; ++iL )
2197           _volumeDefs._nodes.push_back( _polygons[ iF ]._links[ iL ].FirstNode() );
2198       }
2199     }
2200   }
2201   //================================================================================
2202   /*!
2203    * \brief Create elements in the mesh
2204    */
2205   int Hexahedron::MakeElements(SMESH_MesherHelper&                      helper,
2206                                const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap)
2207   {
2208     SMESHDS_Mesh* mesh = helper.GetMeshDS();
2209
2210     size_t nbCells[3] = { _grid->_coords[0].size() - 1,
2211                           _grid->_coords[1].size() - 1,
2212                           _grid->_coords[2].size() - 1 };
2213     const size_t nbGridCells = nbCells[0] * nbCells[1] * nbCells[2];
2214     vector< Hexahedron* > intersectedHex( nbGridCells, 0 );
2215     int nbIntHex = 0;
2216
2217     // set intersection nodes from GridLine's to links of intersectedHex
2218     int i,j,k, iDirOther[3][2] = {{ 1,2 },{ 0,2 },{ 0,1 }};
2219     for ( int iDir = 0; iDir < 3; ++iDir )
2220     {
2221       int dInd[4][3] = { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} };
2222       dInd[1][ iDirOther[iDir][0] ] = -1;
2223       dInd[2][ iDirOther[iDir][1] ] = -1;
2224       dInd[3][ iDirOther[iDir][0] ] = -1; dInd[3][ iDirOther[iDir][1] ] = -1;
2225       // loop on GridLine's parallel to iDir
2226       LineIndexer lineInd = _grid->GetLineIndexer( iDir );
2227       for ( ; lineInd.More(); ++lineInd )
2228       {
2229         GridLine& line = _grid->_lines[ iDir ][ lineInd.LineIndex() ];
2230         multiset< F_IntersectPoint >::const_iterator ip = line._intPoints.begin();
2231         for ( ; ip != line._intPoints.end(); ++ip )
2232         {
2233           // if ( !ip->_node ) continue; // intersection at a grid node
2234           lineInd.SetIndexOnLine( ip->_indexOnLine );
2235           for ( int iL = 0; iL < 4; ++iL ) // loop on 4 cells sharing a link
2236           {
2237             i = int(lineInd.I()) + dInd[iL][0];
2238             j = int(lineInd.J()) + dInd[iL][1];
2239             k = int(lineInd.K()) + dInd[iL][2];
2240             if ( i < 0 || i >= nbCells[0] ||
2241                  j < 0 || j >= nbCells[1] ||
2242                  k < 0 || k >= nbCells[2] ) continue;
2243
2244             const size_t hexIndex = _grid->CellIndex( i,j,k );
2245             Hexahedron *& hex = intersectedHex[ hexIndex ];
2246             if ( !hex)
2247             {
2248               hex = new Hexahedron( *this );
2249               hex->_i = i;
2250               hex->_j = j;
2251               hex->_k = k;
2252               ++nbIntHex;
2253             }
2254             const int iLink = iL + iDir * 4;
2255             hex->_hexLinks[iLink]._intNodes.push_back( _Node( 0, &(*ip) ));
2256             hex->_nbIntNodes += bool( ip->_node );
2257           }
2258         }
2259       }
2260     }
2261
2262     // implement geom edges into the mesh
2263     addEdges( helper, intersectedHex, edge2faceIDsMap );
2264
2265     // add not split hexadrons to the mesh
2266     int nbAdded = 0;
2267     vector<int> intHexInd( nbIntHex );
2268     nbIntHex = 0;
2269     for ( size_t i = 0; i < intersectedHex.size(); ++i )
2270     {
2271       Hexahedron * & hex = intersectedHex[ i ];
2272       if ( hex )
2273       {
2274         intHexInd[ nbIntHex++ ] = i;
2275         if ( hex->_nbIntNodes > 0 || ! hex->_edgeIntPnts.empty())
2276           continue; // treat intersected hex later
2277         this->init( hex->_i, hex->_j, hex->_k );
2278       }
2279       else
2280       {    
2281         this->init( i );
2282       }
2283       if (( _nbCornerNodes == 8 ) &&
2284           ( _nbBndNodes < _nbCornerNodes || !isInHole() ))
2285       {
2286         // order of _hexNodes is defined by enum SMESH_Block::TShapeID
2287         SMDS_MeshElement* el =
2288           mesh->AddVolume( _hexNodes[0].Node(), _hexNodes[2].Node(),
2289                            _hexNodes[3].Node(), _hexNodes[1].Node(),
2290                            _hexNodes[4].Node(), _hexNodes[6].Node(),
2291                            _hexNodes[7].Node(), _hexNodes[5].Node() );
2292         mesh->SetMeshElementOnShape( el, helper.GetSubShapeID() );
2293         ++nbAdded;
2294         if ( hex )
2295         {
2296           delete hex;
2297           intersectedHex[ i ] = 0;
2298           --nbIntHex;
2299         }
2300       }
2301       else if ( _nbCornerNodes > 3  && !hex )
2302       {
2303         // all intersection of hex with geometry are at grid nodes
2304         hex = new Hexahedron( *this );
2305         //hex->init( i );
2306         hex->_i = _i;
2307         hex->_j = _j;
2308         hex->_k = _k;
2309         intHexInd.push_back(0);
2310         intHexInd[ nbIntHex++ ] = i;
2311       }
2312     }
2313
2314     // add elements resulted from hexadron intersection
2315 #ifdef WITH_TBB
2316     intHexInd.resize( nbIntHex );
2317     tbb::parallel_for ( tbb::blocked_range<size_t>( 0, nbIntHex ),
2318                         ParallelHexahedron( intersectedHex, intHexInd ),
2319                         tbb::simple_partitioner()); // ComputeElements() is called here
2320     for ( size_t i = 0; i < intHexInd.size(); ++i )
2321       if ( Hexahedron * hex = intersectedHex[ intHexInd[ i ]] )
2322         nbAdded += hex->addElements( helper );
2323 #else
2324     for ( size_t i = 0; i < intHexInd.size(); ++i )
2325       if ( Hexahedron * hex = intersectedHex[ intHexInd[ i ]] )
2326       {
2327         hex->ComputeElements();
2328         nbAdded += hex->addElements( helper );
2329       }
2330 #endif
2331
2332     for ( size_t i = 0; i < intersectedHex.size(); ++i )
2333       if ( intersectedHex[ i ] )
2334         delete intersectedHex[ i ];
2335
2336     return nbAdded;
2337   }
2338
2339   //================================================================================
2340   /*!
2341    * \brief Implements geom edges into the mesh
2342    */
2343   void Hexahedron::addEdges(SMESH_MesherHelper&                      helper,
2344                             vector< Hexahedron* >&                   hexes,
2345                             const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap)
2346   {
2347     if ( edge2faceIDsMap.empty() ) return;
2348
2349     // Prepare planes for intersecting with EDGEs
2350     GridPlanes pln[3];
2351     {
2352       for ( int iDirZ = 0; iDirZ < 3; ++iDirZ ) // iDirZ gives normal direction to planes
2353       {
2354         GridPlanes& planes = pln[ iDirZ ];
2355         int iDirX = ( iDirZ + 1 ) % 3;
2356         int iDirY = ( iDirZ + 2 ) % 3;
2357         // planes._uNorm  = ( _grid->_axes[ iDirY ] ^ _grid->_axes[ iDirZ ] ).Normalized();
2358         // planes._vNorm  = ( _grid->_axes[ iDirZ ] ^ _grid->_axes[ iDirX ] ).Normalized();
2359         planes._zNorm  = ( _grid->_axes[ iDirX ] ^ _grid->_axes[ iDirY ] ).Normalized();
2360         planes._zProjs.resize ( _grid->_coords[ iDirZ ].size() );
2361         planes._zProjs [0] = 0;
2362         const double       zFactor = _grid->_axes[ iDirZ ] * planes._zNorm;
2363         const vector< double > & u = _grid->_coords[ iDirZ ];
2364         for ( int i = 1; i < planes._zProjs.size(); ++i )
2365         {
2366           planes._zProjs [i] = zFactor * ( u[i] - u[0] );
2367         }
2368       }
2369     }
2370     const double deflection = _grid->_minCellSize / 20.;
2371     const double tol        = _grid->_tol;
2372     E_IntersectPoint ip;
2373
2374     // Intersect EDGEs with the planes
2375     map< TGeomID, vector< TGeomID > >::const_iterator e2fIt = edge2faceIDsMap.begin();
2376     for ( ; e2fIt != edge2faceIDsMap.end(); ++e2fIt )
2377     {
2378       const TGeomID  edgeID = e2fIt->first;
2379       const TopoDS_Edge & E = TopoDS::Edge( _grid->_shapes( edgeID ));
2380       BRepAdaptor_Curve curve( E );
2381       TopoDS_Vertex v1 = helper.IthVertex( 0, E, false ); 
2382       TopoDS_Vertex v2 = helper.IthVertex( 1, E, false ); 
2383
2384       ip._faceIDs = e2fIt->second;
2385       ip._shapeID = edgeID;
2386
2387       // discretize the EGDE
2388       GCPnts_UniformDeflection discret( curve, deflection, true );
2389       if ( !discret.IsDone() || discret.NbPoints() < 2 )
2390         continue;
2391
2392       // perform intersection
2393       for ( int iDirZ = 0; iDirZ < 3; ++iDirZ )
2394       {
2395         GridPlanes& planes = pln[ iDirZ ];
2396         int      iDirX = ( iDirZ + 1 ) % 3;
2397         int      iDirY = ( iDirZ + 2 ) % 3;
2398         double    xLen = _grid->_coords[ iDirX ].back() - _grid->_coords[ iDirX ][0];
2399         double    yLen = _grid->_coords[ iDirY ].back() - _grid->_coords[ iDirY ][0];
2400         double    zLen = _grid->_coords[ iDirZ ].back() - _grid->_coords[ iDirZ ][0];
2401         //double zFactor = _grid->_axes[ iDirZ ] * planes._zNorm;
2402         int dIJK[3], d000[3] = { 0,0,0 };
2403         double o[3] = { _grid->_coords[0][0],
2404                         _grid->_coords[1][0],
2405                         _grid->_coords[2][0] };
2406
2407         // locate the 1st point of a segment within the grid
2408         gp_XYZ p1     = discret.Value( 1 ).XYZ();
2409         double u1     = discret.Parameter( 1 );
2410         double zProj1 = planes._zNorm * ( p1 - _grid->_origin );
2411
2412         _grid->ComputeUVW( p1, ip._uvw );
2413         int iX1 = int(( ip._uvw[iDirX] - o[iDirX]) / xLen * (_grid->_coords[ iDirX ].size() - 1));
2414         int iY1 = int(( ip._uvw[iDirY] - o[iDirY]) / yLen * (_grid->_coords[ iDirY ].size() - 1));
2415         int iZ1 = int(( ip._uvw[iDirZ] - o[iDirZ]) / zLen * (_grid->_coords[ iDirZ ].size() - 1));
2416         locateValue( iX1, ip._uvw[iDirX], _grid->_coords[ iDirX ], dIJK[ iDirX ], tol );
2417         locateValue( iY1, ip._uvw[iDirY], _grid->_coords[ iDirY ], dIJK[ iDirY ], tol );
2418         locateValue( iZ1, ip._uvw[iDirZ], _grid->_coords[ iDirZ ], dIJK[ iDirZ ], tol );
2419
2420         int ijk[3]; // grid index where a segment intersect a plane
2421         ijk[ iDirX ] = iX1;
2422         ijk[ iDirY ] = iY1;
2423         ijk[ iDirZ ] = iZ1;
2424
2425         // add the 1st vertex point to a hexahedron
2426         if ( iDirZ == 0 )
2427         {
2428           ip._point   = p1;
2429           ip._shapeID = _grid->_shapes.Add( v1 );
2430           _grid->_edgeIntP.push_back( ip );
2431           if ( !addIntersection( _grid->_edgeIntP.back(), hexes, ijk, d000 ))
2432             _grid->_edgeIntP.pop_back();
2433           ip._shapeID = edgeID;
2434         }
2435         for ( int iP = 2; iP <= discret.NbPoints(); ++iP )
2436         {
2437           // locate the 2nd point of a segment within the grid
2438           gp_XYZ p2     = discret.Value( iP ).XYZ();
2439           double u2     = discret.Parameter( iP );
2440           double zProj2 = planes._zNorm * ( p2 - _grid->_origin );
2441           int iZ2       = iZ1;
2442           locateValue( iZ2, zProj2, planes._zProjs, dIJK[ iDirZ ], tol );
2443
2444           // treat intersections with planes between 2 end points of a segment
2445           int dZ = ( iZ1 <= iZ2 ) ? +1 : -1;
2446           int iZ = iZ1 + ( iZ1 < iZ2 );
2447           for ( int i = 0, nb = Abs( iZ1 - iZ2 ); i < nb; ++i, iZ += dZ )
2448           {
2449             ip._point = findIntPoint( u1, zProj1, u2, zProj2,
2450                                       planes._zProjs[ iZ ],
2451                                       curve, planes._zNorm, _grid->_origin );
2452             _grid->ComputeUVW( ip._point.XYZ(), ip._uvw );
2453             locateValue( ijk[iDirX], ip._uvw[iDirX], _grid->_coords[iDirX], dIJK[iDirX], tol );
2454             locateValue( ijk[iDirY], ip._uvw[iDirY], _grid->_coords[iDirY], dIJK[iDirY], tol );
2455             ijk[ iDirZ ] = iZ;
2456
2457             // add ip to hex "above" the plane
2458             _grid->_edgeIntP.push_back( ip );
2459             dIJK[ iDirZ ] = 0;
2460             bool added = addIntersection(_grid->_edgeIntP.back(), hexes, ijk, dIJK);
2461
2462             // add ip to hex "below" the plane
2463             ijk[ iDirZ ] = iZ-1;
2464             if ( !addIntersection( _grid->_edgeIntP.back(), hexes, ijk, dIJK ) &&
2465                  !added)
2466               _grid->_edgeIntP.pop_back();
2467           }
2468           iZ1    = iZ2;
2469           p1     = p2;
2470           u1     = u2;
2471           zProj1 = zProj2;
2472         }
2473         // add the 2nd vertex point to a hexahedron
2474         if ( iDirZ == 0 )
2475         {
2476           ip._shapeID = _grid->_shapes.Add( v2 );
2477           ip._point = p1;
2478           _grid->ComputeUVW( p1, ip._uvw );
2479           locateValue( ijk[iDirX], ip._uvw[iDirX], _grid->_coords[iDirX], dIJK[iDirX], tol );
2480           locateValue( ijk[iDirY], ip._uvw[iDirY], _grid->_coords[iDirY], dIJK[iDirY], tol );
2481           ijk[ iDirZ ] = iZ1;
2482           _grid->_edgeIntP.push_back( ip );
2483           if ( !addIntersection( _grid->_edgeIntP.back(), hexes, ijk, d000 ))
2484             _grid->_edgeIntP.pop_back();
2485           ip._shapeID = edgeID;
2486         }
2487       } // loop on 3 grid directions
2488     } // loop on EDGEs
2489
2490     // Create nodes at found intersections
2491     // const E_IntersectPoint* eip;
2492     // for ( size_t i = 0; i < hexes.size(); ++i )
2493     // {
2494     //   Hexahedron* h = hexes[i];
2495     //   if ( !h ) continue;
2496     //   for ( int iF = 0; iF < 6; ++iF )
2497     //   {
2498     //     _Face& quad = h->_hexQuads[ iF ];
2499     //     for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
2500     //       if ( !quad._edgeNodes[ iP ]._node )
2501     //         if (( eip = quad._edgeNodes[ iP ].EdgeIntPnt() ))
2502     //           quad._edgeNodes[ iP ]._intPoint->_node = helper.AddNode( eip->_point.X(),
2503     //                                                                    eip->_point.Y(),
2504     //                                                                    eip->_point.Z() );
2505     //   }
2506     //   for ( size_t iP = 0; iP < hexes[i]->_vertexNodes.size(); ++iP )
2507     //     if (( eip = h->_vertexNodes[ iP ].EdgeIntPnt() ))
2508     //       h->_vertexNodes[ iP ]._intPoint->_node = helper.AddNode( eip->_point.X(),
2509     //                                                                eip->_point.Y(),
2510     //                                                                eip->_point.Z() );
2511     // }
2512   }
2513
2514   //================================================================================
2515   /*!
2516    * \brief Finds intersection of a curve with a plane
2517    *  \param [in] u1 - parameter of one curve point
2518    *  \param [in] proj1 - projection of the curve point to the plane normal
2519    *  \param [in] u2 - parameter of another curve point
2520    *  \param [in] proj2 - projection of the other curve point to the plane normal
2521    *  \param [in] proj - projection of a point where the curve intersects the plane
2522    *  \param [in] curve - the curve
2523    *  \param [in] axis - the plane normal
2524    *  \param [in] origin - the plane origin
2525    *  \return gp_Pnt - the found intersection point
2526    */
2527   gp_Pnt Hexahedron::findIntPoint( double u1, double proj1,
2528                                    double u2, double proj2,
2529                                    double proj,
2530                                    BRepAdaptor_Curve& curve,
2531                                    const gp_XYZ& axis,
2532                                    const gp_XYZ& origin)
2533   {
2534     double r = (( proj - proj1 ) / ( proj2 - proj1 ));
2535     double u = u1 * ( 1 - r ) + u2 * r;
2536     gp_Pnt p = curve.Value( u );
2537     double newProj =  axis * ( p.XYZ() - origin );
2538     if ( Abs( proj - newProj ) > _grid->_tol / 10. )
2539     {
2540       if ( r > 0.5 )
2541         return findIntPoint( u2, proj2, u, newProj, proj, curve, axis, origin );
2542       else
2543         return findIntPoint( u1, proj2, u, newProj, proj, curve, axis, origin );
2544     }
2545     return p;
2546   }
2547
2548   //================================================================================
2549   /*!
2550    * \brief Returns indices of a hexahedron sub-entities holding a point
2551    *  \param [in] ip - intersection point
2552    *  \param [out] facets - 0-3 facets holding a point
2553    *  \param [out] sub - index of a vertex or an edge holding a point
2554    *  \return int - number of facets holding a point
2555    */
2556   int Hexahedron::getEntity( const E_IntersectPoint* ip, int* facets, int& sub )
2557   {
2558     enum { X = 1, Y = 2, Z = 4 }; // == 001, 010, 100
2559     int nbFacets = 0;
2560     int vertex = 0, egdeMask = 0;
2561
2562     if ( Abs( _grid->_coords[0][ _i   ] - ip->_uvw[0] ) < _grid->_tol ) {
2563       facets[ nbFacets++ ] = SMESH_Block::ID_F0yz;
2564       egdeMask |= X;
2565     }
2566     else if ( Abs( _grid->_coords[0][ _i+1 ] - ip->_uvw[0] ) < _grid->_tol ) {
2567       facets[ nbFacets++ ] = SMESH_Block::ID_F1yz;
2568       vertex   |= X;
2569       egdeMask |= X;
2570     }
2571     if ( Abs( _grid->_coords[1][ _j   ] - ip->_uvw[1] ) < _grid->_tol ) {
2572       facets[ nbFacets++ ] = SMESH_Block::ID_Fx0z;
2573       egdeMask |= Y;
2574     }
2575     else if ( Abs( _grid->_coords[1][ _j+1 ] - ip->_uvw[1] ) < _grid->_tol ) {
2576       facets[ nbFacets++ ] = SMESH_Block::ID_Fx1z;
2577       vertex   |= Y;
2578       egdeMask |= Y;
2579     }
2580     if ( Abs( _grid->_coords[2][ _k   ] - ip->_uvw[2] ) < _grid->_tol ) {
2581       facets[ nbFacets++ ] = SMESH_Block::ID_Fxy0;
2582       egdeMask |= Z;
2583     }
2584     else if ( Abs( _grid->_coords[2][ _k+1 ] - ip->_uvw[2] ) < _grid->_tol ) {
2585       facets[ nbFacets++ ] = SMESH_Block::ID_Fxy1;
2586       vertex   |= Z;
2587       egdeMask |= Z;
2588     }
2589
2590     switch ( nbFacets )
2591     {
2592     case 0: sub = 0;         break;
2593     case 1: sub = facets[0]; break;
2594     case 2: {
2595       const int edge [3][8] = {
2596         { SMESH_Block::ID_E00z, SMESH_Block::ID_E10z,
2597           SMESH_Block::ID_E01z, SMESH_Block::ID_E11z },
2598         { SMESH_Block::ID_E0y0, SMESH_Block::ID_E1y0, 0, 0,
2599           SMESH_Block::ID_E0y1, SMESH_Block::ID_E1y1 },
2600         { SMESH_Block::ID_Ex00, 0, SMESH_Block::ID_Ex10, 0,
2601           SMESH_Block::ID_Ex01, 0, SMESH_Block::ID_Ex11 }
2602       };
2603       switch ( egdeMask ) {
2604       case X | Y: sub = edge[ 0 ][ vertex ]; break;
2605       case X | Z: sub = edge[ 1 ][ vertex ]; break;
2606       default:    sub = edge[ 2 ][ vertex ];
2607       }
2608       break;
2609     }
2610     //case 3:
2611     default:
2612       sub = vertex + SMESH_Block::ID_FirstV;
2613     }
2614
2615     return nbFacets;
2616   }
2617   //================================================================================
2618   /*!
2619    * \brief Adds intersection with an EDGE
2620    */
2621   bool Hexahedron::addIntersection( const E_IntersectPoint& ip,
2622                                     vector< Hexahedron* >&  hexes,
2623                                     int ijk[], int dIJK[] )
2624   {
2625     bool added = false;
2626
2627     size_t hexIndex[4] = {
2628       _grid->CellIndex( ijk[0], ijk[1], ijk[2] ),
2629       dIJK[0] ? _grid->CellIndex( ijk[0]+dIJK[0], ijk[1], ijk[2] ) : -1,
2630       dIJK[1] ? _grid->CellIndex( ijk[0], ijk[1]+dIJK[1], ijk[2] ) : -1,
2631       dIJK[2] ? _grid->CellIndex( ijk[0], ijk[1], ijk[2]+dIJK[2] ) : -1
2632     };
2633     for ( int i = 0; i < 4; ++i )
2634     {
2635       if ( /*0 <= hexIndex[i] &&*/ hexIndex[i] < hexes.size() && hexes[ hexIndex[i] ] )
2636       {
2637         Hexahedron* h = hexes[ hexIndex[i] ];
2638         // check if ip is really inside the hex
2639 #ifdef _DEBUG_
2640         if (( _grid->_coords[0][ h->_i   ] - _grid->_tol > ip._uvw[0] ) ||
2641             ( _grid->_coords[0][ h->_i+1 ] + _grid->_tol < ip._uvw[0] ) ||
2642             ( _grid->_coords[1][ h->_j   ] - _grid->_tol > ip._uvw[1] ) ||
2643             ( _grid->_coords[1][ h->_j+1 ] + _grid->_tol < ip._uvw[1] ) ||
2644             ( _grid->_coords[2][ h->_k   ] - _grid->_tol > ip._uvw[2] ) ||
2645             ( _grid->_coords[2][ h->_k+1 ] + _grid->_tol < ip._uvw[2] ))
2646           throw SALOME_Exception("ip outside a hex");
2647 #endif
2648         h->_edgeIntPnts.push_back( & ip );
2649         added = true;
2650       }
2651     }
2652     return added;
2653   }
2654   //================================================================================
2655   /*!
2656    * \brief Finds nodes at a path from one node to another via intersections with EDGEs
2657    */
2658   bool Hexahedron::findChain( _Node*          n1,
2659                               _Node*          n2,
2660                               _Face&          quad,
2661                               vector<_Node*>& chn )
2662   {
2663     chn.clear();
2664     chn.push_back( n1 );
2665     for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
2666       if ( !quad._edgeNodes[ iP ]._isUsedInFace &&
2667            n1->IsLinked( quad._edgeNodes[ iP ]._intPoint ) &&
2668            n2->IsLinked( quad._edgeNodes[ iP ]._intPoint ))
2669       {
2670         chn.push_back( & quad._edgeNodes[ iP ]);
2671         chn.push_back( n2 );
2672         quad._edgeNodes[ iP ]._isUsedInFace = true;
2673         return true;
2674       }
2675     bool found;
2676     do
2677     {
2678       found = false;
2679       for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
2680         if ( !quad._edgeNodes[ iP ]._isUsedInFace &&
2681              chn.back()->IsLinked( quad._edgeNodes[ iP ]._intPoint ))
2682         {
2683           chn.push_back( & quad._edgeNodes[ iP ]);
2684           found = quad._edgeNodes[ iP ]._isUsedInFace = true;
2685           break;
2686         }
2687     } while ( found && ! chn.back()->IsLinked( n2->_intPoint ) );
2688
2689     if ( chn.back() != n2 && chn.back()->IsLinked( n2->_intPoint ))
2690       chn.push_back( n2 );
2691
2692     return chn.size() > 1;
2693   }
2694   //================================================================================
2695   /*!
2696    * \brief Try to heal a polygon whose ends are not connected
2697    */
2698   bool Hexahedron::closePolygon( _Face* polygon, vector<_Node*>& chainNodes ) const
2699   {
2700     int i = -1, nbLinks = polygon->_links.size();
2701     if ( nbLinks < 3 )
2702       return false;
2703     vector< _OrientedLink > newLinks;
2704     // find a node lying on the same FACE as the last one
2705     _Node*   node = polygon->_links.back().LastNode();
2706     int avoidFace = node->IsLinked( polygon->_links.back().FirstNode()->_intPoint );
2707     for ( i = nbLinks - 2; i >= 0; --i )
2708       if ( node->IsLinked( polygon->_links[i].FirstNode()->_intPoint, avoidFace ))
2709         break;
2710     if ( i >= 0 )
2711     {
2712       for ( ; i < nbLinks; ++i )
2713         newLinks.push_back( polygon->_links[i] );
2714     }
2715     else
2716     {
2717       // find a node lying on the same FACE as the first one
2718       node      = polygon->_links[0].FirstNode();
2719       avoidFace = node->IsLinked( polygon->_links[0].LastNode()->_intPoint );
2720       for ( i = 1; i < nbLinks; ++i )
2721         if ( node->IsLinked( polygon->_links[i].LastNode()->_intPoint, avoidFace ))
2722           break;
2723       if ( i < nbLinks )
2724         for ( nbLinks = i + 1, i = 0; i < nbLinks; ++i )
2725           newLinks.push_back( polygon->_links[i] );
2726     }
2727     if ( newLinks.size() > 1 )
2728     {
2729       polygon->_links.swap( newLinks );
2730       chainNodes.clear();
2731       chainNodes.push_back( polygon->_links.back().LastNode() );
2732       chainNodes.push_back( polygon->_links[0].FirstNode() );
2733       return true;
2734     }
2735     return false;
2736   }
2737   //================================================================================
2738   /*!
2739    * \brief Checks transition at the 1st node of a link
2740    */
2741   bool Hexahedron::is1stNodeOut( _Link& link /*int iLink*/ ) const
2742   {
2743     // new version is for the case: tangent transition at the 1st node
2744     bool isOut = false;
2745     if ( link._intNodes.size() > 1 )
2746     {
2747       // check transition at the next intersection
2748       switch ( link._intNodes[1].FaceIntPnt()->_transition ) {
2749       case Trans_OUT: return false;
2750       case Trans_IN : return true;
2751       default: ; // tangent transition
2752       }
2753     }
2754     gp_Pnt p1 = link._nodes[0]->Point();
2755     gp_Pnt p2 = link._nodes[1]->Point();
2756     gp_Pnt testPnt = 0.8 * p1.XYZ() + 0.2 * p2.XYZ();
2757
2758     TGeomID          faceID = link._intNodes[0]._intPoint->_faceIDs[0];
2759     const TopoDS_Face& face = TopoDS::Face( _grid->_shapes( faceID ));
2760     TopLoc_Location loc;
2761     GeomAPI_ProjectPointOnSurf& proj =
2762       _grid->_helper->GetProjector( face, loc, 0.1*_grid->_tol );
2763     testPnt.Transform( loc );
2764     proj.Perform( testPnt );
2765     if ( proj.IsDone() &&
2766          proj.NbPoints() > 0 &&
2767          proj.LowerDistance() > _grid->_tol )
2768     {
2769       Quantity_Parameter u,v;
2770       proj.LowerDistanceParameters( u,v );
2771       gp_Dir normal;
2772       if ( GeomLib::NormEstim( BRep_Tool::Surface( face, loc ),
2773                                gp_Pnt2d( u,v ),
2774                                0.1*_grid->_tol,
2775                                normal ) < 3 )
2776       {
2777         if ( face.Orientation() == TopAbs_REVERSED )
2778           normal.Reverse();
2779         gp_Vec v( proj.NearestPoint(), testPnt );
2780         return v * normal > 0;
2781       }
2782     }
2783     //     if ( !_hexLinks[ iLink ]._nodes[0]->Node() ) // no node
2784     //       return true;
2785     //     if ( !_hexLinks[ iLink ]._nodes[0]->_intPoint ) // no intersection with geometry
2786     //       return false;
2787     //     switch ( _hexLinks[ iLink ]._nodes[0]->FaceIntPnt()->_transition ) {
2788     //     case Trans_OUT: return true;
2789     //     case Trans_IN : return false;
2790     //     default: ; // tangent transition
2791     //     }
2792
2793 //     // ijk of a GridLine corresponding to the link
2794 //     int   iDir = iLink / 4;
2795 //     int indSub = iLink % 4;
2796 //     LineIndexer li = _grid->GetLineIndexer( iDir );
2797 //     li.SetIJK( _i,_j,_k );
2798 //     size_t lineIndex[4] = { li.LineIndex  (),
2799 //                             li.LineIndex10(),
2800 //                             li.LineIndex01(),
2801 //                             li.LineIndex11() };
2802 //     GridLine& line = _grid->_lines[ iDir ][ lineIndex[ indSub ]];
2803
2804 //     // analyze transition of previous ip
2805 //     bool isOut = true;
2806 //     multiset< F_IntersectPoint >::const_iterator ip = line._intPoints.begin();
2807 //     for ( ; ip != line._intPoints.end(); ++ip )
2808 //     {
2809 //       if ( &(*ip) == _hexLinks[ iLink ]._nodes[0]->_intPoint )
2810 //         break;
2811 //       switch ( ip->_transition ) {
2812 //       case Trans_OUT: isOut = true;
2813 //       case Trans_IN : isOut = false;
2814 //       default:;
2815 //       }
2816 //     }
2817 // #ifdef _DEBUG_
2818 //     if ( ip == line._intPoints.end() )
2819 //       cout << "BUG: Wrong GridLine. IKJ = ( "<< _i << " " << _j << " " << _k << " )" << endl;
2820 // #endif
2821     return isOut;
2822   }
2823   //================================================================================
2824   /*!
2825    * \brief Adds computed elements to the mesh
2826    */
2827   int Hexahedron::addElements(SMESH_MesherHelper& helper)
2828   {
2829     int nbAdded = 0;
2830     // add elements resulted from hexahedron intersection
2831     //for ( size_t i = 0; i < _volumeDefs.size(); ++i )
2832     {
2833       vector< const SMDS_MeshNode* > nodes( _volumeDefs._nodes.size() );
2834       for ( size_t iN = 0; iN < nodes.size(); ++iN )
2835         if ( !( nodes[iN] = _volumeDefs._nodes[iN]->Node() ))
2836         {
2837           if ( const E_IntersectPoint* eip = _volumeDefs._nodes[iN]->EdgeIntPnt() )
2838             nodes[iN] = _volumeDefs._nodes[iN]->_intPoint->_node =
2839               helper.AddNode( eip->_point.X(),
2840                               eip->_point.Y(),
2841                               eip->_point.Z() );
2842           else
2843             throw SALOME_Exception("Bug: no node at intersection point");
2844         }
2845
2846       if ( !_volumeDefs._quantities.empty() )
2847       {
2848         helper.AddPolyhedralVolume( nodes, _volumeDefs._quantities );
2849       }
2850       else
2851       {
2852         switch ( nodes.size() )
2853         {
2854         case 8: helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3],
2855                                   nodes[4],nodes[5],nodes[6],nodes[7] );
2856           break;
2857         case 4: helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3] );
2858           break;
2859         case 6: helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3], nodes[4],nodes[5] );
2860           break;
2861         case 5:
2862           helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3],nodes[4] );
2863           break;
2864         }
2865       }
2866       nbAdded += int ( _volumeDefs._nodes.size() > 0 );
2867     }
2868
2869     return nbAdded;
2870   }
2871   //================================================================================
2872   /*!
2873    * \brief Return true if the element is in a hole
2874    */
2875   bool Hexahedron::isInHole() const
2876   {
2877     if ( !_vertexNodes.empty() )
2878       return false;
2879
2880     const int ijk[3] = { _i, _j, _k };
2881     F_IntersectPoint curIntPnt;
2882
2883     // consider a cell to be in a hole if all links in any direction
2884     // comes OUT of geometry
2885     for ( int iDir = 0; iDir < 3; ++iDir )
2886     {
2887       const vector<double>& coords = _grid->_coords[ iDir ];
2888       LineIndexer               li = _grid->GetLineIndexer( iDir );
2889       li.SetIJK( _i,_j,_k );
2890       size_t lineIndex[4] = { li.LineIndex  (),
2891                               li.LineIndex10(),
2892                               li.LineIndex01(),
2893                               li.LineIndex11() };
2894       bool allLinksOut = true, hasLinks = false;
2895       for ( int iL = 0; iL < 4 && allLinksOut; ++iL ) // loop on 4 links parallel to iDir
2896       {
2897         const _Link& link = _hexLinks[ iL + 4*iDir ];
2898         // check transition of the first node of a link
2899         const F_IntersectPoint* firstIntPnt = 0;
2900         if ( link._nodes[0]->Node() ) // 1st node is a hexa corner
2901         {
2902           curIntPnt._paramOnLine = coords[ ijk[ iDir ]] - coords[0];
2903           const GridLine& line = _grid->_lines[ iDir ][ lineIndex[ iL ]];
2904           multiset< F_IntersectPoint >::const_iterator ip =
2905             line._intPoints.upper_bound( curIntPnt );
2906           --ip;
2907           firstIntPnt = &(*ip);
2908         }
2909         else if ( !link._intNodes.empty() )
2910         {
2911           firstIntPnt = link._intNodes[0].FaceIntPnt();
2912         }
2913
2914         if ( firstIntPnt )
2915         {
2916           hasLinks = true;
2917           allLinksOut = ( firstIntPnt->_transition == Trans_OUT );
2918         }
2919       }
2920       if ( hasLinks && allLinksOut )
2921         return true;
2922     }
2923     return false;
2924   }
2925
2926   //================================================================================
2927   /*!
2928    * \brief Return true if a polyhedron passes _sizeThreshold criterion
2929    */
2930   bool Hexahedron::checkPolyhedronSize() const
2931   {
2932     double volume = 0;
2933     for ( size_t iP = 0; iP < _polygons.size(); ++iP )
2934     {
2935       const _Face& polygon = _polygons[iP];
2936       gp_XYZ area (0,0,0);
2937       gp_XYZ p1 = polygon._links[ 0 ].FirstNode()->Point().XYZ();
2938       for ( size_t iL = 0; iL < polygon._links.size(); ++iL )
2939       {
2940         gp_XYZ p2 = polygon._links[ iL ].LastNode()->Point().XYZ();
2941         area += p1 ^ p2;
2942         p1 = p2;
2943       }
2944       volume += p1 * area;
2945     }
2946     volume /= 6;
2947
2948     double initVolume = _sideLength[0] * _sideLength[1] * _sideLength[2];
2949
2950     return volume > initVolume / _sizeThreshold;
2951   }
2952   //================================================================================
2953   /*!
2954    * \brief Tries to create a hexahedron
2955    */
2956   bool Hexahedron::addHexa()
2957   {
2958     if ( _polygons[0]._links.size() != 4 ||
2959          _polygons[1]._links.size() != 4 ||
2960          _polygons[2]._links.size() != 4 ||
2961          _polygons[3]._links.size() != 4 ||
2962          _polygons[4]._links.size() != 4 ||
2963          _polygons[5]._links.size() != 4   )
2964       return false;
2965     _Node* nodes[8];
2966     int nbN = 0;
2967     for ( int iL = 0; iL < 4; ++iL )
2968     {
2969       // a base node
2970       nodes[iL] = _polygons[0]._links[iL].FirstNode();
2971       ++nbN;
2972
2973       // find a top node above the base node
2974       _Link* link = _polygons[0]._links[iL]._link;
2975       //ASSERT( link->_faces.size() > 1 );
2976       if ( link->_faces.size() < 2 )
2977         return debugDumpLink( link );
2978       // a quadrangle sharing <link> with _polygons[0]
2979       _Face* quad = link->_faces[ bool( link->_faces[0] == & _polygons[0] )];
2980       for ( int i = 0; i < 4; ++i )
2981         if ( quad->_links[i]._link == link )
2982         {
2983           // 1st node of a link opposite to <link> in <quad>
2984           nodes[iL+4] = quad->_links[(i+2)%4].FirstNode();
2985           ++nbN;
2986           break;
2987         }
2988     }
2989     if ( nbN == 8 )
2990       _volumeDefs.set( vector< _Node* >( nodes, nodes+8 ));
2991
2992     return nbN == 8;
2993   }
2994   //================================================================================
2995   /*!
2996    * \brief Tries to create a tetrahedron
2997    */
2998   bool Hexahedron::addTetra()
2999   {
3000     _Node* nodes[4];
3001     nodes[0] = _polygons[0]._links[0].FirstNode();
3002     nodes[1] = _polygons[0]._links[1].FirstNode();
3003     nodes[2] = _polygons[0]._links[2].FirstNode();
3004
3005     _Link* link = _polygons[0]._links[0]._link;
3006     //ASSERT( link->_faces.size() > 1 );
3007     if ( link->_faces.size() < 2 )
3008       return debugDumpLink( link );
3009
3010     // a triangle sharing <link> with _polygons[0]
3011     _Face* tria = link->_faces[ bool( link->_faces[0] == & _polygons[0] )];
3012     for ( int i = 0; i < 3; ++i )
3013       if ( tria->_links[i]._link == link )
3014       {
3015         nodes[3] = tria->_links[(i+1)%3].LastNode();
3016         _volumeDefs.set( vector< _Node* >( nodes, nodes+4 ));
3017         return true;
3018       }
3019
3020     return false;
3021   }
3022   //================================================================================
3023   /*!
3024    * \brief Tries to create a pentahedron
3025    */
3026   bool Hexahedron::addPenta()
3027   {
3028     // find a base triangular face
3029     int iTri = -1;
3030     for ( int iF = 0; iF < 5 && iTri < 0; ++iF )
3031       if ( _polygons[ iF ]._links.size() == 3 )
3032         iTri = iF;
3033     if ( iTri < 0 ) return false;
3034
3035     // find nodes
3036     _Node* nodes[6];
3037     int nbN = 0;
3038     for ( int iL = 0; iL < 3; ++iL )
3039     {
3040       // a base node
3041       nodes[iL] = _polygons[ iTri ]._links[iL].FirstNode();
3042       ++nbN;
3043
3044       // find a top node above the base node
3045       _Link* link = _polygons[ iTri ]._links[iL]._link;
3046       //ASSERT( link->_faces.size() > 1 );
3047       if ( link->_faces.size() < 2 )
3048         return debugDumpLink( link );
3049       // a quadrangle sharing <link> with a base triangle
3050       _Face* quad = link->_faces[ bool( link->_faces[0] == & _polygons[ iTri ] )];
3051       if ( quad->_links.size() != 4 ) return false;
3052       for ( int i = 0; i < 4; ++i )
3053         if ( quad->_links[i]._link == link )
3054         {
3055           // 1st node of a link opposite to <link> in <quad>
3056           nodes[iL+3] = quad->_links[(i+2)%4].FirstNode();
3057           ++nbN;
3058           break;
3059         }
3060     }
3061     if ( nbN == 6 )
3062       _volumeDefs.set( vector< _Node* >( nodes, nodes+6 ));
3063
3064     return ( nbN == 6 );
3065   }
3066   //================================================================================
3067   /*!
3068    * \brief Tries to create a pyramid
3069    */
3070   bool Hexahedron::addPyra()
3071   {
3072     // find a base quadrangle
3073     int iQuad = -1;
3074     for ( int iF = 0; iF < 5 && iQuad < 0; ++iF )
3075       if ( _polygons[ iF ]._links.size() == 4 )
3076         iQuad = iF;
3077     if ( iQuad < 0 ) return false;
3078
3079     // find nodes
3080     _Node* nodes[5];
3081     nodes[0] = _polygons[iQuad]._links[0].FirstNode();
3082     nodes[1] = _polygons[iQuad]._links[1].FirstNode();
3083     nodes[2] = _polygons[iQuad]._links[2].FirstNode();
3084     nodes[3] = _polygons[iQuad]._links[3].FirstNode();
3085
3086     _Link* link = _polygons[iQuad]._links[0]._link;
3087     ASSERT( link->_faces.size() > 1 );
3088     if ( link->_faces.size() < 2 )
3089       return debugDumpLink( link );
3090
3091     // a triangle sharing <link> with a base quadrangle
3092     _Face* tria = link->_faces[ bool( link->_faces[0] == & _polygons[ iQuad ] )];
3093     if ( tria->_links.size() != 3 ) return false;
3094     for ( int i = 0; i < 3; ++i )
3095       if ( tria->_links[i]._link == link )
3096       {
3097         nodes[4] = tria->_links[(i+1)%3].LastNode();
3098         _volumeDefs.set( vector< _Node* >( nodes, nodes+5 ));
3099         return true;
3100       }
3101
3102     return false;
3103   }
3104   //================================================================================
3105   /*!
3106    * \brief Dump a link and return \c false
3107    */
3108   bool Hexahedron::debugDumpLink( Hexahedron::_Link* link )
3109   {
3110 #ifdef _DEBUG_
3111     gp_Pnt p1 = link->_nodes[0]->Point(), p2 = link->_nodes[1]->Point();
3112     cout << "BUG: not shared link. IKJ = ( "<< _i << " " << _j << " " << _k << " )" << endl
3113          << "n1 (" << p1.X() << ", "<< p1.Y() << ", "<< p1.Z() << " )" << endl
3114          << "n2 (" << p2.X() << ", "<< p2.Y() << ", "<< p2.Z() << " )" << endl;
3115 #endif
3116     return false;
3117   }
3118
3119   //================================================================================
3120   /*!
3121    * \brief computes exact bounding box with axes parallel to given ones
3122    */
3123   //================================================================================
3124
3125   void getExactBndBox( const vector< TopoDS_Shape >& faceVec,
3126                        const double*                 axesDirs,
3127                        Bnd_Box&                      shapeBox )
3128   {
3129     BRep_Builder b;
3130     TopoDS_Compound allFacesComp;
3131     b.MakeCompound( allFacesComp );
3132     for ( size_t iF = 0; iF < faceVec.size(); ++iF )
3133       b.Add( allFacesComp, faceVec[ iF ] );
3134
3135     double sP[6]; // aXmin, aYmin, aZmin, aXmax, aYmax, aZmax
3136     shapeBox.Get(sP[0],sP[1],sP[2],sP[3],sP[4],sP[5]);
3137     double farDist = 0;
3138     for ( int i = 0; i < 6; ++i )
3139       farDist = Max( farDist, 10 * sP[i] );
3140
3141     gp_XYZ axis[3] = { gp_XYZ( axesDirs[0], axesDirs[1], axesDirs[2] ),
3142                        gp_XYZ( axesDirs[3], axesDirs[4], axesDirs[5] ),
3143                        gp_XYZ( axesDirs[6], axesDirs[7], axesDirs[8] ) };
3144     axis[0].Normalize();
3145     axis[1].Normalize();
3146     axis[2].Normalize();
3147
3148     gp_Mat basis( axis[0], axis[1], axis[2] );
3149     gp_Mat bi = basis.Inverted();
3150
3151     gp_Pnt pMin, pMax;
3152     for ( int iDir = 0; iDir < 3; ++iDir )
3153     {
3154       gp_XYZ axis0 = axis[ iDir ];
3155       gp_XYZ axis1 = axis[ ( iDir + 1 ) % 3 ];
3156       gp_XYZ axis2 = axis[ ( iDir + 2 ) % 3 ];
3157       for ( int isMax = 0; isMax < 2; ++isMax )
3158       {
3159         double shift = isMax ? farDist : -farDist;
3160         gp_XYZ orig = shift * axis0;
3161         gp_XYZ norm = axis1 ^ axis2;
3162         gp_Pln pln( orig, norm );
3163         norm = pln.Axis().Direction().XYZ();
3164         BRepBuilderAPI_MakeFace plane( pln, -farDist, farDist, -farDist, farDist );
3165
3166         gp_Pnt& pAxis = isMax ? pMax : pMin;
3167         gp_Pnt pPlane, pFaces;
3168         double dist = GEOMUtils::GetMinDistance( plane, allFacesComp, pPlane, pFaces );
3169         if ( dist < 0 )
3170         {
3171           Bnd_B3d bb;
3172           gp_XYZ corner;
3173           for ( int i = 0; i < 2; ++i ) {
3174             corner.SetCoord( 1, sP[ i*3 ]);
3175             for ( int j = 0; j < 2; ++j ) {
3176               corner.SetCoord( 2, sP[ i*3 + 1 ]);
3177               for ( int k = 0; k < 2; ++k )
3178               {
3179                 corner.SetCoord( 3, sP[ i*3 + 2 ]);
3180                 corner *= bi;
3181                 bb.Add( corner );
3182               }
3183             }
3184           }
3185           corner = isMax ? bb.CornerMax() : bb.CornerMin();
3186           pAxis.SetCoord( iDir+1, corner.Coord( iDir+1 ));
3187         }
3188         else
3189         {
3190           gp_XYZ pf = pFaces.XYZ() * bi;
3191           pAxis.SetCoord( iDir+1, pf.Coord( iDir+1 ) );
3192         }
3193       }
3194     } // loop on 3 axes
3195
3196     shapeBox.SetVoid();
3197     shapeBox.Add( pMin );
3198     shapeBox.Add( pMax );
3199
3200     return;
3201   }
3202
3203 } // namespace
3204
3205 //=============================================================================
3206 /*!
3207  * \brief Generates 3D structured Cartesian mesh in the internal part of
3208  * solid shapes and polyhedral volumes near the shape boundary.
3209  *  \param theMesh - mesh to fill in
3210  *  \param theShape - a compound of all SOLIDs to mesh
3211  *  \retval bool - true in case of success
3212  */
3213 //=============================================================================
3214
3215 bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh &         theMesh,
3216                                       const TopoDS_Shape & theShape)
3217 {
3218   // The algorithm generates the mesh in following steps:
3219
3220   // 1) Intersection of grid lines with the geometry boundary.
3221   // This step allows to find out if a given node of the initial grid is
3222   // inside or outside the geometry.
3223
3224   // 2) For each cell of the grid, check how many of it's nodes are outside
3225   // of the geometry boundary. Depending on a result of this check
3226   // - skip a cell, if all it's nodes are outside
3227   // - skip a cell, if it is too small according to the size threshold
3228   // - add a hexahedron in the mesh, if all nodes are inside
3229   // - add a polyhedron in the mesh, if some nodes are inside and some outside
3230
3231   _computeCanceled = false;
3232
3233   SMESH_MesherHelper helper( theMesh );
3234
3235   try
3236   {
3237     Grid grid;
3238     grid._helper = &helper;
3239
3240     vector< TopoDS_Shape > faceVec;
3241     {
3242       TopTools_MapOfShape faceMap;
3243       TopExp_Explorer fExp;
3244       for ( fExp.Init( theShape, TopAbs_FACE ); fExp.More(); fExp.Next() )
3245         if ( !faceMap.Add( fExp.Current() ))
3246           faceMap.Remove( fExp.Current() ); // remove a face shared by two solids
3247
3248       for ( fExp.ReInit(); fExp.More(); fExp.Next() )
3249         if ( faceMap.Contains( fExp.Current() ))
3250           faceVec.push_back( fExp.Current() );
3251     }
3252     vector<FaceGridIntersector> facesItersectors( faceVec.size() );
3253     map< TGeomID, vector< TGeomID > > edge2faceIDsMap;
3254     TopExp_Explorer eExp;
3255     Bnd_Box shapeBox;
3256     for ( int i = 0; i < faceVec.size(); ++i )
3257     {
3258       facesItersectors[i]._face   = TopoDS::Face    ( faceVec[i] );
3259       facesItersectors[i]._faceID = grid._shapes.Add( faceVec[i] );
3260       facesItersectors[i]._grid   = &grid;
3261       shapeBox.Add( facesItersectors[i].GetFaceBndBox() );
3262
3263       if ( _hyp->GetToAddEdges() )
3264       {
3265         helper.SetSubShape( faceVec[i] );
3266         for ( eExp.Init( faceVec[i], TopAbs_EDGE ); eExp.More(); eExp.Next() )
3267         {
3268           const TopoDS_Edge& edge = TopoDS::Edge( eExp.Current() );
3269           if ( !SMESH_Algo::isDegenerated( edge ) &&
3270                !helper.IsRealSeam( edge ))
3271             edge2faceIDsMap[ grid._shapes.Add( edge )].push_back( facesItersectors[i]._faceID );
3272         }
3273       }
3274     }
3275
3276     getExactBndBox( faceVec, _hyp->GetAxisDirs(), shapeBox );
3277
3278     vector<double> xCoords, yCoords, zCoords;
3279     _hyp->GetCoordinates( xCoords, yCoords, zCoords, shapeBox );
3280
3281     grid.SetCoordinates( xCoords, yCoords, zCoords, _hyp->GetAxisDirs(), shapeBox );
3282
3283     if ( _computeCanceled ) return false;
3284
3285 #ifdef WITH_TBB
3286     { // copy partner faces and curves of not thread-safe types
3287       set< const Standard_Transient* > tshapes;
3288       BRepBuilderAPI_Copy copier;
3289       for ( size_t i = 0; i < facesItersectors.size(); ++i )
3290       {
3291         if ( !facesItersectors[i].IsThreadSafe(tshapes) )
3292         {
3293           copier.Perform( facesItersectors[i]._face );
3294           facesItersectors[i]._face = TopoDS::Face( copier );
3295         }
3296       }
3297     }
3298     // Intersection of grid lines with the geometry boundary.
3299     tbb::parallel_for ( tbb::blocked_range<size_t>( 0, facesItersectors.size() ),
3300                         ParallelIntersector( facesItersectors ),
3301                         tbb::simple_partitioner());
3302 #else
3303     for ( size_t i = 0; i < facesItersectors.size(); ++i )
3304       facesItersectors[i].Intersect();
3305 #endif
3306
3307     // put interesection points onto the GridLine's; this is done after intersection
3308     // to avoid contention of facesItersectors for writing into the same GridLine
3309     // in case of parallel work of facesItersectors
3310     for ( size_t i = 0; i < facesItersectors.size(); ++i )
3311       facesItersectors[i].StoreIntersections();
3312
3313     TopExp_Explorer solidExp (theShape, TopAbs_SOLID);
3314     helper.SetSubShape( solidExp.Current() );
3315     helper.SetElementsOnShape( true );
3316
3317     if ( _computeCanceled ) return false;
3318
3319     // create nodes on the geometry
3320     grid.ComputeNodes(helper);
3321
3322     if ( _computeCanceled ) return false;
3323
3324     // create volume elements
3325     Hexahedron hex( _hyp->GetSizeThreshold(), &grid );
3326     int nbAdded = hex.MakeElements( helper, edge2faceIDsMap );
3327
3328     SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
3329     if ( nbAdded > 0 )
3330     {
3331       // make all SOLIDs computed
3332       if ( SMESHDS_SubMesh* sm1 = meshDS->MeshElements( solidExp.Current()) )
3333       {
3334         SMDS_ElemIteratorPtr volIt = sm1->GetElements();
3335         for ( ; solidExp.More() && volIt->more(); solidExp.Next() )
3336         {
3337           const SMDS_MeshElement* vol = volIt->next();
3338           sm1->RemoveElement( vol, /*isElemDeleted=*/false );
3339           meshDS->SetMeshElementOnShape( vol, solidExp.Current() );
3340         }
3341       }
3342       // make other sub-shapes computed
3343       setSubmeshesComputed( theMesh, theShape );
3344     }
3345
3346     // remove free nodes
3347     if ( SMESHDS_SubMesh * smDS = meshDS->MeshElements( helper.GetSubShapeID() ))
3348     {
3349       TIDSortedNodeSet nodesToRemove;
3350       // get intersection nodes
3351       for ( int iDir = 0; iDir < 3; ++iDir )
3352       {
3353         vector< GridLine >& lines = grid._lines[ iDir ];
3354         for ( size_t i = 0; i < lines.size(); ++i )
3355         {
3356           multiset< F_IntersectPoint >::iterator ip = lines[i]._intPoints.begin();
3357           for ( ; ip != lines[i]._intPoints.end(); ++ip )
3358             if ( ip->_node && ip->_node->NbInverseElements() == 0 )
3359               nodesToRemove.insert( nodesToRemove.end(), ip->_node );
3360         }
3361       }
3362       // get grid nodes
3363       for ( size_t i = 0; i < grid._nodes.size(); ++i )
3364         if ( grid._nodes[i] && grid._nodes[i]->NbInverseElements() == 0 )
3365           nodesToRemove.insert( nodesToRemove.end(), grid._nodes[i] );
3366
3367       // do remove
3368       TIDSortedNodeSet::iterator n = nodesToRemove.begin();
3369       for ( ; n != nodesToRemove.end(); ++n )
3370         meshDS->RemoveFreeNode( *n, smDS, /*fromGroups=*/false );
3371     }
3372
3373     return nbAdded;
3374
3375   }
3376   // SMESH_ComputeError is not caught at SMESH_submesh level for an unknown reason
3377   catch ( SMESH_ComputeError& e)
3378   {
3379     return error( SMESH_ComputeErrorPtr( new SMESH_ComputeError( e )));
3380   }
3381   return false;
3382 }
3383
3384 //=============================================================================
3385 /*!
3386  *  Evaluate
3387  */
3388 //=============================================================================
3389
3390 bool StdMeshers_Cartesian_3D::Evaluate(SMESH_Mesh &         theMesh,
3391                                        const TopoDS_Shape & theShape,
3392                                        MapShapeNbElems&     theResMap)
3393 {
3394   // TODO
3395 //   std::vector<int> aResVec(SMDSEntity_Last);
3396 //   for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
3397 //   if(IsQuadratic) {
3398 //     aResVec[SMDSEntity_Quad_Cartesian] = nb2d_face0 * ( nb2d/nb1d );
3399 //     int nb1d_face0_int = ( nb2d_face0*4 - nb1d ) / 2;
3400 //     aResVec[SMDSEntity_Node] = nb0d_face0 * ( 2*nb2d/nb1d - 1 ) - nb1d_face0_int * nb2d/nb1d;
3401 //   }
3402 //   else {
3403 //     aResVec[SMDSEntity_Node] = nb0d_face0 * ( nb2d/nb1d - 1 );
3404 //     aResVec[SMDSEntity_Cartesian] = nb2d_face0 * ( nb2d/nb1d );
3405 //   }
3406 //   SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);
3407 //   aResMap.insert(std::make_pair(sm,aResVec));
3408
3409   return true;
3410 }
3411
3412 //=============================================================================
3413 namespace
3414 {
3415   /*!
3416    * \brief Event listener setting/unsetting _alwaysComputed flag to
3417    *        submeshes of inferior levels to prevent their computing
3418    */
3419   struct _EventListener : public SMESH_subMeshEventListener
3420   {
3421     string _algoName;
3422
3423     _EventListener(const string& algoName):
3424       SMESH_subMeshEventListener(/*isDeletable=*/true,"StdMeshers_Cartesian_3D::_EventListener"),
3425       _algoName(algoName)
3426     {}
3427     // --------------------------------------------------------------------------------
3428     // setting/unsetting _alwaysComputed flag to submeshes of inferior levels
3429     //
3430     static void setAlwaysComputed( const bool     isComputed,
3431                                    SMESH_subMesh* subMeshOfSolid)
3432     {
3433       SMESH_subMeshIteratorPtr smIt =
3434         subMeshOfSolid->getDependsOnIterator(/*includeSelf=*/false, /*complexShapeFirst=*/false);
3435       while ( smIt->more() )
3436       {
3437         SMESH_subMesh* sm = smIt->next();
3438         sm->SetIsAlwaysComputed( isComputed );
3439       }
3440       subMeshOfSolid->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
3441     }
3442
3443     // --------------------------------------------------------------------------------
3444     // unsetting _alwaysComputed flag if "Cartesian_3D" was removed
3445     //
3446     virtual void ProcessEvent(const int          event,
3447                               const int          eventType,
3448                               SMESH_subMesh*     subMeshOfSolid,
3449                               SMESH_subMeshEventListenerData* data,
3450                               const SMESH_Hypothesis*         hyp = 0)
3451     {
3452       if ( eventType == SMESH_subMesh::COMPUTE_EVENT )
3453       {
3454         setAlwaysComputed( subMeshOfSolid->GetComputeState() == SMESH_subMesh::COMPUTE_OK,
3455                            subMeshOfSolid );
3456       }
3457       else
3458       {
3459         SMESH_Algo* algo3D = subMeshOfSolid->GetAlgo();
3460         if ( !algo3D || _algoName != algo3D->GetName() )
3461           setAlwaysComputed( false, subMeshOfSolid );
3462       }
3463     }
3464
3465     // --------------------------------------------------------------------------------
3466     // set the event listener
3467     //
3468     static void SetOn( SMESH_subMesh* subMeshOfSolid, const string& algoName )
3469     {
3470       subMeshOfSolid->SetEventListener( new _EventListener( algoName ),
3471                                         /*data=*/0,
3472                                         subMeshOfSolid );
3473     }
3474
3475   }; // struct _EventListener
3476
3477 } // namespace
3478
3479 //================================================================================
3480 /*!
3481  * \brief Sets event listener to submeshes if necessary
3482  *  \param subMesh - submesh where algo is set
3483  * This method is called when a submesh gets HYP_OK algo_state.
3484  * After being set, event listener is notified on each event of a submesh.
3485  */
3486 //================================================================================
3487
3488 void StdMeshers_Cartesian_3D::SetEventListener(SMESH_subMesh* subMesh)
3489 {
3490   _EventListener::SetOn( subMesh, GetName() );
3491 }
3492
3493 //================================================================================
3494 /*!
3495  * \brief Set _alwaysComputed flag to submeshes of inferior levels to avoid their computing
3496  */
3497 //================================================================================
3498
3499 void StdMeshers_Cartesian_3D::setSubmeshesComputed(SMESH_Mesh&         theMesh,
3500                                                    const TopoDS_Shape& theShape)
3501 {
3502   for ( TopExp_Explorer soExp( theShape, TopAbs_SOLID ); soExp.More(); soExp.Next() )
3503     _EventListener::setAlwaysComputed( true, theMesh.GetSubMesh( soExp.Current() ));
3504 }
3505