Salome HOME
Merge branch 'V9_3_BR'
[modules/smesh.git] / src / StdMeshers / StdMeshers_CompositeHexa_3D.cxx
1 // Copyright (C) 2007-2019  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 //  SMESH SMESH : implementation of SMESH idl descriptions
21 // File      : StdMeshers_CompositeHexa_3D.cxx
22 // Module    : SMESH
23 // Created   : Tue Nov 25 11:04:59 2008
24 // Author    : Edward AGAPOV (eap)
25
26 #include "StdMeshers_CompositeHexa_3D.hxx"
27
28 #include "SMDS_Mesh.hxx"
29 #include "SMDS_MeshNode.hxx"
30 #include "SMDS_SetIterator.hxx"
31 #include "SMESHDS_Mesh.hxx"
32 #include "SMESHDS_SubMesh.hxx"
33 #include "SMESH_Block.hxx"
34 #include "SMESH_Comment.hxx"
35 #include "SMESH_ComputeError.hxx"
36 #include "SMESH_HypoFilter.hxx"
37 #include "SMESH_Mesh.hxx"
38 #include "SMESH_MeshAlgos.hxx"
39 #include "SMESH_MesherHelper.hxx"
40 #include "SMESH_subMesh.hxx"
41 #include "StdMeshers_ViscousLayers.hxx"
42
43 #include <BRepAdaptor_Surface.hxx>
44 #include <BRep_Tool.hxx>
45 #include <Standard_ErrorHandler.hxx>
46 #include <Standard_Failure.hxx>
47 #include <TopExp_Explorer.hxx>
48 #include <TopTools_IndexedMapOfShape.hxx>
49 #include <TopTools_MapIteratorOfMapOfShape.hxx>
50 #include <TopTools_MapOfShape.hxx>
51 #include <TopTools_SequenceOfShape.hxx>
52 #include <TopoDS.hxx>
53 #include <TopoDS_Edge.hxx>
54 #include <TopoDS_Face.hxx>
55 #include <TopoDS_Vertex.hxx>
56 #include <gp_Pnt.hxx>
57 #include <gp_Pnt2d.hxx>
58 #include <gp_Vec.hxx>
59 #include <gp_XYZ.hxx>
60
61 #include <list>
62 #include <set>
63 #include <vector>
64
65 using namespace std;
66
67 #ifdef _DEBUG_
68 // #define DEB_FACES
69 // #define DEB_GRID
70 // #define DUMP_VERT(msg,V) { TopoDS_Vertex v = V; gp_Pnt p = BRep_Tool::Pnt(v); cout << msg << "( "<< p.X()<<", "<<p.Y()<<", "<<p.Z()<<" )"<<endl; }
71 #endif
72
73 #ifndef DUMP_VERT
74 #define DUMP_VERT(msg,v)
75 #endif
76
77 //================================================================================
78 // text for message about an internal error
79 #define ERR_LI(txt) SMESH_Comment(txt) << ":" << __LINE__
80
81 // order corresponds to right order of edges in CASCADE face
82 enum EQuadSides{ Q_BOTTOM=0, Q_RIGHT, Q_TOP, Q_LEFT,   Q_CHILD, Q_PARENT };
83
84 enum EBoxSides{ B_BOTTOM=0, B_RIGHT, B_TOP, B_LEFT, B_FRONT, B_BACK, B_UNDEFINED };
85
86 enum EAxes{ COO_X=1, COO_Y, COO_Z };
87
88 //================================================================================
89 /*!
90  * \brief Converter of a pair of integers to a sole index
91  */
92 struct _Indexer
93 {
94   int _xSize, _ySize;
95   _Indexer( int xSize, int ySize ): _xSize(xSize), _ySize(ySize) {}
96   int size() const { return _xSize * _ySize; }
97   int operator()(const int x, const int y) const { return y * _xSize + x; }
98 };
99
100 //================================================================================
101 /*!
102  * \brief Wrapper of a composite or an ordinary edge.
103  */
104 class _FaceSide
105 {
106 public:
107   _FaceSide(const _FaceSide& other);
108   _FaceSide(const TopoDS_Edge& edge=TopoDS_Edge());
109   _FaceSide(const list<TopoDS_Edge>& edges);
110   _FaceSide* GetSide(const int i);
111   const _FaceSide* GetSide(const int i) const;
112   int size() const { return myChildren.size(); }
113   int NbVertices() const;
114   int NbCommonVertices( const TopTools_MapOfShape& VV ) const;
115   TopoDS_Vertex FirstVertex() const;
116   TopoDS_Vertex LastVertex() const;
117   TopoDS_Vertex Vertex(int i) const;
118   TopoDS_Edge   Edge(int i) const;
119   bool Contain( const _FaceSide& side, int* which=0 ) const;
120   bool Contain( const TopoDS_Vertex& vertex ) const;
121   void AppendSide( const _FaceSide& side );
122   void SetBottomSide( int i );
123   int GetNbSegments(SMESH_ProxyMesh& mesh, const SMESHDS_SubMesh* smToCheckEdges=0) const;
124   bool StoreNodes(SMESH_ProxyMesh& mesh, vector<const SMDS_MeshNode*>& myGrid,
125                   bool reverse, bool isProxy, const SMESHDS_SubMesh* smToCheckEdges=0 );
126   void SetID(EQuadSides id) { myID = id; }
127   static inline const TopoDS_TShape* ptr(const TopoDS_Shape& theShape)
128   { return theShape.TShape().operator->(); }
129   void Dump() const;
130
131 private:
132
133
134   TopoDS_Edge       myEdge;
135   list< _FaceSide > myChildren;
136   int               myNbChildren;
137
138   TopTools_MapOfShape myVertices;
139
140   EQuadSides        myID; // debug
141 };
142 //================================================================================
143 /*!
144  * \brief Class corresponding to a meshed composite face of a box.
145  *        Provides simplified access to it's sub-mesh data.
146  */
147 class _QuadFaceGrid
148 {
149   typedef list< _QuadFaceGrid > TChildren;
150 public:
151   _QuadFaceGrid();
152
153 public: //** Methods to find and orient faces of 6 sides of the box **//
154   
155   //!< initialization
156   bool Init(const TopoDS_Face& f, SMESH_ProxyMesh& mesh );
157
158   //!< try to unite self with other face
159   bool AddContinuousFace( const _QuadFaceGrid& f, const TopTools_MapOfShape& internalEdges );
160
161   //!< Try to set the side as bottom hirizontal side
162   bool SetBottomSide(const _FaceSide& side, int* sideIndex=0);
163
164   //!< Return face adjacent to zero-based i-th side of this face
165   _QuadFaceGrid* FindAdjacentForSide(int i, list<_QuadFaceGrid>& faces, EBoxSides id) const;
166
167   //!< Reverse edges in order to have the bottom edge going along axes of the unit box
168   void ReverseEdges();
169
170   bool IsComplex() const { return !myChildren.empty(); }
171
172   int NbChildren() const { return myChildren.size(); }
173
174   typedef SMDS_SetIterator< const _QuadFaceGrid&,
175                             TChildren::const_iterator,
176                             SMDS::SimpleAccessor<const _QuadFaceGrid&,TChildren::const_iterator>,
177                             SMDS::PassAllValueFilter<_QuadFaceGrid> >
178     TChildIterator;
179
180   TChildIterator GetChildren() const
181   { return TChildIterator( myChildren.begin(), myChildren.end()); }
182
183 public: //** Loading and access to mesh **//
184
185   //!< Load nodes of a mesh
186   bool LoadGrid( SMESH_ProxyMesh& mesh );
187
188   //!< Computes normalized parameters of nodes of myGrid
189   void ComputeIJK( int i1, int i2, double v3 );
190
191   //!< Return number of segments on the hirizontal sides
192   int GetNbHoriSegments(SMESH_ProxyMesh& mesh, bool withBrothers=false) const;
193
194   //!< Return number of segments on the vertical sides
195   int GetNbVertSegments(SMESH_ProxyMesh& mesh, bool withBrothers=false) const;
196
197   //!< Return edge on the hirizontal bottom sides
198   int GetHoriEdges(vector<TopoDS_Edge> & edges) const;
199
200   //!< Return a node by its position
201   const SMDS_MeshNode* GetNode(int iHori, int iVert) const;
202
203   //!< Return node coordinates by its position
204   gp_XYZ GetXYZ(int iHori, int iVert) const;
205
206   //!< Return normalized parameters of nodes within the unitary cube
207   gp_XYZ& GetIJK(int iCol, int iRow) { return myIJK[ myIndexer( iCol, iRow )]; }
208
209 public: //** Access to member fields **//
210
211   //!< Return i-th face side (0<i<4)
212   const _FaceSide& GetSide(int i) const;
213
214   //!< Return it's face, NULL if it is composite
215   TopoDS_Face GetFace() const { return myFace; }
216
217   //!< Return normal to the face at vertex v
218   bool GetNormal( const TopoDS_Vertex& v, gp_Vec& n ) const;
219
220   SMESH_ComputeErrorPtr GetError() const { return myError; }
221
222   void SetID(EBoxSides id) { myID = id; }
223
224   void DumpGrid() const;
225
226   void DumpVertices() const;
227
228 private:
229
230   bool error(const std::string& text, int code = COMPERR_ALGO_FAILED)
231   { myError = SMESH_ComputeError::New( code, text ); return false; }
232
233   bool error(const SMESH_ComputeErrorPtr& err)
234   { myError = err; return ( !myError || myError->IsOK() ); }
235
236   bool loadCompositeGrid(SMESH_ProxyMesh& mesh);
237
238   bool fillGrid(SMESH_ProxyMesh&               theMesh,
239                 vector<const SMDS_MeshNode*> & theGrid,
240                 const _Indexer&                theIndexer,
241                 int                            theX,
242                 int                            theY);
243
244   bool locateChildren();
245
246   void setBrothers( set< _QuadFaceGrid* >& notLocatedBrothers );
247
248   TopoDS_Face myFace;
249   _FaceSide   mySides;
250   bool        myReverse;
251
252   TChildren   myChildren;
253
254   _QuadFaceGrid* myLeftBottomChild;
255   _QuadFaceGrid* myRightBrother;
256   _QuadFaceGrid* myUpBrother;
257
258   _Indexer                      myIndexer;
259   vector<const SMDS_MeshNode*>  myGrid;
260   vector<gp_XYZ>                myIJK; // normalized parameters of nodes
261
262   SMESH_ComputeErrorPtr         myError;
263
264   EBoxSides   myID; // debug
265 };
266
267 //================================================================================
268 /*!
269  * \brief Constructor
270  */
271 //================================================================================
272
273 StdMeshers_CompositeHexa_3D::StdMeshers_CompositeHexa_3D(int hypId, SMESH_Gen* gen)
274   :SMESH_3D_Algo(hypId, gen)
275 {
276   _name = "CompositeHexa_3D";
277   _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);       // 1 bit /shape type
278 }
279
280 //================================================================================
281 /*!
282  * \brief always return true
283  */
284 //================================================================================
285
286 bool StdMeshers_CompositeHexa_3D::CheckHypothesis(SMESH_Mesh&         aMesh,
287                                                   const TopoDS_Shape& aShape,
288                                                   Hypothesis_Status&  aStatus)
289 {
290   aStatus = HYP_OK;
291   return true;
292 }
293
294 namespace
295 {
296
297   //================================================================================
298   /*!
299    * \brief Checks structure of a quadrangular mesh at the common VERTEX of two EDGEs.
300    *        Returns true if there are two quadrangles near the VERTEX.
301    */
302   //================================================================================
303
304   bool isContinuousMesh(TopoDS_Edge            E1,
305                         TopoDS_Edge            E2,
306                         const TopoDS_Face&     F,
307                         const SMESH_ProxyMesh& mesh)
308   {
309     if (E1.Orientation() > TopAbs_REVERSED) // INTERNAL
310       E1.Orientation( TopAbs_FORWARD );
311     if (E2.Orientation() > TopAbs_REVERSED) // INTERNAL
312       E2.Orientation( TopAbs_FORWARD );
313
314     TopoDS_Vertex V;
315     if ( !TopExp::CommonVertex( E1, E2, V )) return false;
316
317     const SMDS_MeshNode* n = SMESH_Algo::VertexNode( V, mesh.GetMeshDS() );
318     if ( !n ) return SMESH_Algo::IsContinuous( E1, E2 ); // meshed by "composite segment"
319
320     n = mesh.GetProxyNode( n );
321
322     const SMESHDS_SubMesh* sm = mesh.GetSubMesh( F );
323     if ( !sm ) return false;
324
325     int nbQuads = 0;
326     SMDS_ElemIteratorPtr fIt = mesh.GetInverseElementIterator( n, SMDSAbs_Face );
327     if ( !fIt->more() )
328       return SMESH_Algo::IsContinuous( E1, E2 ); // meshed by "composite segment"
329     while ( fIt->more() )
330     {
331       const SMDS_MeshElement* f = fIt->next();
332       if ( !sm->Contains( f )) continue;
333
334       if ( f->NbCornerNodes() == 4 )
335         ++nbQuads;
336       else
337         return false;
338     }
339     return nbQuads == 2;
340   }
341
342   //================================================================================
343   /*!
344    * \brief Return true if a vertex holds a node and this node is used by some quadrangle
345    */
346   //================================================================================
347
348   // bool isMeshedVertex( TopoDS_Vertex&     V,
349   //                      const SMESH_Mesh&  mesh )
350   // {
351   //   const SMDS_MeshNode* n = SMESH_Algo::VertexNode( V, mesh.GetMeshDS() );
352   //   if ( !n ) return false;
353     
354   //   SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
355   //   while ( fIt->more() )
356   //   {
357   //     const SMDS_MeshElement* f = fIt->next();
358   //     if ( f->NbCornerNodes() == 4 )
359   //       return true;
360   //   }
361   //   return false;
362   // }
363
364   //================================================================================
365   /*!
366    * \brief Finds VERTEXes located at block corners
367    */
368   //================================================================================
369
370   void getBlockCorners( SMESH_ProxyMesh&     mesh,
371                         const TopoDS_Shape&  shape,
372                         TopTools_MapOfShape& cornerVV)
373   {
374     std::set<int> faceIDs; // ids of FACEs in the shape
375     TopExp_Explorer exp;
376     for ( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
377       faceIDs.insert( mesh.GetMeshDS()->ShapeToIndex( exp.Current() ));
378
379     TopTools_MapOfShape checkedVV;
380     for ( exp.Init( shape, TopAbs_VERTEX ); exp.More(); exp.Next() )
381     {
382       TopoDS_Vertex V = TopoDS::Vertex( exp.Current() );
383       if ( !checkedVV.Add( V )) continue;
384
385       const SMDS_MeshNode* n = SMESH_Algo::VertexNode( V, mesh.GetMeshDS() );
386       if ( !n ) continue;
387
388       const SMDS_MeshNode* nProxy = mesh.GetProxyNode( n );
389       bool isProxy = ( nProxy != n );
390       n = nProxy;
391
392       int nbQuads = 0;
393       SMDS_ElemIteratorPtr fIt = mesh.GetInverseElementIterator( n, SMDSAbs_Face );
394       while ( fIt->more() )
395       {
396         const SMDS_MeshElement* f = fIt->next();
397         if ( !faceIDs.count( f->getshapeId() )) continue;
398
399         if ( isProxy && !mesh.GetSubMesh( f->getshapeId() )->Contains( f ))
400           continue;
401
402         if ( f->NbCornerNodes() == 4 )
403           ++nbQuads;
404         else
405           nbQuads = 100;
406       }
407       if ( nbQuads == 3 )
408         cornerVV.Add( V );
409     }
410   }
411
412   //================================================================================
413   /*!
414    * \brief Return EDGEs dividing one box side
415    */
416   //================================================================================
417
418   bool getInternalEdges( SMESH_Mesh&                mesh,
419                          const TopoDS_Shape&        shape,
420                          const TopTools_MapOfShape& cornerVV,
421                          TopTools_MapOfShape&       internEE)
422   {
423     TopTools_IndexedMapOfShape subEE;
424     TopExp::MapShapes( shape, TopAbs_EDGE, subEE );
425     //TopExp::MapShapes( shape, TopAbs_FACE, subFF );
426
427     TopoDS_Vertex VV[2];
428     TopTools_MapOfShape subChecked, ridgeEE;
429     TopTools_MapIteratorOfMapOfShape vIt( cornerVV );
430     for ( ; vIt.More(); vIt.Next() )
431     {
432       TopoDS_Shape V0 = vIt.Key();
433       // walk from one corner VERTEX to another along ridge EDGEs
434       PShapeIteratorPtr riIt = SMESH_MesherHelper::GetAncestors( V0, mesh, TopAbs_EDGE );
435       while ( const TopoDS_Shape* riE = riIt->next() )
436       {
437         if ( !subEE.Contains( *riE ) || !subChecked.Add( *riE ))
438           continue;
439         TopoDS_Edge ridgeE = TopoDS::Edge( *riE );
440         while ( !ridgeE.IsNull() )
441         {
442           if ( !ridgeEE.Add( ridgeE ))
443             break;
444           TopExp::Vertices( ridgeE, VV[0], VV[1] );
445           TopoDS_Shape V1 = VV[ V0.IsSame( VV[0] )];
446           if ( cornerVV.Contains( V1 ) )
447             break; // ridgeE reached a corner VERTEX
448
449           // detect internal EDGEs among those sharing V1. There can be 2, 3 or 4 EDGEs and
450           // number of internal EDGEs is N-2
451           TopoDS_Shape nextRidgeE;
452           PShapeIteratorPtr eIt = SMESH_MesherHelper::GetAncestors( V1, mesh, TopAbs_EDGE );
453           while ( const TopoDS_Shape* E = eIt->next() )
454           {
455             if ( E->IsSame( ridgeE ) || !subEE.Contains( *E ) || !subChecked.Add( *E ))
456               continue;
457             // look for FACEs sharing both E and ridgeE
458             PShapeIteratorPtr fIt = SMESH_MesherHelper::GetAncestors( *E, mesh, TopAbs_FACE );
459             while ( const TopoDS_Shape* F = fIt->next() )
460             {
461               if ( !SMESH_MesherHelper::IsSubShape( ridgeE, *F ))
462                 continue;
463               if ( isContinuousMesh( ridgeE, TopoDS::Edge( *E ), TopoDS::Face( *F ), mesh ))
464               {
465                 nextRidgeE = *E;
466               }
467               else
468               {
469                 internEE.Add( *E );
470               }
471               break;
472             }
473           }
474           // look for the next ridge EDGE ending at V1
475           if ( nextRidgeE.IsNull() )
476           {
477             eIt = SMESH_MesherHelper::GetAncestors( V1, mesh, TopAbs_EDGE );
478             while ( const TopoDS_Shape* E = eIt->next() )
479               if ( !ridgeE.IsSame( *E ) && !internEE.Contains( *E ) && subEE.Contains( *E ))
480               {
481                 nextRidgeE = *E;
482                 break;
483               }
484           }
485           ridgeE = TopoDS::Edge( nextRidgeE );
486           V0 = V1;
487
488           if ( ridgeE.IsNull() )
489             return false;
490         } // check EDGEs around the last VERTEX of ridgeE 
491       } // loop on ridge EDGEs around a corner VERTEX
492     } // loop on on corner VERTEXes
493
494     if ( subEE.Extent() > ridgeEE.Extent() + internEE.Extent() ) // PAL23269
495       for ( int i = 1; i < subEE.Extent(); ++i )
496         if ( !ridgeEE.Contains( subEE(i) ))
497           internEE.Add( subEE(i) );
498
499     return true;
500   } // getInternalEdges()
501
502   //================================================================================
503   /*!
504    * \brief Find a face including two given nodes
505    */
506   //================================================================================
507
508   const SMDS_MeshElement* FindFaceByNodes( const SMDS_MeshNode* n1,
509                                            const SMDS_MeshNode* n2,
510                                            TIDSortedElemSet     avoidSet,
511                                            SMESH_ProxyMesh&     mesh)
512   {
513     SMDS_ElemIteratorPtr faceIt = mesh.GetInverseElementIterator( n1, SMDSAbs_Face );
514     while ( faceIt->more() )
515     {
516       const SMDS_MeshElement* f = faceIt->next();
517       if ( !avoidSet.count( f ) && f->GetNodeIndex( n2 ) >= 0 )
518         return f;
519     }
520     return 0;
521   }
522
523   //================================================================================
524   /*!
525    * \brief Check that a segment bounds a face belonging to smOfFaces
526    */
527   //================================================================================
528
529   bool IsSegmentOnSubMeshBoundary( const SMDS_MeshNode*   n1,
530                                    const SMDS_MeshNode*   n2,
531                                    const SMESHDS_SubMesh* smOfFaces,
532                                    SMESH_ProxyMesh&       mesh)
533   {
534     TIDSortedElemSet avoidSet;
535     bool faceFound = false;
536
537     while ( const SMDS_MeshElement* f = FindFaceByNodes( n1, n2, avoidSet, mesh ))
538     {
539       if (( faceFound = smOfFaces->Contains( f )))
540         break;
541       avoidSet.insert( f );
542     }
543     return faceFound;
544   }
545
546 } // namespace
547
548 //================================================================================
549 /*!
550  * \brief Tries to find 6 sides of a box
551  */
552 //================================================================================
553
554 bool StdMeshers_CompositeHexa_3D::findBoxFaces( const TopoDS_Shape&    shape,
555                                                 list< _QuadFaceGrid >& boxFaces,
556                                                 SMESH_Mesh&            mesh,
557                                                 SMESH_ProxyMesh&       proxyMesh,
558                                                 _QuadFaceGrid * &      fBottom,
559                                                 _QuadFaceGrid * &      fTop,
560                                                 _QuadFaceGrid * &      fFront,
561                                                 _QuadFaceGrid * &      fBack,
562                                                 _QuadFaceGrid * &      fLeft,
563                                                 _QuadFaceGrid * &      fRight)
564 {
565   TopTools_MapOfShape cornerVertices;
566   getBlockCorners( proxyMesh, shape, cornerVertices );
567   if ( cornerVertices.Extent() != 8 )
568     return error( COMPERR_BAD_INPUT_MESH, "Can't find 8 corners of a block by 2D mesh" );
569   TopTools_MapOfShape internalEdges;
570   if ( !getInternalEdges( mesh, shape, cornerVertices, internalEdges ))
571     return error( COMPERR_BAD_INPUT_MESH, "2D mesh is not suitable for i,j,k hexa meshing" );
572
573   list< _QuadFaceGrid >::iterator boxFace;
574   TopExp_Explorer exp;
575   int nbFaces = 0;
576   for ( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next(), ++nbFaces )
577   {
578     _QuadFaceGrid f;
579     if ( !f.Init( TopoDS::Face( exp.Current() ), proxyMesh ))
580       return error (COMPERR_BAD_SHAPE);
581
582     _QuadFaceGrid* prevContinuous = 0;
583     for ( boxFace = boxFaces.begin(); boxFace != boxFaces.end(); ++boxFace )
584     {
585       if ( prevContinuous )
586       {
587         if ( prevContinuous->AddContinuousFace( *boxFace, internalEdges ))
588           boxFace = --boxFaces.erase( boxFace );
589       }
590       else if ( boxFace->AddContinuousFace( f, internalEdges ))
591       {
592         prevContinuous = & (*boxFace);
593       }
594     }
595     if ( !prevContinuous )
596       boxFaces.push_back( f );
597   }
598   // Check what we have
599   if ( boxFaces.size() != 6 && nbFaces != 6)
600     return error
601       (COMPERR_BAD_SHAPE,
602        SMESH_Comment("Can't find 6 sides of a box. Number of found sides - ")<<boxFaces.size());
603
604   if ( boxFaces.size() != 6 && nbFaces == 6 ) { // strange ordinary box with continuous faces
605     boxFaces.resize( 6 );
606     boxFace = boxFaces.begin();
607     for ( exp.Init( shape, TopAbs_FACE); exp.More(); exp.Next(), ++boxFace )
608       boxFace->Init( TopoDS::Face( exp.Current() ), proxyMesh );
609   }
610   // ----------------------------------------
611   // Find out position of faces within a box
612   // ----------------------------------------
613   // start from a bottom face
614   fBottom = &boxFaces.front();
615   fBottom->SetID( B_BOTTOM );
616   // find vertical faces
617   fFront = fBottom->FindAdjacentForSide( Q_BOTTOM, boxFaces, B_FRONT );
618   fLeft  = fBottom->FindAdjacentForSide( Q_RIGHT,  boxFaces, B_LEFT  );
619   fBack  = fBottom->FindAdjacentForSide( Q_TOP,    boxFaces, B_BACK  );
620   fRight = fBottom->FindAdjacentForSide( Q_LEFT,   boxFaces, B_RIGHT );
621   // check the found
622   if ( !fFront || !fBack || !fLeft || !fRight )
623     return error(COMPERR_BAD_SHAPE);
624   // find a top face
625   fTop = 0;
626   for ( boxFace = ++boxFaces.begin(); boxFace != boxFaces.end() && !fTop; ++boxFace )
627   {
628     fTop = & (*boxFace);
629     fTop->SetID( B_TOP );
630     if ( fTop==fFront || fTop==fLeft || fTop==fBack || fTop==fRight )
631       fTop = 0;
632   }
633   // set bottom of the top side
634   if ( !fTop->SetBottomSide( fFront->GetSide( Q_TOP ) )) {
635     if ( !fFront->IsComplex() )
636       return error( ERR_LI("Error in StdMeshers_CompositeHexa_3D::Compute()"));
637     else {
638       _QuadFaceGrid::TChildIterator chIt = fFront->GetChildren();
639       while ( chIt.more() ) {
640         const _QuadFaceGrid& frontChild = chIt.next();
641         if ( fTop->SetBottomSide( frontChild.GetSide( Q_TOP )))
642           break;
643       }
644     }
645   }
646   if ( !fTop )
647     return error(COMPERR_BAD_SHAPE);
648
649   // orient bottom edge of faces along axes of the unit box
650   fBottom->ReverseEdges();
651   fBack  ->ReverseEdges();
652   fLeft  ->ReverseEdges();
653
654   return true;
655 }
656
657 //================================================================================
658 /*!
659  * \brief Computes hexahedral mesh on a box with composite sides
660  *  \param aMesh - mesh to compute
661  *  \param aShape - shape to mesh
662  *  \retval bool - success sign
663  */
664 //================================================================================
665
666 bool StdMeshers_CompositeHexa_3D::Compute(SMESH_Mesh&         theMesh,
667                                           const TopoDS_Shape& theShape)
668 {
669   SMESH_MesherHelper helper( theMesh );
670   _quadraticMesh = helper.IsQuadraticSubMesh( theShape );
671   helper.SetElementsOnShape( true );
672
673   // get Viscous Mesh
674   SMESH_ProxyMesh::Ptr proxyMesh;
675   SMESH_HypoFilter vlFilter( SMESH_HypoFilter::HasName( StdMeshers_ViscousLayers::GetHypType() ));
676   const SMESH_Hypothesis *          hyp = theMesh.GetHypothesis( theShape, vlFilter, true );
677   const StdMeshers_ViscousLayers* vlHyp = static_cast< const StdMeshers_ViscousLayers* >( hyp );
678   if ( vlHyp )
679     proxyMesh = vlHyp->Compute( theMesh, theShape, /*toMakeN2NMap=*/true );
680   else
681     proxyMesh.reset( new SMESH_ProxyMesh( theMesh ));
682
683   // -------------------------
684   // Try to find 6 side faces
685   // -------------------------
686   list< _QuadFaceGrid > boxFaceContainer;
687   _QuadFaceGrid *fBottom, *fTop, *fFront, *fBack, *fLeft, *fRight;
688   if ( ! findBoxFaces( theShape, boxFaceContainer, theMesh, *proxyMesh,
689                        fBottom, fTop, fFront, fBack, fLeft, fRight))
690     return false;
691
692   // ------------------------------------------
693   // Fill columns of nodes with existing nodes
694   // ------------------------------------------
695
696   // let faces load their grids
697   if ( !fBottom->LoadGrid( *proxyMesh )) return error( fBottom->GetError() );
698   if ( !fBack  ->LoadGrid( *proxyMesh )) return error( fBack  ->GetError() );
699   if ( !fLeft  ->LoadGrid( *proxyMesh )) return error( fLeft  ->GetError() );
700   if ( !fFront ->LoadGrid( *proxyMesh )) return error( fFront ->GetError() );
701   if ( !fRight ->LoadGrid( *proxyMesh )) return error( fRight ->GetError() );
702   if ( !fTop   ->LoadGrid( *proxyMesh )) return error( fTop   ->GetError() );
703
704   // compute normalized parameters of nodes on sides (PAL23189)
705   fBottom->ComputeIJK( COO_X, COO_Y, /*z=*/0. );
706   fBack  ->ComputeIJK( COO_X, COO_Z, /*y=*/1. );
707   fLeft  ->ComputeIJK( COO_Y, COO_Z, /*x=*/0. );
708   fFront ->ComputeIJK( COO_X, COO_Z, /*y=*/0. );
709   fRight ->ComputeIJK( COO_Y, COO_Z, /*x=*/1. );
710   fTop   ->ComputeIJK( COO_X, COO_Y, /*z=*/1. );
711
712   int x, xSize = fBottom->GetNbHoriSegments(*proxyMesh) + 1, X = xSize - 1;
713   int y, ySize = fBottom->GetNbVertSegments(*proxyMesh) + 1, Y = ySize - 1;
714   int z, zSize = fFront ->GetNbVertSegments(*proxyMesh) + 1, Z = zSize - 1;
715   _Indexer colIndex( xSize, ySize );
716   vector< vector< const SMDS_MeshNode* > > columns( colIndex.size() );
717
718   // fill node columns by front and back box sides
719   for ( x = 0; x < xSize; ++x ) {
720     vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( x, 0 )];
721     vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( x, Y )];
722     column0.resize( zSize );
723     column1.resize( zSize );
724     for ( z = 0; z < zSize; ++z ) {
725       column0[ z ] = fFront->GetNode( x, z );
726       column1[ z ] = fBack ->GetNode( x, z );
727     }
728   }
729   // fill node columns by left and right box sides
730   for ( y = 1; y < ySize-1; ++y ) {
731     vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( 0, y )];
732     vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( X, y )];
733     column0.resize( zSize );
734     column1.resize( zSize );
735     for ( z = 0; z < zSize; ++z ) {
736       column0[ z ] = fLeft ->GetNode( y, z );
737       column1[ z ] = fRight->GetNode( y, z );
738     }
739   }
740   // get nodes from top and bottom box sides
741   for ( x = 1; x < xSize-1; ++x ) {
742     for ( y = 1; y < ySize-1; ++y ) {
743       vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )];
744       column.resize( zSize );
745       column.front() = fBottom->GetNode( x, y );
746       column.back()  = fTop   ->GetNode( x, y );
747     }
748   }
749
750   // ----------------------------
751   // Add internal nodes of a box
752   // ----------------------------
753   // projection points of internal nodes on box sub-shapes by which
754   // coordinates of internal nodes are computed
755   vector<gp_XYZ> pointsOnShapes( SMESH_Block::ID_Shell );
756
757   // projections on vertices are constant
758   pointsOnShapes[ SMESH_Block::ID_V000 ] = fBottom->GetXYZ( 0, 0 );
759   pointsOnShapes[ SMESH_Block::ID_V100 ] = fBottom->GetXYZ( X, 0 );
760   pointsOnShapes[ SMESH_Block::ID_V010 ] = fBottom->GetXYZ( 0, Y );
761   pointsOnShapes[ SMESH_Block::ID_V110 ] = fBottom->GetXYZ( X, Y );
762   pointsOnShapes[ SMESH_Block::ID_V001 ] = fTop->GetXYZ( 0, 0 );
763   pointsOnShapes[ SMESH_Block::ID_V101 ] = fTop->GetXYZ( X, 0 );
764   pointsOnShapes[ SMESH_Block::ID_V011 ] = fTop->GetXYZ( 0, Y );
765   pointsOnShapes[ SMESH_Block::ID_V111 ] = fTop->GetXYZ( X, Y );
766
767   gp_XYZ params; // normalized parameters of an internal node within the unit box
768
769   for ( x = 1; x < xSize-1; ++x )
770   {
771     const double rX = x / double(X);
772     for ( y = 1; y < ySize-1; ++y )
773     {
774       const double rY = y / double(Y);
775       // column to fill during z loop
776       vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )];
777       // points projections on horizontal edges
778       pointsOnShapes[ SMESH_Block::ID_Ex00 ] = fBottom->GetXYZ( x, 0 );
779       pointsOnShapes[ SMESH_Block::ID_Ex10 ] = fBottom->GetXYZ( x, Y );
780       pointsOnShapes[ SMESH_Block::ID_E0y0 ] = fBottom->GetXYZ( 0, y );
781       pointsOnShapes[ SMESH_Block::ID_E1y0 ] = fBottom->GetXYZ( X, y );
782       pointsOnShapes[ SMESH_Block::ID_Ex01 ] = fTop->GetXYZ( x, 0 );
783       pointsOnShapes[ SMESH_Block::ID_Ex11 ] = fTop->GetXYZ( x, Y );
784       pointsOnShapes[ SMESH_Block::ID_E0y1 ] = fTop->GetXYZ( 0, y );
785       pointsOnShapes[ SMESH_Block::ID_E1y1 ] = fTop->GetXYZ( X, y );
786       // points projections on horizontal faces
787       pointsOnShapes[ SMESH_Block::ID_Fxy0 ] = fBottom->GetXYZ( x, y );
788       pointsOnShapes[ SMESH_Block::ID_Fxy1 ] = fTop   ->GetXYZ( x, y );
789       for ( z = 1; z < zSize-1; ++z ) // z loop
790       {
791         // compute normalized parameters of an internal node within the unit box
792         const double   rZ = z / double(Z);
793         const gp_XYZ& pBo = fBottom->GetIJK( x, y );
794         const gp_XYZ& pTo = fTop   ->GetIJK( x, y );
795         const gp_XYZ& pFr = fFront ->GetIJK( x, z );
796         const gp_XYZ& pBa = fBack  ->GetIJK( x, z );
797         const gp_XYZ& pLe = fLeft  ->GetIJK( y, z );
798         const gp_XYZ& pRi = fRight ->GetIJK( y, z );
799         params.SetCoord( 1, 0.5 * ( pBo.X() * ( 1. - rZ ) + pTo.X() * rZ  +
800                                     pFr.X() * ( 1. - rY ) + pBa.X() * rY ));
801         params.SetCoord( 2, 0.5 * ( pBo.Y() * ( 1. - rZ ) + pTo.Y() * rZ  +
802                                     pLe.Y() * ( 1. - rX ) + pRi.Y() * rX ));
803         params.SetCoord( 3, 0.5 * ( pFr.Z() * ( 1. - rY ) + pBa.Z() * rY  +
804                                     pLe.Z() * ( 1. - rX ) + pRi.Z() * rX ));
805
806         // point projections on vertical edges
807         pointsOnShapes[ SMESH_Block::ID_E00z ] = fFront->GetXYZ( 0, z );
808         pointsOnShapes[ SMESH_Block::ID_E10z ] = fFront->GetXYZ( X, z );
809         pointsOnShapes[ SMESH_Block::ID_E01z ] = fBack->GetXYZ( 0, z );
810         pointsOnShapes[ SMESH_Block::ID_E11z ] = fBack->GetXYZ( X, z );
811         // point projections on vertical faces
812         pointsOnShapes[ SMESH_Block::ID_Fx0z ] = fFront->GetXYZ( x, z );
813         pointsOnShapes[ SMESH_Block::ID_Fx1z ] = fBack ->GetXYZ( x, z );    
814         pointsOnShapes[ SMESH_Block::ID_F0yz ] = fLeft ->GetXYZ( y, z );    
815         pointsOnShapes[ SMESH_Block::ID_F1yz ] = fRight->GetXYZ( y, z );
816
817         // compute internal node coordinates
818         gp_XYZ coords;
819         SMESH_Block::ShellPoint( params, pointsOnShapes, coords );
820         column[ z ] = helper.AddNode( coords.X(), coords.Y(), coords.Z() );
821
822 #ifdef DEB_GRID
823         // debug
824         //cout << "----------------------------------------------------------------------"<<endl;
825         //for ( int id = SMESH_Block::ID_V000; id < SMESH_Block::ID_Shell; ++id)
826         //{
827         //  gp_XYZ p = pointsOnShapes[ id ];
828         //  SMESH_Block::DumpShapeID( id,cout)<<" ( "<<p.X()<<", "<<p.Y()<<", "<<p.Z()<<" )"<<endl;
829         //}
830         //cout << "Params: ( "<< params.X()<<", "<<params.Y()<<", "<<params.Z()<<" )"<<endl;
831         //cout << "coords: ( "<< coords.X()<<", "<<coords.Y()<<", "<<coords.Z()<<" )"<<endl;
832 #endif
833       }
834     }
835   }
836   // faces no more needed, free memory
837   boxFaceContainer.clear();
838
839   // ----------------
840   // Add hexahedrons
841   // ----------------
842   for ( x = 0; x < xSize-1; ++x ) {
843     for ( y = 0; y < ySize-1; ++y ) {
844       vector< const SMDS_MeshNode* >& col00 = columns[ colIndex( x, y )];
845       vector< const SMDS_MeshNode* >& col10 = columns[ colIndex( x+1, y )];
846       vector< const SMDS_MeshNode* >& col01 = columns[ colIndex( x, y+1 )];
847       vector< const SMDS_MeshNode* >& col11 = columns[ colIndex( x+1, y+1 )];
848       for ( z = 0; z < zSize-1; ++z )
849       {
850         // bottom face normal of a hexa mush point outside the volume
851         helper.AddVolume(col00[z],   col01[z],   col11[z],   col10[z],
852                          col00[z+1], col01[z+1], col11[z+1], col10[z+1]);
853       }
854     }
855   }
856   return true;
857 }
858
859 //================================================================================
860 /*!
861  *  Evaluate
862  */
863 //================================================================================
864
865 bool StdMeshers_CompositeHexa_3D::Evaluate(SMESH_Mesh&         theMesh,
866                                            const TopoDS_Shape& theShape,
867                                            MapShapeNbElems&    aResMap)
868 {
869   SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( theMesh ));
870
871   // -------------------------
872   // Try to find 6 side faces
873   // -------------------------
874   list< _QuadFaceGrid > boxFaceContainer;
875   _QuadFaceGrid *fBottom, *fTop, *fFront, *fBack, *fLeft, *fRight;
876   if ( ! findBoxFaces( theShape, boxFaceContainer, theMesh, *proxyMesh,
877                        fBottom, fTop, fFront, fBack, fLeft, fRight))
878     return false;
879
880   // Find a less complex side
881   _QuadFaceGrid * lessComplexSide = & boxFaceContainer.front();
882   list< _QuadFaceGrid >::iterator face = boxFaceContainer.begin();
883   for ( ++face; face != boxFaceContainer.end() && lessComplexSide->IsComplex(); ++face )
884     if ( face->NbChildren() < lessComplexSide->NbChildren() )
885       lessComplexSide = & *face;
886
887   // Get an 1D size of lessComplexSide
888   int nbSeg1 = 0;
889   vector<TopoDS_Edge> edges;
890   if ( !lessComplexSide->GetHoriEdges(edges) )
891     return false;
892   for ( size_t i = 0; i < edges.size(); ++i )
893   {
894     const vector<int>& nbElems = aResMap[ theMesh.GetSubMesh( edges[i] )];
895     if ( !nbElems.empty() )
896       nbSeg1 += Max( nbElems[ SMDSEntity_Edge ], nbElems[ SMDSEntity_Quad_Edge ]);
897   }
898
899   // Get an 1D size of a box side orthogonal to lessComplexSide
900   int nbSeg2 = 0;
901   _QuadFaceGrid* ortoSide =
902     lessComplexSide->FindAdjacentForSide( Q_LEFT, boxFaceContainer, B_UNDEFINED );
903   edges.clear();
904   if ( !ortoSide || !ortoSide->GetHoriEdges(edges) ) return false;
905   for ( size_t i = 0; i < edges.size(); ++i )
906   {
907     const vector<int>& nbElems = aResMap[ theMesh.GetSubMesh( edges[i] )];
908     if ( !nbElems.empty() )
909       nbSeg2 += Max( nbElems[ SMDSEntity_Edge ], nbElems[ SMDSEntity_Quad_Edge ]);
910   }
911
912   // Get an 2D size of a box side orthogonal to lessComplexSide
913   int nbFaces = 0, nbQuadFace = 0;
914   list< TopoDS_Face > sideFaces;
915   if ( ortoSide->IsComplex() )
916     for ( _QuadFaceGrid::TChildIterator child = ortoSide->GetChildren(); child.more(); )
917       sideFaces.push_back( child.next().GetFace() );
918   else
919     sideFaces.push_back( ortoSide->GetFace() );
920   //
921   list< TopoDS_Face >::iterator f = sideFaces.begin();
922   for ( ; f != sideFaces.end(); ++f )
923   {
924     const vector<int>& nbElems = aResMap[ theMesh.GetSubMesh( *f )];
925     if ( !nbElems.empty() )
926     {
927       nbFaces    = nbElems[ SMDSEntity_Quadrangle ];
928       nbQuadFace = nbElems[ SMDSEntity_Quad_Quadrangle ];
929     }
930   }
931
932   // Fill nb of elements
933   vector<int> aResVec(SMDSEntity_Last,0);
934   int nbSeg3 = ( nbFaces + nbQuadFace ) / nbSeg2;
935   aResVec[SMDSEntity_Node]       = (nbSeg1-1) * (nbSeg2-1) * (nbSeg3-1);
936   aResVec[SMDSEntity_Hexa]       = nbSeg1 * nbFaces;
937   aResVec[SMDSEntity_Quad_Hexa]  = nbSeg1 * nbQuadFace;
938
939   aResMap.insert( make_pair( theMesh.GetSubMesh(theShape), aResVec ));
940
941   return true;
942 }
943
944
945 //================================================================================
946 /*!
947  * \brief constructor of non-initialized _QuadFaceGrid
948  */
949 //================================================================================
950
951 _QuadFaceGrid::_QuadFaceGrid():
952   myReverse(false), myRightBrother(0), myUpBrother(0), myIndexer(0,0), myID(B_UNDEFINED)
953 {
954 }
955
956 //================================================================================
957 /*!
958  * \brief Initialization
959  */
960 //================================================================================
961
962 bool _QuadFaceGrid::Init(const TopoDS_Face& f, SMESH_ProxyMesh& mesh)
963 {
964   myFace         = f;
965   mySides        = _FaceSide();
966   myReverse      = false;
967   myLeftBottomChild = myRightBrother = myUpBrother = 0;
968   myChildren.clear();
969   myGrid.clear();
970   //if ( myFace.Orientation() != TopAbs_FORWARD )
971     //myFace.Reverse();
972
973   list< TopoDS_Edge > edges;
974   list< int > nbEdgesInWire;
975   int nbWire = SMESH_Block::GetOrderedEdges (myFace, edges, nbEdgesInWire);
976   if ( nbWire != 1 )
977     return false;
978
979   list< TopoDS_Edge >::iterator edgeIt = edges.begin();
980   if ( nbEdgesInWire.front() == 4 ) // exactly 4 edges
981   {
982     for ( ; edgeIt != edges.end(); ++edgeIt )
983       mySides.AppendSide( _FaceSide( *edgeIt ));
984   }
985   else if ( nbEdgesInWire.front() > 4 ) { // more than 4 edges - try to unite some
986     list< TopoDS_Edge > sideEdges;
987     while ( !edges.empty()) {
988       sideEdges.clear();
989       sideEdges.splice( sideEdges.end(), edges, edges.begin());// edges.front()->sideEdges.back()
990       if ( SMESH_Algo::isDegenerated( sideEdges.back() ))
991         continue;
992       while ( !edges.empty() ) {
993         if ( isContinuousMesh( sideEdges.back(), edges.front(), f, mesh )) {
994           sideEdges.splice( sideEdges.end(), edges, edges.begin());
995         }
996         else if ( isContinuousMesh( sideEdges.front(), edges.back(), f, mesh )) {
997           sideEdges.splice( sideEdges.begin(), edges, --edges.end());
998         }
999         else {
1000           break;
1001         }
1002       }
1003       mySides.AppendSide( _FaceSide( sideEdges ));
1004     }
1005   }
1006   if (mySides.size() != 4)
1007     return false;
1008
1009 #ifdef _DEBUG_
1010   mySides.GetSide( Q_BOTTOM )->SetID( Q_BOTTOM );
1011   mySides.GetSide( Q_RIGHT  )->SetID( Q_RIGHT );
1012   mySides.GetSide( Q_TOP    )->SetID( Q_TOP );
1013   mySides.GetSide( Q_LEFT   )->SetID( Q_LEFT );
1014 #endif
1015
1016   return true;
1017 }
1018
1019 //================================================================================
1020 /*!
1021  * \brief Try to unite self with other ordinary face
1022  */
1023 //================================================================================
1024
1025 bool _QuadFaceGrid::AddContinuousFace( const _QuadFaceGrid&       other,
1026                                        const TopTools_MapOfShape& internalEdges)
1027 {
1028   for ( int i = 0; i < 4; ++i )
1029   {
1030     const _FaceSide& otherSide = other.GetSide( i );
1031     int iMyCommon;
1032     if ( mySides.Contain( otherSide, &iMyCommon ))
1033     {
1034       if ( internalEdges.Contains( otherSide.Edge( 0 )))
1035       {
1036         DUMP_VERT("Cont 1", mySides.GetSide(iMyCommon)->FirstVertex());
1037         DUMP_VERT("Cont 2", mySides.GetSide(iMyCommon)->LastVertex());
1038         DUMP_VERT("Cont 3", otherSide.FirstVertex());
1039         DUMP_VERT("Cont 4", otherSide.LastVertex());
1040
1041         if ( myChildren.empty() )
1042         {
1043           myChildren.push_back( *this );
1044           myFace.Nullify();
1045         }
1046         else // find iMyCommon in myChildren
1047         {
1048           for ( TChildIterator children = GetChildren(); children.more(); ) {
1049             const _QuadFaceGrid& child = children.next();
1050             if ( child.mySides.Contain( otherSide, &iMyCommon ))
1051               break;
1052           }
1053         }
1054
1055         // orient new children equally
1056         int otherBottomIndex = SMESH_MesherHelper::WrapIndex( i - iMyCommon + 2, 4 );
1057         if ( other.IsComplex() )
1058           for ( TChildIterator children = other.GetChildren(); children.more(); ) {
1059             myChildren.push_back( children.next() );
1060             myChildren.back().SetBottomSide( myChildren.back().GetSide( otherBottomIndex ));
1061           }
1062         else {
1063           myChildren.push_back( other );
1064           myChildren.back().SetBottomSide( myChildren.back().GetSide( otherBottomIndex ));
1065         }
1066
1067         myLeftBottomChild = 0;
1068
1069         // collect vertices in mySides
1070         if ( other.IsComplex() )
1071           for ( TChildIterator children = other.GetChildren(); children.more(); )
1072           {
1073             const _QuadFaceGrid& child = children.next();
1074             for ( int i = 0; i < 4; ++i )
1075               mySides.AppendSide( child.GetSide(i) );
1076           }
1077         else
1078           for ( int i = 0; i < 4; ++i )
1079             mySides.AppendSide( other.GetSide(i) );
1080
1081         return true;
1082       }
1083     }
1084   }
1085   return false;
1086 }
1087
1088 //================================================================================
1089 /*!
1090  * \brief Try to set the side as bottom hirizontal side
1091  */
1092 //================================================================================
1093
1094 bool _QuadFaceGrid::SetBottomSide(const _FaceSide& bottom, int* sideIndex)
1095 {
1096   myLeftBottomChild = myRightBrother = myUpBrother = 0;
1097
1098   int myBottomIndex;
1099   if ( myChildren.empty() )
1100   {
1101     if ( mySides.Contain( bottom, &myBottomIndex )) {
1102       mySides.SetBottomSide( myBottomIndex );
1103       if ( sideIndex )
1104         *sideIndex = myBottomIndex;
1105       return true;
1106     }
1107   }
1108   else
1109   {
1110     TChildren::iterator childFace = myChildren.begin(), childEnd = myChildren.end();
1111     for ( ; childFace != childEnd; ++childFace )
1112     {
1113       if ( childFace->SetBottomSide( bottom, &myBottomIndex ))
1114       {
1115         TChildren::iterator orientedChild = childFace;
1116         for ( childFace = myChildren.begin(); childFace != childEnd; ++childFace ) {
1117           if ( childFace != orientedChild )
1118             childFace->SetBottomSide( childFace->GetSide( myBottomIndex ));
1119         }
1120         if ( sideIndex )
1121           *sideIndex = myBottomIndex;
1122         return true;
1123       }
1124     }
1125   }
1126   return false;
1127 }
1128
1129 //================================================================================
1130 /*!
1131  * \brief Return face adjacent to i-th side of this face, (0<i<4)
1132  */
1133 //================================================================================
1134
1135 _QuadFaceGrid* _QuadFaceGrid::FindAdjacentForSide(int                  i,
1136                                                   list<_QuadFaceGrid>& faces,
1137                                                   EBoxSides            id) const
1138 {
1139   const _FaceSide & iSide = GetSide( i );
1140   list< _QuadFaceGrid >::iterator boxFace = faces.begin();
1141   for ( ; boxFace != faces.end(); ++boxFace )
1142   {
1143     _QuadFaceGrid* f  = & (*boxFace);
1144     if ( f != this && f->SetBottomSide( iSide ))
1145       return f->SetID( id ), f;
1146   }
1147   return (_QuadFaceGrid*) 0;
1148 }
1149
1150 //================================================================================
1151 /*!
1152  * \brief Return i-th side
1153  */
1154 //================================================================================
1155
1156 const _FaceSide& _QuadFaceGrid::GetSide(int i) const
1157 {
1158   if ( myChildren.empty() )
1159     return *mySides.GetSide(i);
1160
1161   _QuadFaceGrid* me = const_cast<_QuadFaceGrid*>(this);
1162   if ( !me->locateChildren() || !myLeftBottomChild )
1163     return *mySides.GetSide(i);
1164
1165   const _QuadFaceGrid* child = myLeftBottomChild;
1166   switch ( i ){
1167   case Q_BOTTOM:
1168   case Q_LEFT:
1169     break;
1170   case Q_RIGHT:
1171     while ( child->myRightBrother )
1172       child = child->myRightBrother;
1173     break;
1174   case Q_TOP:
1175     while ( child->myUpBrother )
1176       child = child->myUpBrother;
1177     break;
1178   default: ;
1179   }
1180   return child->GetSide( i );
1181 }
1182
1183 //================================================================================
1184 /*!
1185  * \brief Reverse edges in order to have them oriented along axes of the unit box
1186  */
1187 //================================================================================
1188
1189 void _QuadFaceGrid::ReverseEdges()
1190 {
1191   myReverse = !myReverse;
1192
1193 // #ifdef DEB_FACES
1194 //   if ( !myFace.IsNull() )
1195 //     TopAbs::Print(myFace.Orientation(), cout);
1196 // #endif
1197
1198   if ( myChildren.empty() )
1199   {
1200     DumpVertices();
1201   }
1202   else
1203   {
1204     DumpVertices();
1205     TChildren::iterator child = myChildren.begin(), childEnd = myChildren.end();
1206     for ( ; child != childEnd; ++child )
1207       child->ReverseEdges();
1208   }
1209 }
1210
1211 //================================================================================
1212 /*!
1213  * \brief Load nodes of a mesh
1214  */
1215 //================================================================================
1216
1217 bool _QuadFaceGrid::LoadGrid( SMESH_ProxyMesh& mesh )
1218 {
1219   if ( !myChildren.empty() )
1220   {
1221     // Let child faces load their grids
1222     TChildren::iterator child = myChildren.begin(), childEnd = myChildren.end();
1223     for ( ; child != childEnd; ++child ) {
1224       child->SetID( myID );
1225       if ( !child->LoadGrid( mesh ) )
1226         return error( child->GetError() );
1227     }
1228     // Fill myGrid with nodes of patches
1229     return loadCompositeGrid( mesh );
1230   }
1231
1232   // ---------------------------------------
1233   // Fill myGrid with nodes bound to myFace
1234   // ---------------------------------------
1235
1236   if ( !myGrid.empty() )
1237     return true;
1238
1239   const SMESHDS_SubMesh* faceSubMesh = mesh.GetSubMesh( myFace );
1240
1241   // check that all faces are quadrangular
1242   SMDS_ElemIteratorPtr fIt = faceSubMesh->GetElements();
1243   while ( fIt->more() )
1244     if ( fIt->next()->NbNodes() % 4 > 0 )
1245       return error("Non-quadrangular mesh faces are not allowed on sides of a composite block");
1246
1247   bool isProxy, isTmpElem;
1248   if ( faceSubMesh && faceSubMesh->NbElements() > 0 )
1249   {
1250     isProxy   = dynamic_cast< const SMESH_ProxyMesh::SubMesh* >( faceSubMesh );
1251     isTmpElem = mesh.IsTemporary( faceSubMesh->GetElements()->next() );
1252   }
1253   const SMESHDS_SubMesh* smToCheckEdges = ( isProxy && !isTmpElem ) ? faceSubMesh : 0;
1254
1255   myIndexer._xSize = 1 + mySides.GetSide( Q_BOTTOM )->GetNbSegments( mesh, smToCheckEdges );
1256   myIndexer._ySize = 1 + mySides.GetSide( Q_LEFT   )->GetNbSegments( mesh, smToCheckEdges );
1257
1258   myGrid.resize( myIndexer.size() );
1259
1260   // store nodes bound to the bottom edge
1261   mySides.GetSide( Q_BOTTOM )->StoreNodes( mesh, myGrid, myReverse, isProxy, smToCheckEdges );
1262
1263   // store the rest nodes row by row
1264
1265   TIDSortedElemSet avoidSet;
1266   const SMDS_MeshElement* firstQuad = 0; // most left face above the last row of found nodes
1267
1268   size_t nbFoundNodes = myIndexer._xSize;
1269   while ( nbFoundNodes != myGrid.size() )
1270   {
1271     // first and last nodes of the last filled row of nodes
1272     const SMDS_MeshNode* n1down = myGrid[ nbFoundNodes - myIndexer._xSize ];
1273     const SMDS_MeshNode* n2down = myGrid[ nbFoundNodes - myIndexer._xSize + 1];
1274     const SMDS_MeshNode* n1downLast = myGrid[ nbFoundNodes-1 ];
1275
1276     // find the first face above the row by the first two left nodes
1277     //
1278     // n1up     n2up
1279     //     o---o
1280     //     |   |
1281     //     o---o  o  o  o  o
1282     //n1down    n2down
1283     //
1284     firstQuad = FindFaceByNodes( n1down, n2down, avoidSet, mesh );
1285     while ( firstQuad && !faceSubMesh->Contains( firstQuad )) {
1286       avoidSet.insert( firstQuad );
1287       firstQuad = FindFaceByNodes( n1down, n2down, avoidSet, mesh);
1288     }
1289     if ( !firstQuad || !faceSubMesh->Contains( firstQuad ))
1290       return error(ERR_LI("Error in _QuadFaceGrid::LoadGrid()"));
1291
1292     // find the node of quad bound to the left geom edge
1293     int i2down = firstQuad->GetNodeIndex( n2down );
1294     const SMDS_MeshNode* n1up = firstQuad->GetNode(( i2down+2 ) % 4 );
1295     myGrid[ nbFoundNodes++ ] = n1up;
1296     // the 4-the node of the first quad
1297     int i1down = firstQuad->GetNodeIndex( n1down );
1298     const SMDS_MeshNode* n2up = firstQuad->GetNode(( i1down+2 ) % 4 );
1299     myGrid[ nbFoundNodes++ ] = n2up;
1300
1301     n1down = n2down;
1302     n1up   = n2up;
1303     const SMDS_MeshElement* quad = firstQuad;
1304
1305     // find the rest nodes by remaining faces above the row
1306     //
1307     //             n1up
1308     //     o---o--o
1309     //     |   |  | ->
1310     //     o---o--o  o  o  o
1311     //                      n1downLast
1312     //
1313     while ( n1down != n1downLast )
1314     {
1315       // next face
1316       avoidSet.clear(); avoidSet.insert( quad );
1317       quad = FindFaceByNodes( n1down, n1up, avoidSet, mesh );
1318       if ( !quad || quad->NbNodes() % 4 > 0)
1319         return error(ERR_LI("Error in _QuadFaceGrid::LoadGrid()"));
1320
1321       // next node
1322       if ( quad->GetNode( i1down ) != n1down ) // check already found index
1323         i1down = quad->GetNodeIndex( n1down );
1324       n2up = quad->GetNode(( i1down+2 ) % 4 );
1325       myGrid[ nbFoundNodes++ ] = n2up;
1326
1327       n1down = myGrid[ nbFoundNodes - myIndexer._xSize - 1 ];
1328       n1up   = n2up;
1329     }
1330     avoidSet.clear(); avoidSet.insert( firstQuad );
1331   }
1332   DumpGrid(); // debug
1333
1334   return true;
1335 }
1336
1337 //================================================================================
1338 /*!
1339  * \brief Fill myIJK with normalized parameters of nodes in myGrid
1340  *  \param [in] i1 - coordinate index along rows of myGrid
1341  *  \param [in] i2 - coordinate index along columns of myGrid
1342  *  \param [in] v3 - value of the constant parameter
1343  */
1344 //================================================================================
1345
1346 void _QuadFaceGrid::ComputeIJK( int i1, int i2, double v3 )
1347 {
1348   gp_XYZ ijk( v3, v3, v3 );
1349   myIJK.resize( myIndexer.size(), ijk );
1350
1351   const size_t nbCol = myIndexer._xSize;
1352   const size_t nbRow = myIndexer._ySize;
1353
1354   vector< double > len( nbRow );
1355   len[0] = 0;
1356   for ( size_t i = 0; i < nbCol; ++i )
1357   {
1358     gp_Pnt pPrev = GetXYZ( i, 0 );
1359     for ( size_t j = 1; j < nbRow; ++j )
1360     {
1361       gp_Pnt p = GetXYZ( i, j );
1362       len[ j ] = len[ j-1 ] + p.Distance( pPrev );
1363       pPrev = p;
1364     }
1365     for ( size_t j = 0; j < nbRow; ++j )
1366       GetIJK( i, j ).SetCoord( i2, len[ j ]/len.back() );
1367   }
1368
1369   len.resize( nbCol );
1370   for ( size_t j = 0; j < nbRow; ++j )
1371   {
1372     gp_Pnt pPrev = GetXYZ( 0, j );
1373     for ( size_t i = 1; i < nbCol; ++i )
1374     {
1375       gp_Pnt p = GetXYZ( i, j );
1376       len[ i ] = len[ i-1 ] + p.Distance( pPrev );
1377       pPrev = p;
1378     }
1379     for ( size_t i = 0; i < nbCol; ++i )
1380       GetIJK( i, j ).SetCoord( i1, len[ i ]/len.back() );
1381   }
1382 }
1383
1384 //================================================================================
1385 /*!
1386  * \brief Find out mutual location of children: find their right and up brothers
1387  */
1388 //================================================================================
1389
1390 bool _QuadFaceGrid::locateChildren()
1391 {
1392   if ( myLeftBottomChild )
1393     return true;
1394
1395   TChildren::iterator child = myChildren.begin(), childEnd = myChildren.end();
1396
1397   // find a child sharing it's first bottom vertex with no other brother
1398   myLeftBottomChild = 0;
1399   for ( ; !myLeftBottomChild && child != childEnd; ++child )
1400   {
1401     TopoDS_Vertex leftVertex = child->GetSide( Q_BOTTOM ).FirstVertex();
1402     bool sharedVertex = false;
1403     TChildren::iterator otherChild = myChildren.begin();
1404     for ( ; otherChild != childEnd && !sharedVertex; ++otherChild )
1405       if ( otherChild != child )
1406         sharedVertex = otherChild->mySides.Contain( leftVertex );
1407     if ( !sharedVertex ) {
1408       myLeftBottomChild = & (*child);
1409       DUMP_VERT("0 left bottom Vertex: ",leftVertex );
1410     }
1411   }
1412   if (!myLeftBottomChild)
1413     return error(ERR_LI("Error in locateChildren()"));
1414
1415   set< _QuadFaceGrid* > notLocatedChilren;
1416   for (child = myChildren.begin() ; child != childEnd; ++child )
1417     notLocatedChilren.insert( & (*child));
1418
1419   // connect myLeftBottomChild to it's right and upper brothers
1420   notLocatedChilren.erase( myLeftBottomChild );
1421   myLeftBottomChild->setBrothers( notLocatedChilren );
1422   if ( !notLocatedChilren.empty() )
1423     return error(ERR_LI("Error in locateChildren()"));
1424
1425   return true;
1426 }
1427
1428 //================================================================================
1429 /*!
1430  * \brief Fill myGrid with nodes of patches
1431  */
1432 //================================================================================
1433
1434 bool _QuadFaceGrid::loadCompositeGrid(SMESH_ProxyMesh& mesh)
1435 {
1436   // Find out mutual location of children: find their right and up brothers
1437   if ( !locateChildren() )
1438     return false;
1439
1440   // Load nodes according to mutual location of children
1441
1442   // grid size
1443   myIndexer._xSize = 1 + myLeftBottomChild->GetNbHoriSegments( mesh, /*withBrothers=*/true );
1444   myIndexer._ySize = 1 + myLeftBottomChild->GetNbVertSegments( mesh, /*withBrothers=*/true );
1445
1446   myGrid.resize( myIndexer.size() );
1447
1448   int fromX = myReverse ? myIndexer._xSize : 0;
1449   if ( !myLeftBottomChild->fillGrid( mesh, myGrid, myIndexer, fromX, 0 ))
1450     return error( myLeftBottomChild->GetError() );
1451
1452   DumpGrid();
1453
1454   return true;
1455 }
1456
1457 //================================================================================
1458 /*!
1459  * \brief Find right an upper brothers among notLocatedBrothers
1460  */
1461 //================================================================================
1462
1463 void _QuadFaceGrid::setBrothers( set< _QuadFaceGrid* >& notLocatedBrothers )
1464 {
1465   if ( !notLocatedBrothers.empty() )
1466   {
1467     // find right brother
1468     TopoDS_Vertex rightVertex = GetSide( Q_BOTTOM ).LastVertex();
1469     DUMP_VERT("1 right bottom Vertex: ",rightVertex );
1470     set< _QuadFaceGrid* >::iterator brIt, brEnd = notLocatedBrothers.end();
1471     for ( brIt = notLocatedBrothers.begin(); brIt != brEnd; ++brIt )
1472     {
1473       _QuadFaceGrid* brother = *brIt;
1474       TopoDS_Vertex brotherLeftVertex = brother->GetSide( Q_BOTTOM ).FirstVertex();
1475       DUMP_VERT( "brother left bottom: ", brotherLeftVertex );
1476       if ( rightVertex.IsSame( brotherLeftVertex )) {
1477         myRightBrother = brother;
1478         notLocatedBrothers.erase( brIt );
1479         break;
1480       }
1481     }
1482     // find upper brother
1483     TopoDS_Vertex upVertex = GetSide( Q_LEFT ).FirstVertex();
1484     DUMP_VERT("1 left up Vertex: ",upVertex);
1485     brIt = notLocatedBrothers.begin(), brEnd = notLocatedBrothers.end();
1486     for ( ; brIt != brEnd; ++brIt )
1487     {
1488       _QuadFaceGrid* brother = *brIt;
1489       TopoDS_Vertex brotherLeftVertex = brother->GetSide( Q_BOTTOM ).FirstVertex();
1490       DUMP_VERT("brother left bottom: ", brotherLeftVertex);
1491       if ( upVertex.IsSame( brotherLeftVertex )) {
1492         myUpBrother = brother;
1493         notLocatedBrothers.erase( myUpBrother );
1494         break;
1495       }
1496     }
1497     // recursive call
1498     if ( myRightBrother )
1499       myRightBrother->setBrothers( notLocatedBrothers );
1500     if ( myUpBrother )
1501       myUpBrother->setBrothers( notLocatedBrothers );
1502   }
1503 }
1504
1505 //================================================================================
1506 /*!
1507  * \brief Store nodes of a simple face into grid starting from (x,y) position
1508  */
1509 //================================================================================
1510
1511 bool _QuadFaceGrid::fillGrid(SMESH_ProxyMesh&               theMesh,
1512                              vector<const SMDS_MeshNode*> & theGrid,
1513                              const _Indexer&                theIndexer,
1514                              int                            theX,
1515                              int                            theY)
1516 {
1517   if ( myGrid.empty() && !LoadGrid( theMesh ))
1518     return false;
1519
1520   // store my own grid in the global grid
1521
1522   int fromX = myReverse ? theX - myIndexer._xSize: theX;
1523
1524   for ( int i = 0, x = fromX; i < myIndexer._xSize; ++i, ++x )
1525     for ( int j = 0, y = theY; j < myIndexer._ySize; ++j, ++y )
1526       theGrid[ theIndexer( x, y )] = myGrid[ myIndexer( i, j )];
1527
1528   // store grids of my right and upper brothers
1529
1530   if ( myRightBrother )
1531   {
1532     if ( myReverse )
1533       fromX += 1;
1534     else
1535       fromX += myIndexer._xSize - 1;
1536     if ( !myRightBrother->fillGrid( theMesh, theGrid, theIndexer, fromX, theY ))
1537       return error( myRightBrother->GetError() );
1538   }
1539   if ( myUpBrother )
1540   {
1541     if ( !myUpBrother->fillGrid( theMesh, theGrid, theIndexer,
1542                                  theX, theY + myIndexer._ySize - 1))
1543       return error( myUpBrother->GetError() );
1544   }
1545   return true;
1546 }
1547
1548 //================================================================================
1549 /*!
1550  * \brief Return number of segments on the hirizontal sides
1551  */
1552 //================================================================================
1553
1554 int _QuadFaceGrid::GetNbHoriSegments(SMESH_ProxyMesh& mesh, bool withBrothers) const
1555 {
1556   int nbSegs = 0;
1557   if ( myLeftBottomChild )
1558   {
1559     nbSegs += myLeftBottomChild->GetNbHoriSegments( mesh, true );
1560   }
1561   else
1562   {
1563     nbSegs = mySides.GetSide( Q_BOTTOM )->GetNbSegments( mesh );
1564     if ( withBrothers && myRightBrother )
1565       nbSegs += myRightBrother->GetNbHoriSegments( mesh, withBrothers );
1566   }
1567   return nbSegs;
1568 }
1569
1570 //================================================================================
1571 /*!
1572  * \brief Return number of segments on the vertical sides
1573  */
1574 //================================================================================
1575
1576 int _QuadFaceGrid::GetNbVertSegments(SMESH_ProxyMesh& mesh, bool withBrothers) const
1577 {
1578   int nbSegs = 0;
1579   if ( myLeftBottomChild )
1580   {
1581     nbSegs += myLeftBottomChild->GetNbVertSegments( mesh, true );
1582   }
1583   else
1584   {
1585     nbSegs = mySides.GetSide( Q_LEFT )->GetNbSegments(mesh,0);
1586     if ( withBrothers && myUpBrother )
1587       nbSegs += myUpBrother->GetNbVertSegments( mesh, withBrothers );
1588   }
1589   return nbSegs;
1590 }
1591
1592 //================================================================================
1593 /*!
1594  * \brief Return edge on the hirizontal bottom sides
1595  */
1596 //================================================================================
1597
1598 int _QuadFaceGrid::GetHoriEdges(vector<TopoDS_Edge> & edges) const
1599 {
1600   if ( myLeftBottomChild )
1601   {
1602     return myLeftBottomChild->GetHoriEdges( edges );
1603   }
1604   else
1605   {
1606     const _FaceSide* bottom  = mySides.GetSide( Q_BOTTOM );
1607     int i = 0;
1608     while ( true ) {
1609       TopoDS_Edge e = bottom->Edge( i++ );
1610       if ( e.IsNull() )
1611         break;
1612       else
1613         edges.push_back( e );
1614     }
1615     if ( myRightBrother )
1616       myRightBrother->GetHoriEdges( edges );
1617   }
1618   return edges.size();
1619 }
1620
1621 //================================================================================
1622 /*!
1623  * \brief Return a node by its position
1624  */
1625 //================================================================================
1626
1627 const SMDS_MeshNode* _QuadFaceGrid::GetNode(int iHori, int iVert) const
1628 {
1629   return myGrid[ myIndexer( iHori, iVert )];
1630 }
1631
1632 //================================================================================
1633 /*!
1634  * \brief Return node coordinates by its position
1635  */
1636 //================================================================================
1637
1638 gp_XYZ _QuadFaceGrid::GetXYZ(int iHori, int iVert) const
1639 {
1640   SMESH_TNodeXYZ xyz = myGrid[ myIndexer( iHori, iVert )];
1641   return xyz;
1642 }
1643
1644 //================================================================================
1645 /*!
1646  * \brief Return normal to the face at vertex v
1647  */
1648 //================================================================================
1649
1650 bool _QuadFaceGrid::GetNormal( const TopoDS_Vertex& v, gp_Vec& n ) const
1651 {
1652   if ( myChildren.empty() )
1653   {
1654     if ( mySides.Contain( v )) {
1655       try {
1656         gp_Pnt2d uv = BRep_Tool::Parameters( v, myFace );
1657         BRepAdaptor_Surface surface( myFace );
1658         gp_Pnt p; gp_Vec d1u, d1v;
1659         surface.D1( uv.X(), uv.Y(), p, d1u, d1v );
1660         n = d1u.Crossed( d1v );
1661         return true;
1662       }
1663       catch (Standard_Failure) {
1664         return false;
1665       }
1666     }
1667   }
1668   else
1669   {
1670     TChildren::const_iterator child = myChildren.begin(), childEnd = myChildren.end();
1671     for ( ; child != childEnd; ++child )
1672       if ( child->GetNormal( v, n ))
1673         return true;
1674   }
1675   return false;
1676 }
1677
1678 //================================================================================
1679 /*!
1680  * \brief Dumps coordinates of grid nodes
1681  */
1682 //================================================================================
1683
1684 void _QuadFaceGrid::DumpGrid() const
1685 {
1686 #ifdef DEB_GRID
1687   const char* names[] = { "B_BOTTOM", "B_RIGHT", "B_TOP", "B_LEFT", "B_FRONT", "B_BACK" };
1688   cout << "****** Face " << names[ myID ] << endl;
1689
1690   if ( myChildren.empty() || !myGrid.empty() )
1691   {
1692     cout << "x size: " << myIndexer._xSize << "; y size: " << myIndexer._ySize << endl;
1693     for ( int y = 0; y < myIndexer._ySize; ++y ) {
1694       cout << "-- row " << y << endl;
1695       for ( int x = 0; x < myIndexer._xSize; ++x ) {
1696         const SMDS_MeshNode* n = myGrid[ myIndexer( x, y ) ];
1697         cout << x << " ( " << n->X() << ", " << n->Y() << ", " << n->Z() << " )" << endl;
1698       }
1699     }
1700   }
1701   else
1702   {
1703     cout << "Nb children: " << myChildren.size() << endl;
1704     TChildren::const_iterator child = myChildren.begin(), childEnd = myChildren.end();
1705     for ( int i=0; child != childEnd; ++child, ++i ) {
1706       cout << "   *** SUBFACE " << i+1 << endl;
1707       ((_QuadFaceGrid&)(*child)).SetID( myID );
1708       child->DumpGrid();
1709     }
1710   }
1711 #endif
1712 }
1713
1714 //================================================================================
1715 /*!
1716  * \brief Dump vertices
1717  */
1718 //================================================================================
1719
1720 void _QuadFaceGrid::DumpVertices() const
1721 {
1722 #ifdef DEB_FACES
1723   cout << "****** Face ";
1724   const char* names[] = { "B_BOTTOM", "B_RIGHT", "B_TOP", "B_LEFT", "B_FRONT", "B_BACK" };
1725   if ( myID >= B_BOTTOM && myID < B_BACK )
1726     cout << names[ myID ] << endl;
1727   else
1728     cout << "UNDEFINED" << endl;
1729
1730   if ( myChildren.empty() )
1731   {
1732     for ( int i = 0; i < 4; ++i )
1733     {
1734       cout << "  Side "; mySides.GetSide( i )->Dump();
1735     }
1736   }
1737   else
1738   {
1739     cout << "-- Nb children: " << myChildren.size() << endl;
1740     TChildren::const_iterator child = myChildren.begin(), childEnd = myChildren.end();
1741     for ( int i=0; child != childEnd; ++child, ++i ) {
1742       cout << "   *** SUBFACE " << i+1 << endl;
1743       ((_QuadFaceGrid&)(*child)).SetID( myID );
1744       child->DumpVertices();
1745     }
1746   }
1747 #endif
1748 }
1749
1750 //=======================================================================
1751 //function : _FaceSide
1752 //purpose  : copy constructor
1753 //=======================================================================
1754
1755 _FaceSide::_FaceSide(const _FaceSide& other)
1756 {
1757   myEdge = other.myEdge;
1758   myChildren = other.myChildren;
1759   myNbChildren = other.myNbChildren;
1760   myVertices.Assign( other.myVertices );
1761   myID = other.myID;
1762 }
1763
1764 //================================================================================
1765 /*!
1766  * \brief Construct a face side of one edge
1767  */
1768 //================================================================================
1769
1770 _FaceSide::_FaceSide(const TopoDS_Edge& edge):
1771   myEdge( edge ), myNbChildren(0)
1772 {
1773   if ( !edge.IsNull() )
1774     for ( TopExp_Explorer exp( edge, TopAbs_VERTEX ); exp.More(); exp.Next() )
1775       //myVertices.insert( ptr ( exp.Current() ));
1776       myVertices.Add( exp.Current() );
1777 }
1778
1779 //================================================================================
1780 /*!
1781  * \brief Construct a face side of several edges
1782  */
1783 //================================================================================
1784
1785 _FaceSide::_FaceSide(const list<TopoDS_Edge>& edges):
1786   myNbChildren(0)
1787 {
1788   list<TopoDS_Edge>::const_iterator edge = edges.begin(), eEnd = edges.end();
1789   for ( ; edge != eEnd; ++edge ) {
1790     myChildren.push_back( _FaceSide( *edge ));
1791     myNbChildren++;
1792     myVertices.Add( myChildren.back().FirstVertex() );
1793     myVertices.Add( myChildren.back().LastVertex() );
1794     myChildren.back().SetID( Q_CHILD ); // not to splice them
1795   }
1796 }
1797
1798 //=======================================================================
1799 //function : GetSide
1800 //purpose  :
1801 //=======================================================================
1802
1803 _FaceSide* _FaceSide::GetSide(const int i)
1804 {
1805   if ( i >= myNbChildren )
1806     return 0;
1807
1808   list< _FaceSide >::iterator side = myChildren.begin();
1809   if ( i )
1810     std::advance( side, i );
1811   return & (*side);
1812 }
1813
1814 //=======================================================================
1815 //function : GetSide
1816 //purpose  : 
1817 //=======================================================================
1818
1819 const _FaceSide* _FaceSide::GetSide(const int i) const
1820 {
1821   return const_cast< _FaceSide* >(this)->GetSide(i);
1822 }
1823
1824 //=======================================================================
1825 //function : NbVertices
1826 //purpose  : return nb of vertices in the side
1827 //=======================================================================
1828
1829 int _FaceSide::NbVertices() const
1830 {
1831   if ( myChildren.empty() )
1832     return myVertices.Extent();
1833
1834   return myNbChildren + 1;
1835 }
1836
1837 //=======================================================================
1838 //function : NbCommonVertices
1839 //purpose  : Returns number of my vertices common with the given ones
1840 //=======================================================================
1841
1842 int _FaceSide::NbCommonVertices( const TopTools_MapOfShape& VV ) const
1843 {
1844   int nbCommon = 0;
1845   TopTools_MapIteratorOfMapOfShape vIt ( myVertices );
1846   for ( ; vIt.More(); vIt.Next() )
1847     nbCommon += ( VV.Contains( vIt.Key() ));
1848
1849   return nbCommon;
1850 }
1851
1852 //=======================================================================
1853 //function : FirstVertex
1854 //purpose  :
1855 //=======================================================================
1856
1857 TopoDS_Vertex _FaceSide::FirstVertex() const
1858 {
1859   if ( myChildren.empty() )
1860     return TopExp::FirstVertex( myEdge, Standard_True );
1861
1862   return myChildren.front().FirstVertex();
1863 }
1864
1865 //=======================================================================
1866 //function : LastVertex
1867 //purpose  : 
1868 //=======================================================================
1869
1870 TopoDS_Vertex _FaceSide::LastVertex() const
1871 {
1872   if ( myChildren.empty() )
1873     return TopExp::LastVertex( myEdge, Standard_True );
1874
1875   return myChildren.back().LastVertex();
1876 }
1877
1878 //=======================================================================
1879 //function : Vertex
1880 //purpose  : 
1881 //=======================================================================
1882
1883 TopoDS_Vertex _FaceSide::Vertex(int i) const
1884 {
1885   if ( myChildren.empty() )
1886     return i ? LastVertex() : FirstVertex();
1887       
1888   if ( i >= myNbChildren )
1889     return myChildren.back().LastVertex();
1890   
1891   return GetSide(i)->FirstVertex();
1892 }
1893
1894 //================================================================================
1895 /*!
1896  * \brief Return i-the zero-based edge of the side
1897  */
1898 //================================================================================
1899
1900 TopoDS_Edge _FaceSide::Edge(int i) const
1901 {
1902   if ( i == 0 && !myEdge.IsNull() )
1903     return myEdge;
1904
1905   if ( const _FaceSide* iSide = GetSide( i ))
1906     return iSide->myEdge;
1907
1908   return TopoDS_Edge();
1909 }
1910
1911 //=======================================================================
1912 //function : Contain
1913 //purpose  : 
1914 //=======================================================================
1915
1916 bool _FaceSide::Contain( const _FaceSide& side, int* which ) const
1917 {
1918   if ( !which || myChildren.empty() )
1919   {
1920     if ( which )
1921       *which = 0;
1922     int nbCommon = 0;
1923     TopTools_MapIteratorOfMapOfShape vIt ( side.myVertices );
1924     for ( ; vIt.More(); vIt.Next() )
1925       nbCommon += ( myVertices.Contains( vIt.Key() ));
1926     return (nbCommon > 1);
1927   }
1928   list< _FaceSide >::const_iterator mySide = myChildren.begin(), sideEnd = myChildren.end();
1929   for ( int i = 0; mySide != sideEnd; ++mySide, ++i ) {
1930     if ( mySide->Contain( side )) {
1931       *which = i;
1932       return true;
1933     }
1934   }
1935   return false;
1936 }
1937
1938 //=======================================================================
1939 //function : Contain
1940 //purpose  : 
1941 //=======================================================================
1942
1943 bool _FaceSide::Contain( const TopoDS_Vertex& vertex ) const
1944 {
1945   return myVertices.Contains( vertex );
1946 }
1947
1948 //=======================================================================
1949 //function : AppendSide
1950 //purpose  : 
1951 //=======================================================================
1952
1953 void _FaceSide::AppendSide( const _FaceSide& side )
1954 {
1955   if ( !myEdge.IsNull() )
1956   {
1957     myChildren.push_back( *this );
1958     myNbChildren = 1;
1959     myEdge.Nullify();
1960   }
1961   myChildren.push_back( side );
1962   myNbChildren++;
1963   TopTools_MapIteratorOfMapOfShape vIt ( side.myVertices );
1964   for ( ; vIt.More(); vIt.Next() )
1965     myVertices.Add( vIt.Key() );
1966
1967   myID = Q_PARENT;
1968   myChildren.back().SetID( EQuadSides( myNbChildren-1 ));
1969 }
1970
1971 //=======================================================================
1972 //function : SetBottomSide
1973 //purpose  : 
1974 //=======================================================================
1975
1976 void _FaceSide::SetBottomSide( int i )
1977 {
1978   if ( i > 0 && myID == Q_PARENT ) {
1979     list< _FaceSide >::iterator sideEnd, side = myChildren.begin();
1980     std::advance( side, i );
1981     myChildren.splice( myChildren.begin(), myChildren, side, myChildren.end() );
1982
1983     side = myChildren.begin(), sideEnd = myChildren.end();
1984     for ( int i = 0; side != sideEnd; ++side, ++i ) {
1985       side->SetID( EQuadSides(i) );
1986       side->SetBottomSide(i);
1987     }
1988   }
1989 }
1990
1991 //=======================================================================
1992 //function : GetNbSegments
1993 //purpose  : 
1994 //=======================================================================
1995
1996 int _FaceSide::GetNbSegments(SMESH_ProxyMesh& mesh, const SMESHDS_SubMesh* smToCheckEdges) const
1997 {
1998   int nb = 0;
1999   if ( myChildren.empty() )
2000   {
2001     nb = mesh.GetSubMesh(myEdge)->NbElements();
2002
2003     if ( smToCheckEdges )
2004     {
2005       // check that segments bound faces belonging to smToCheckEdges
2006       SMDS_ElemIteratorPtr segIt = mesh.GetSubMesh(myEdge)->GetElements();
2007       while ( segIt->more() )
2008       {
2009         const SMDS_MeshElement* seg = segIt->next();
2010         if ( !IsSegmentOnSubMeshBoundary( mesh.GetProxyNode( seg->GetNode(0) ),
2011                                           mesh.GetProxyNode( seg->GetNode(1) ),
2012                                           smToCheckEdges, mesh ))
2013           --nb;
2014       }
2015     }
2016   }
2017   else
2018   {
2019     list< _FaceSide >::const_iterator side = myChildren.begin(), sideEnd = myChildren.end();
2020     for ( ; side != sideEnd; ++side )
2021       nb += side->GetNbSegments( mesh, smToCheckEdges );
2022   }
2023   return nb;
2024 }
2025
2026 //=======================================================================
2027 //function : StoreNodes
2028 //purpose  :
2029 //=======================================================================
2030
2031 bool _FaceSide::StoreNodes(SMESH_ProxyMesh&              mesh,
2032                            vector<const SMDS_MeshNode*>& myGrid,
2033                            bool                          reverse,
2034                            bool                          isProxy,
2035                            const SMESHDS_SubMesh*        smToCheckEdges)
2036 {
2037   list< TopoDS_Edge > edges;
2038   if ( myChildren.empty() )
2039   {
2040     edges.push_back( myEdge );
2041   }
2042   else
2043   {
2044     list< _FaceSide >::const_iterator side = myChildren.begin(), sideEnd = myChildren.end();
2045     for ( ; side != sideEnd; ++side )
2046       if ( reverse )
2047         edges.push_front( side->myEdge );
2048       else
2049         edges.push_back ( side->myEdge );
2050   }
2051   int nbNodes = 0;
2052   list< TopoDS_Edge >::iterator edge = edges.begin(), eEnd = edges.end();
2053   for ( ; edge != eEnd; ++edge )
2054   {
2055     typedef map< double, const SMDS_MeshNode* > TParamNodeMap;
2056     TParamNodeMap nodes;
2057     bool ok = SMESH_Algo::GetSortedNodesOnEdge( mesh.GetMeshDS(),
2058                                                 *edge,
2059                                                 /*ignoreMediumNodes=*/true,
2060                                                 nodes);
2061     if ( !ok ) return false;
2062
2063     // skip nodes on VERTEXes not included in faces
2064     if ( !nodes.begin()->second->GetInverseElementIterator(SMDSAbs_Face)->more() )
2065       nodes.erase( nodes.begin() );
2066     if ( !nodes.empty() &&
2067          !nodes.rbegin()->second->GetInverseElementIterator(SMDSAbs_Face)->more() )
2068       nodes.erase( --nodes.end() );
2069
2070     if ( isProxy )
2071     {
2072       TParamNodeMap::iterator u_node, nEnd = nodes.end();
2073       for ( u_node = nodes.begin(); u_node != nEnd; ++u_node )
2074         u_node->second = mesh.GetProxyNode( u_node->second );
2075     }
2076
2077     if ( smToCheckEdges ) // erase nodes of segments not bounding faces of smToCheckEdges
2078     {
2079       {
2080         TParamNodeMap::iterator u_node1, u_node2 = nodes.begin(), nEnd = nodes.end();
2081         for ( u_node1 = u_node2++; u_node2 != nEnd; u_node1 = u_node2++ )
2082           if ( IsSegmentOnSubMeshBoundary( u_node1->second, u_node2->second,
2083                                            smToCheckEdges, mesh ))
2084             break;
2085           else
2086             nodes.erase( u_node1 );
2087       }
2088       {
2089         TParamNodeMap::reverse_iterator u_node1, u_node2 = nodes.rbegin(), nEnd = nodes.rend();
2090         for ( u_node1 = u_node2++; u_node2 != nEnd; u_node1 = u_node2++ )
2091           if ( IsSegmentOnSubMeshBoundary( u_node1->second, u_node2->second,
2092                                            smToCheckEdges, mesh ))
2093             break;
2094           else
2095             nodes.erase( --( u_node1.base() ));
2096       }
2097     }
2098
2099     bool forward = ( edge->Orientation() == TopAbs_FORWARD );
2100     if ( reverse ) forward = !forward;
2101     if ( forward )
2102     {
2103       TParamNodeMap::iterator u_node, nEnd = nodes.end();
2104       for ( u_node = nodes.begin(); u_node != nEnd; ++u_node )
2105         myGrid[ nbNodes++ ] = u_node->second;
2106     }
2107     else
2108     {
2109       TParamNodeMap::reverse_iterator u_node, nEnd = nodes.rend();
2110       for ( u_node = nodes.rbegin(); u_node != nEnd; ++u_node )
2111         myGrid[ nbNodes++ ] = u_node->second;
2112     }
2113     nbNodes--; // node on vertex present in two adjacent edges
2114   }
2115   return nbNodes > 0;
2116 }
2117
2118 //=======================================================================
2119 //function : Dump
2120 //purpose  : dump end vertices
2121 //=======================================================================
2122
2123 void _FaceSide::Dump() const
2124 {
2125   if ( myChildren.empty() )
2126   {
2127     const char* sideNames[] = { "Q_BOTTOM", "Q_RIGHT", "Q_TOP", "Q_LEFT", "Q_CHILD", "Q_PARENT" };
2128     if ( myID >= Q_BOTTOM && myID < Q_PARENT )
2129       cout << sideNames[ myID ] << endl;
2130     else
2131       cout << "<UNDEFINED ID>" << endl;
2132     TopoDS_Vertex f = FirstVertex();
2133     TopoDS_Vertex l = LastVertex();
2134     gp_Pnt pf = BRep_Tool::Pnt(f);
2135     gp_Pnt pl = BRep_Tool::Pnt(l);
2136     cout << "\t ( "<< ptr( f ) << " - " << ptr( l )<< " )"
2137          << "\t ( "<< pf.X()<<", "<<pf.Y()<<", "<<pf.Z()<<" ) - "
2138          << " ( "<< pl.X()<<", "<<pl.Y()<<", "<<pl.Z()<<" )"<<endl;
2139   }
2140   else
2141   {
2142     list< _FaceSide >::const_iterator side = myChildren.begin(), sideEnd = myChildren.end();
2143     for ( ; side != sideEnd; ++side ) {
2144       side->Dump();
2145       cout << "\t";
2146     }
2147   }
2148 }