Salome HOME
IPAL53401: BelongToGeom is very long on multiple lines
[modules/smesh.git] / src / StdMeshers / StdMeshers_Hexa_3D.cxx
1 // Copyright (C) 2007-2016  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
23 //  SMESH SMESH : implementaion of SMESH idl descriptions
24 //  File   : StdMeshers_Hexa_3D.cxx
25 //           Moved here from SMESH_Hexa_3D.cxx
26 //  Author : Paul RASCLE, EDF
27 //  Module : SMESH
28 //
29 #include "StdMeshers_Hexa_3D.hxx"
30
31 #include "StdMeshers_CompositeHexa_3D.hxx"
32 #include "StdMeshers_FaceSide.hxx"
33 #include "StdMeshers_HexaFromSkin_3D.hxx"
34 #include "StdMeshers_Penta_3D.hxx"
35 #include "StdMeshers_Prism_3D.hxx"
36 #include "StdMeshers_Quadrangle_2D.hxx"
37 #include "StdMeshers_ViscousLayers.hxx"
38
39 #include "SMESH_Comment.hxx"
40 #include "SMESH_Gen.hxx"
41 #include "SMESH_Mesh.hxx"
42 #include "SMESH_MesherHelper.hxx"
43 #include "SMESH_subMesh.hxx"
44
45 #include "SMDS_MeshNode.hxx"
46
47 #include <TopExp.hxx>
48 #include <TopExp_Explorer.hxx>
49 #include <TopTools_SequenceOfShape.hxx>
50 #include <TopTools_MapOfShape.hxx>
51 #include <TopoDS.hxx>
52
53 #include "utilities.h"
54 #include "Utils_ExceptHandlers.hxx"
55
56 typedef SMESH_Comment TComm;
57
58 using namespace std;
59
60 static SMESH_ComputeErrorPtr ComputePentahedralMesh(SMESH_Mesh &,
61                                                     const TopoDS_Shape &,
62                                                     SMESH_ProxyMesh* proxyMesh=0);
63
64 static bool EvaluatePentahedralMesh(SMESH_Mesh &, const TopoDS_Shape &,
65                                     MapShapeNbElems &);
66
67 //=============================================================================
68 /*!
69  * Constructor
70  */
71 //=============================================================================
72
73 StdMeshers_Hexa_3D::StdMeshers_Hexa_3D(int hypId, int studyId, SMESH_Gen * gen)
74   :SMESH_3D_Algo(hypId, studyId, gen)
75 {
76   MESSAGE("StdMeshers_Hexa_3D::StdMeshers_Hexa_3D");
77   _name = "Hexa_3D";
78   _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);       // 1 bit /shape type
79   _requireShape = false;
80   _compatibleHypothesis.push_back("ViscousLayers");
81 }
82
83 //=============================================================================
84 /*!
85  * Destructor
86  */
87 //=============================================================================
88
89 StdMeshers_Hexa_3D::~StdMeshers_Hexa_3D()
90 {
91   MESSAGE("StdMeshers_Hexa_3D::~StdMeshers_Hexa_3D");
92 }
93
94 //=============================================================================
95 /*!
96  * Retrieves defined hypotheses
97  */
98 //=============================================================================
99
100 bool StdMeshers_Hexa_3D::CheckHypothesis
101                          (SMESH_Mesh&                          aMesh,
102                           const TopoDS_Shape&                  aShape,
103                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
104 {
105   // check nb of faces in the shape
106 /*  PAL16229
107   aStatus = SMESH_Hypothesis::HYP_BAD_GEOMETRY;
108   int nbFaces = 0;
109   for (TopExp_Explorer exp(aShape, TopAbs_FACE); exp.More(); exp.Next())
110     if ( ++nbFaces > 6 )
111       break;
112   if ( nbFaces != 6 )
113     return false;
114 */
115
116   _viscousLayersHyp = NULL;
117
118   const list<const SMESHDS_Hypothesis*>& hyps =
119     GetUsedHypothesis(aMesh, aShape, /*ignoreAuxiliary=*/false);
120   list <const SMESHDS_Hypothesis* >::const_iterator h = hyps.begin();
121   if ( h == hyps.end())
122   {
123     aStatus = SMESH_Hypothesis::HYP_OK;
124     return true;
125   }
126
127   // only StdMeshers_ViscousLayers can be used
128   aStatus = HYP_OK;
129   for ( ; h != hyps.end(); ++h )
130   {
131     if ( !(_viscousLayersHyp = dynamic_cast< const StdMeshers_ViscousLayers*> ( *h )))
132       break;
133   }
134   if ( !_viscousLayersHyp )
135     aStatus = HYP_INCOMPATIBLE;
136   else
137     error( _viscousLayersHyp->CheckHypothesis( aMesh, aShape, aStatus ));
138
139   return aStatus == HYP_OK;
140 }
141
142 namespace
143 {
144   //=============================================================================
145
146   typedef boost::shared_ptr< FaceQuadStruct > FaceQuadStructPtr;
147   typedef std::vector<gp_XYZ>                 TXYZColumn;
148
149   // symbolic names of box sides
150   enum EBoxSides{ B_BOTTOM=0, B_RIGHT, B_TOP, B_LEFT, B_FRONT, B_BACK, B_NB_SIDES };
151
152   // symbolic names of sides of quadrangle
153   enum EQuadSides{ Q_BOTTOM=0, Q_RIGHT, Q_TOP, Q_LEFT, Q_NB_SIDES };
154
155   enum EAxes{ COO_X=1, COO_Y, COO_Z };
156
157   //=============================================================================
158   /*!
159    * \brief Container of nodes of structured mesh on a qudrangular geom FACE
160    */
161   struct _FaceGrid
162   {
163     // face sides
164     FaceQuadStructPtr _quad;
165
166     // map of (node parameter on EDGE) to (column (vector) of nodes)
167     TParam2ColumnMap _u2nodesMap;
168
169     // node column's taken form _u2nodesMap taking into account sub-shape orientation
170     vector<TNodeColumn> _columns;
171
172     // columns of normalized parameters of nodes within the unitary cube
173     vector<TXYZColumn> _ijkColumns;
174
175     // geometry of a cube side
176     TopoDS_Face _sideF;
177
178     const SMDS_MeshNode* GetNode(int iCol, int iRow) const
179     {
180       return _columns[iCol][iRow];
181     }
182     gp_XYZ GetXYZ(int iCol, int iRow) const
183     {
184       return SMESH_TNodeXYZ( GetNode( iCol, iRow ));
185     }
186     gp_XYZ& GetIJK(int iCol, int iRow)
187     {
188       return _ijkColumns[iCol][iRow];
189     }
190   };
191
192   //================================================================================
193   /*!
194    * \brief Convertor of a pair of integers to a sole index
195    */
196   struct _Indexer
197   {
198     int _xSize, _ySize;
199     _Indexer( int xSize, int ySize ): _xSize(xSize), _ySize(ySize) {}
200     int size() const { return _xSize * _ySize; }
201     int operator()(const int x, const int y) const { return y * _xSize + x; }
202   };
203
204   //================================================================================
205   /*!
206    * \brief Appends a range of node columns from a map to another map
207    */
208   template< class TMapIterator >
209   void append( TParam2ColumnMap& toMap, TMapIterator from, TMapIterator to )
210   {
211     const SMDS_MeshNode* lastNode = toMap.rbegin()->second[0];
212     const SMDS_MeshNode* firstNode = from->second[0];
213     if ( lastNode == firstNode )
214       from++;
215     double u = toMap.rbegin()->first;
216     for (; from != to; ++from )
217     {
218       u += 1;
219       TParam2ColumnMap::iterator u2nn = toMap.insert( toMap.end(), make_pair ( u, TNodeColumn()));
220       u2nn->second.swap( from->second );
221     }
222   }
223
224   //================================================================================
225   /*!
226    * \brief Finds FaceQuadStruct having a side equal to a given one and rearranges
227    *  the found FaceQuadStruct::side to have the given side at a Q_BOTTOM place
228    */
229   FaceQuadStructPtr getQuadWithBottom( StdMeshers_FaceSidePtr side,
230                                        FaceQuadStructPtr      quad[ 6 ])
231   {
232     FaceQuadStructPtr foundQuad;
233     for ( int i = 1; i < 6; ++i )
234     {
235       if ( !quad[i] ) continue;
236       for ( unsigned iS = 0; iS < quad[i]->side.size(); ++iS )
237       {
238         const StdMeshers_FaceSidePtr side2 = quad[i]->side[iS];
239         if (( side->FirstVertex().IsSame( side2->FirstVertex() ) ||
240               side->FirstVertex().IsSame( side2->LastVertex() ))
241             &&
242             ( side->LastVertex().IsSame( side2->FirstVertex() ) ||
243               side->LastVertex().IsSame( side2->LastVertex() ))
244             )
245         {
246           if ( iS != Q_BOTTOM )
247           {
248             vector< FaceQuadStruct::Side > newSides;
249             for ( unsigned j = iS; j < quad[i]->side.size(); ++j )
250               newSides.push_back( quad[i]->side[j] );
251             for ( unsigned j = 0; j < iS; ++j )
252               newSides.push_back( quad[i]->side[j] );
253             quad[i]->side.swap( newSides );
254           }
255           foundQuad.swap(quad[i]);
256           return foundQuad;
257         }
258       }
259     }
260     return foundQuad;
261   }
262   //================================================================================
263   /*!
264    * \brief Returns true if the 1st base node of sideGrid1 belongs to sideGrid2
265    */
266   //================================================================================
267
268   bool beginsAtSide( const _FaceGrid&     sideGrid1,
269                      const _FaceGrid&     sideGrid2,
270                      SMESH_ProxyMesh::Ptr proxymesh )
271   {
272     const TNodeColumn& col0  = sideGrid2._u2nodesMap.begin()->second;
273     const TNodeColumn& col1  = sideGrid2._u2nodesMap.rbegin()->second;
274     const SMDS_MeshNode* n00 = col0.front();
275     const SMDS_MeshNode* n01 = col0.back();
276     const SMDS_MeshNode* n10 = col1.front();
277     const SMDS_MeshNode* n11 = col1.back();
278     const SMDS_MeshNode* n = (sideGrid1._u2nodesMap.begin()->second)[0];
279     if ( proxymesh )
280     {
281       n00 = proxymesh->GetProxyNode( n00 );
282       n10 = proxymesh->GetProxyNode( n10 );
283       n01 = proxymesh->GetProxyNode( n01 );
284       n11 = proxymesh->GetProxyNode( n11 );
285       n   = proxymesh->GetProxyNode( n );
286     }
287     return ( n == n00 || n == n01 || n == n10 || n == n11 );
288   }
289
290   //================================================================================
291   /*!
292    * \brief Fill in _FaceGrid::_ijkColumns
293    *  \param [in,out] fg - a _FaceGrid
294    *  \param [in] i1 - coordinate index along _columns
295    *  \param [in] i2 - coordinate index along _columns[i]
296    *  \param [in] v3 - value of the constant parameter
297    */
298   //================================================================================
299
300   void computeIJK( _FaceGrid& fg, int i1, int i2, double v3 )
301   {
302     gp_XYZ ijk( v3, v3, v3 );
303     const size_t nbCol = fg._columns.size();
304     const size_t nbRow = fg._columns[0].size();
305
306     fg._ijkColumns.resize( nbCol );
307     for ( size_t i = 0; i < nbCol; ++i )
308       fg._ijkColumns[ i ].resize( nbRow, ijk );
309
310     vector< double > len( nbRow );
311     len[0] = 0;
312     for ( size_t i = 0; i < nbCol; ++i )
313     {
314       gp_Pnt pPrev = fg.GetXYZ( i, 0 );
315       for ( size_t j = 1; j < nbRow; ++j )
316       {
317         gp_Pnt p = fg.GetXYZ( i, j );
318         len[ j ] = len[ j-1 ] + p.Distance( pPrev );
319         pPrev = p;
320       }
321       for ( size_t j = 0; j < nbRow; ++j )
322         fg.GetIJK( i, j ).SetCoord( i2, len[ j ]/len.back() );
323     }
324
325     len.resize( nbCol );
326     for ( size_t j = 0; j < nbRow; ++j )
327     {
328       gp_Pnt pPrev = fg.GetXYZ( 0, j );
329       for ( size_t i = 1; i < nbCol; ++i )
330       {
331         gp_Pnt p = fg.GetXYZ( i, j );
332         len[ i ] = len[ i-1 ] + p.Distance( pPrev );
333         pPrev = p;
334       }
335       for ( size_t i = 0; i < nbCol; ++i )
336         fg.GetIJK( i, j ).SetCoord( i1, len[ i ]/len.back() );
337     }
338   }
339 }
340
341 //=============================================================================
342 /*!
343  * Generates hexahedron mesh on hexaedron like form using algorithm from
344  * "Application de l'interpolation transfinie ï¿½ la cr�ation de maillages
345  *  C0 ou G1 continus sur des triangles, quadrangles, tetraedres, pentaedres
346  *  et hexaedres d�form�s."
347  * Alain PERONNET - 8 janvier 1999
348  */
349 //=============================================================================
350
351 bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
352                                  const TopoDS_Shape & aShape)
353 {
354   // PAL14921. Enable catching std::bad_alloc and Standard_OutOfMemory outside
355   //Unexpect aCatch(SalomeException);
356   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
357
358   // Shape verification
359   // ----------------------
360
361   // shape must be a solid (or a shell) with 6 faces
362   TopExp_Explorer exp(aShape,TopAbs_SHELL);
363   if ( !exp.More() )
364     return error(COMPERR_BAD_SHAPE, "No SHELL in the geometry");
365   if ( exp.Next(), exp.More() )
366     return error(COMPERR_BAD_SHAPE, "More than one SHELL in the geometry");
367
368   TopTools_IndexedMapOfShape FF;
369   TopExp::MapShapes( aShape, TopAbs_FACE, FF);
370   if ( FF.Extent() != 6)
371   {
372     static StdMeshers_CompositeHexa_3D compositeHexa(_gen->GetANewId(), 0, _gen);
373     if ( !compositeHexa.Compute( aMesh, aShape ))
374       return error( compositeHexa.GetComputeError() );
375     return true;
376   }
377
378   // Find sides of a cube
379   // ---------------------
380   
381   FaceQuadStructPtr quad[ 6 ];
382   StdMeshers_Quadrangle_2D quadAlgo( _gen->GetANewId(), GetStudyId(), _gen);
383   for ( int i = 0; i < 6; ++i )
384   {
385     if ( !( quad[i] = FaceQuadStructPtr( quadAlgo.CheckNbEdges( aMesh, FF( i+1 )))))
386       return error( quadAlgo.GetComputeError() );
387     if ( quad[i]->side.size() != 4 )
388       return error( COMPERR_BAD_SHAPE, "Not a quadrangular box side" );
389   }
390
391   _FaceGrid aCubeSide[ 6 ];
392
393   swap( aCubeSide[B_BOTTOM]._quad, quad[0] );
394   swap( aCubeSide[B_BOTTOM]._quad->side[ Q_RIGHT],// direct the normal of bottom quad inside cube
395         aCubeSide[B_BOTTOM]._quad->side[ Q_LEFT ] );
396
397   aCubeSide[B_FRONT]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_BOTTOM], quad );
398   aCubeSide[B_RIGHT]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_RIGHT ], quad );
399   aCubeSide[B_BACK ]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_TOP   ], quad );
400   aCubeSide[B_LEFT ]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_LEFT  ], quad );
401   if ( aCubeSide[B_FRONT ]._quad )
402     aCubeSide[B_TOP]._quad = getQuadWithBottom( aCubeSide[B_FRONT ]._quad->side[Q_TOP ], quad );
403
404   for ( int i = 1; i < 6; ++i )
405     if ( !aCubeSide[i]._quad )
406       return error( COMPERR_BAD_SHAPE );
407
408   // Make viscous layers
409   // --------------------
410
411   SMESH_ProxyMesh::Ptr proxymesh;
412   if ( _viscousLayersHyp )
413   {
414     proxymesh = _viscousLayersHyp->Compute( aMesh, aShape, /*makeN2NMap=*/ true );
415     if ( !proxymesh )
416       return false;
417   }
418
419   // Check if there are triangles on cube sides
420   // -------------------------------------------
421
422   if ( aMesh.NbTriangles() > 0 )
423   {
424     for ( int i = 0; i < 6; ++i )
425     {
426       const TopoDS_Face& sideF = aCubeSide[i]._quad->face;
427       const SMESHDS_SubMesh* smDS =
428         proxymesh ? proxymesh->GetSubMesh( sideF ) : meshDS->MeshElements( sideF );
429       if ( !SMESH_MesherHelper::IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE,
430                                                     /*nullSubMeshRes=*/false ))
431       {
432         SMESH_ComputeErrorPtr err = ComputePentahedralMesh(aMesh, aShape, proxymesh.get());
433         return error( err );
434       }
435     }
436   }
437
438   // Check presence of regular grid mesh on FACEs of the cube
439   // ------------------------------------------------------------
440
441   // tool creating quadratic elements if needed
442   SMESH_MesherHelper helper (aMesh);
443   _quadraticMesh = helper.IsQuadraticSubMesh(aShape);
444
445   for ( int i = 0; i < 6; ++i )
446   {
447     const TopoDS_Face& F = aCubeSide[i]._quad->face;
448     StdMeshers_FaceSidePtr baseQuadSide = aCubeSide[i]._quad->side[ Q_BOTTOM ];
449     list<TopoDS_Edge> baseEdges( baseQuadSide->Edges().begin(), baseQuadSide->Edges().end() );
450
451     // assure correctness of node positions on baseE:
452     // helper.GetNodeU() will fix positions if they are wrong
453     helper.ToFixNodeParameters( true );
454     for ( int iE = 0; iE < baseQuadSide->NbEdges(); ++iE )
455     {
456       const TopoDS_Edge& baseE = baseQuadSide->Edge( iE );
457       if ( SMESHDS_SubMesh* smDS = meshDS->MeshElements( baseE ))
458       {
459         bool ok;
460         helper.SetSubShape( baseE );
461         SMDS_ElemIteratorPtr eIt = smDS->GetElements();
462         while ( eIt->more() )
463         {
464           const SMDS_MeshElement* e = eIt->next();
465           // expect problems on a composite side
466           try { helper.GetNodeU( baseE, e->GetNode(0), e->GetNode(1), &ok); }
467           catch (...) {}
468           try { helper.GetNodeU( baseE, e->GetNode(1), e->GetNode(0), &ok); }
469           catch (...) {}
470         }
471       }
472     }
473
474     // load grid
475     bool ok =
476       helper.LoadNodeColumns( aCubeSide[i]._u2nodesMap, F, baseEdges, meshDS, proxymesh.get());
477     if ( ok )
478     {
479       // check if the loaded grid corresponds to nb of quadrangles on the FACE
480       const SMESHDS_SubMesh* faceSubMesh =
481         proxymesh ? proxymesh->GetSubMesh( F ) : meshDS->MeshElements( F );
482       const int nbQuads = faceSubMesh->NbElements();
483       const int nbHor = aCubeSide[i]._u2nodesMap.size() - 1;
484       const int nbVer = aCubeSide[i]._u2nodesMap.begin()->second.size() - 1;
485       ok = ( nbQuads == nbHor * nbVer );
486     }
487     if ( !ok )
488     {
489       SMESH_ComputeErrorPtr err = ComputePentahedralMesh(aMesh, aShape, proxymesh.get());
490       return error( err );
491     }
492   }
493
494   // Orient loaded grids of cube sides along axis of the unitary cube coord system
495   bool isReverse[6];
496   isReverse[B_BOTTOM] = beginsAtSide( aCubeSide[B_BOTTOM], aCubeSide[B_RIGHT ], proxymesh );
497   isReverse[B_TOP   ] = beginsAtSide( aCubeSide[B_TOP   ], aCubeSide[B_RIGHT ], proxymesh );
498   isReverse[B_FRONT ] = beginsAtSide( aCubeSide[B_FRONT ], aCubeSide[B_RIGHT ], proxymesh );
499   isReverse[B_BACK  ] = beginsAtSide( aCubeSide[B_BACK  ], aCubeSide[B_RIGHT ], proxymesh );
500   isReverse[B_LEFT  ] = beginsAtSide( aCubeSide[B_LEFT  ], aCubeSide[B_BACK  ], proxymesh );
501   isReverse[B_RIGHT ] = beginsAtSide( aCubeSide[B_RIGHT ], aCubeSide[B_BACK  ], proxymesh );
502   for ( int i = 0; i < 6; ++i )
503   {
504     aCubeSide[i]._columns.resize( aCubeSide[i]._u2nodesMap.size() );
505
506     size_t iFwd = 0, iRev = aCubeSide[i]._columns.size()-1;
507     size_t*  pi = isReverse[i] ? &iRev : &iFwd;
508     TParam2ColumnMap::iterator u2nn = aCubeSide[i]._u2nodesMap.begin();
509     for ( ; iFwd < aCubeSide[i]._columns.size(); --iRev, ++iFwd, ++u2nn )
510       aCubeSide[i]._columns[ *pi ].swap( u2nn->second );
511
512     aCubeSide[i]._u2nodesMap.clear();
513   }
514
515   if ( proxymesh )
516     for ( int i = 0; i < 6; ++i )
517       for ( unsigned j = 0; j < aCubeSide[i]._columns.size(); ++j)
518         for ( unsigned k = 0; k < aCubeSide[i]._columns[j].size(); ++k)
519         {
520           const SMDS_MeshNode* & n = aCubeSide[i]._columns[j][k];
521           n = proxymesh->GetProxyNode( n );
522         }
523
524   // 4) Create internal nodes of the cube
525   // -------------------------------------
526
527   helper.SetSubShape( aShape );
528   helper.SetElementsOnShape(true);
529
530   // shortcuts to sides
531   _FaceGrid* fBottom = & aCubeSide[ B_BOTTOM ];
532   _FaceGrid* fRight  = & aCubeSide[ B_RIGHT  ];
533   _FaceGrid* fTop    = & aCubeSide[ B_TOP    ];
534   _FaceGrid* fLeft   = & aCubeSide[ B_LEFT   ];
535   _FaceGrid* fFront  = & aCubeSide[ B_FRONT  ];
536   _FaceGrid* fBack   = & aCubeSide[ B_BACK   ];
537
538   // compute normalized parameters of nodes on sides (PAL23189)
539   computeIJK( *fBottom, COO_X, COO_Y, /*z=*/0. );
540   computeIJK( *fRight,  COO_Y, COO_Z, /*x=*/1. );
541   computeIJK( *fTop,    COO_X, COO_Y, /*z=*/1. );
542   computeIJK( *fLeft,   COO_Y, COO_Z, /*x=*/0. );
543   computeIJK( *fFront,  COO_X, COO_Z, /*y=*/0. );
544   computeIJK( *fBack,   COO_X, COO_Z, /*y=*/1. );
545
546   // cube size measured in nb of nodes
547   int x, xSize = fBottom->_columns.size() , X = xSize - 1;
548   int y, ySize = fLeft->_columns.size()   , Y = ySize - 1;
549   int z, zSize = fLeft->_columns[0].size(), Z = zSize - 1;
550
551   // columns of internal nodes "rising" from nodes of fBottom
552   _Indexer colIndex( xSize, ySize );
553   vector< vector< const SMDS_MeshNode* > > columns( colIndex.size() );
554
555   // fill node columns by front and back box sides
556   for ( x = 0; x < xSize; ++x ) {
557     vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( x, 0 )];
558     vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( x, Y )];
559     column0.resize( zSize );
560     column1.resize( zSize );
561     for ( z = 0; z < zSize; ++z ) {
562       column0[ z ] = fFront->GetNode( x, z );
563       column1[ z ] = fBack ->GetNode( x, z );
564     }
565   }
566   // fill node columns by left and right box sides
567   for ( y = 1; y < ySize-1; ++y ) {
568     vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( 0, y )];
569     vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( X, y )];
570     column0.resize( zSize );
571     column1.resize( zSize );
572     for ( z = 0; z < zSize; ++z ) {
573       column0[ z ] = fLeft ->GetNode( y, z );
574       column1[ z ] = fRight->GetNode( y, z );
575     }
576   }
577   // get nodes from top and bottom box sides
578   for ( x = 1; x < xSize-1; ++x ) {
579     for ( y = 1; y < ySize-1; ++y ) {
580       vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )];
581       column.resize( zSize );
582       column.front() = fBottom->GetNode( x, y );
583       column.back()  = fTop   ->GetNode( x, y );
584     }
585   }
586
587   // projection points of the internal node on cube sub-shapes by which
588   // coordinates of the internal node are computed
589   vector<gp_XYZ> pointsOnShapes( SMESH_Block::ID_Shell );
590
591   // projections on vertices are constant
592   pointsOnShapes[ SMESH_Block::ID_V000 ] = fBottom->GetXYZ( 0, 0 );
593   pointsOnShapes[ SMESH_Block::ID_V100 ] = fBottom->GetXYZ( X, 0 );
594   pointsOnShapes[ SMESH_Block::ID_V010 ] = fBottom->GetXYZ( 0, Y );
595   pointsOnShapes[ SMESH_Block::ID_V110 ] = fBottom->GetXYZ( X, Y );
596   pointsOnShapes[ SMESH_Block::ID_V001 ] = fTop->GetXYZ( 0, 0 );
597   pointsOnShapes[ SMESH_Block::ID_V101 ] = fTop->GetXYZ( X, 0 );
598   pointsOnShapes[ SMESH_Block::ID_V011 ] = fTop->GetXYZ( 0, Y );
599   pointsOnShapes[ SMESH_Block::ID_V111 ] = fTop->GetXYZ( X, Y );
600
601   gp_XYZ params; // normalized parameters of an internal node within the unit box
602   for ( x = 1; x < xSize-1; ++x )
603   {
604     const double rX = x / double(X);
605     for ( y = 1; y < ySize-1; ++y )
606     {
607       const double rY = y / double(Y);
608
609       // a column to fill in during z loop
610       vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )];
611       // projection points on horizontal edges
612       pointsOnShapes[ SMESH_Block::ID_Ex00 ] = fBottom->GetXYZ( x, 0 );
613       pointsOnShapes[ SMESH_Block::ID_Ex10 ] = fBottom->GetXYZ( x, Y );
614       pointsOnShapes[ SMESH_Block::ID_E0y0 ] = fBottom->GetXYZ( 0, y );
615       pointsOnShapes[ SMESH_Block::ID_E1y0 ] = fBottom->GetXYZ( X, y );
616       pointsOnShapes[ SMESH_Block::ID_Ex01 ] = fTop->GetXYZ( x, 0 );
617       pointsOnShapes[ SMESH_Block::ID_Ex11 ] = fTop->GetXYZ( x, Y );
618       pointsOnShapes[ SMESH_Block::ID_E0y1 ] = fTop->GetXYZ( 0, y );
619       pointsOnShapes[ SMESH_Block::ID_E1y1 ] = fTop->GetXYZ( X, y );
620       // projection points on horizontal faces
621       pointsOnShapes[ SMESH_Block::ID_Fxy0 ] = fBottom->GetXYZ( x, y );
622       pointsOnShapes[ SMESH_Block::ID_Fxy1 ] = fTop   ->GetXYZ( x, y );
623       for ( z = 1; z < zSize-1; ++z ) // z loop
624       {
625         const double rZ = z / double(Z);
626
627         const gp_XYZ& pBo = fBottom->GetIJK( x, y );
628         const gp_XYZ& pTo = fTop   ->GetIJK( x, y );
629         const gp_XYZ& pFr = fFront ->GetIJK( x, z );
630         const gp_XYZ& pBa = fBack  ->GetIJK( x, z );
631         const gp_XYZ& pLe = fLeft  ->GetIJK( y, z );
632         const gp_XYZ& pRi = fRight ->GetIJK( y, z );
633         params.SetCoord( 1, 0.5 * ( pBo.X() * ( 1. - rZ ) + pTo.X() * rZ  +
634                                     pFr.X() * ( 1. - rY ) + pBa.X() * rY ));
635         params.SetCoord( 2, 0.5 * ( pBo.Y() * ( 1. - rZ ) + pTo.Y() * rZ  +
636                                     pLe.Y() * ( 1. - rX ) + pRi.Y() * rX ));
637         params.SetCoord( 3, 0.5 * ( pFr.Z() * ( 1. - rY ) + pBa.Z() * rY  +
638                                     pLe.Z() * ( 1. - rX ) + pRi.Z() * rX ));
639
640         // projection points on vertical edges
641         pointsOnShapes[ SMESH_Block::ID_E00z ] = fFront->GetXYZ( 0, z );
642         pointsOnShapes[ SMESH_Block::ID_E10z ] = fFront->GetXYZ( X, z );
643         pointsOnShapes[ SMESH_Block::ID_E01z ] = fBack->GetXYZ( 0, z );
644         pointsOnShapes[ SMESH_Block::ID_E11z ] = fBack->GetXYZ( X, z );
645         // projection points on vertical faces
646         pointsOnShapes[ SMESH_Block::ID_Fx0z ] = fFront->GetXYZ( x, z );
647         pointsOnShapes[ SMESH_Block::ID_Fx1z ] = fBack ->GetXYZ( x, z );
648         pointsOnShapes[ SMESH_Block::ID_F0yz ] = fLeft ->GetXYZ( y, z );
649         pointsOnShapes[ SMESH_Block::ID_F1yz ] = fRight->GetXYZ( y, z );
650
651         // compute internal node coordinates
652         gp_XYZ coords;
653         SMESH_Block::ShellPoint( params, pointsOnShapes, coords );
654         column[ z ] = helper.AddNode( coords.X(), coords.Y(), coords.Z() );
655       }
656     }
657   }
658
659   // side data no more needed, free memory
660   for ( int i = 0; i < 6; ++i )
661     aCubeSide[i]._columns.clear();
662
663   // 5) Create hexahedrons
664   // ---------------------
665
666   for ( x = 0; x < xSize-1; ++x ) {
667     for ( y = 0; y < ySize-1; ++y ) {
668       vector< const SMDS_MeshNode* >& col00 = columns[ colIndex( x, y )];
669       vector< const SMDS_MeshNode* >& col10 = columns[ colIndex( x+1, y )];
670       vector< const SMDS_MeshNode* >& col01 = columns[ colIndex( x, y+1 )];
671       vector< const SMDS_MeshNode* >& col11 = columns[ colIndex( x+1, y+1 )];
672       for ( z = 0; z < zSize-1; ++z )
673       {
674         // bottom face normal of a hexa mush point outside the volume
675         helper.AddVolume(col00[z],   col01[z],   col11[z],   col10[z],
676                          col00[z+1], col01[z+1], col11[z+1], col10[z+1]);
677       }
678     }
679   }
680   return true;
681 }
682
683 //=============================================================================
684 /*!
685  *  Evaluate
686  */
687 //=============================================================================
688
689 bool StdMeshers_Hexa_3D::Evaluate(SMESH_Mesh & aMesh,
690                                   const TopoDS_Shape & aShape,
691                                   MapShapeNbElems& aResMap)
692 {
693   vector < SMESH_subMesh * >meshFaces;
694   TopTools_SequenceOfShape aFaces;
695   for (TopExp_Explorer exp(aShape, TopAbs_FACE); exp.More(); exp.Next()) {
696     aFaces.Append(exp.Current());
697     SMESH_subMesh *aSubMesh = aMesh.GetSubMeshContaining(exp.Current());
698     ASSERT(aSubMesh);
699     meshFaces.push_back(aSubMesh);
700   }
701   if (meshFaces.size() != 6) {
702     //return error(COMPERR_BAD_SHAPE, TComm(meshFaces.size())<<" instead of 6 faces in a block");
703     static StdMeshers_CompositeHexa_3D compositeHexa(-10, 0, aMesh.GetGen());
704     return compositeHexa.Evaluate(aMesh, aShape, aResMap);
705   }
706   
707   int i = 0;
708   for(; i<6; i++) {
709     //TopoDS_Shape aFace = meshFaces[i]->GetSubShape();
710     TopoDS_Shape aFace = aFaces.Value(i+1);
711     SMESH_Algo *algo = _gen->GetAlgo(aMesh, aFace);
712     if( !algo ) {
713       std::vector<int> aResVec(SMDSEntity_Last);
714       for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
715       SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);
716       aResMap.insert(std::make_pair(sm,aResVec));
717       SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
718       smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this));
719       return false;
720     }
721     string algoName = algo->GetName();
722     bool isAllQuad = false;
723     if (algoName == "Quadrangle_2D") {
724       MapShapeNbElemsItr anIt = aResMap.find(meshFaces[i]);
725       if( anIt == aResMap.end() ) continue;
726       std::vector<int> aVec = (*anIt).second;
727       int nbtri = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
728       if( nbtri == 0 )
729         isAllQuad = true;
730     }
731     if ( ! isAllQuad ) {
732       return EvaluatePentahedralMesh(aMesh, aShape, aResMap);
733     }
734   }
735   
736   // find number of 1d elems for 1 face
737   int nb1d = 0;
738   TopTools_MapOfShape Edges1;
739   bool IsQuadratic = false;
740   bool IsFirst = true;
741   for (TopExp_Explorer exp(aFaces.Value(1), TopAbs_EDGE); exp.More(); exp.Next()) {
742     Edges1.Add(exp.Current());
743     SMESH_subMesh *sm = aMesh.GetSubMesh(exp.Current());
744     if( sm ) {
745       MapShapeNbElemsItr anIt = aResMap.find(sm);
746       if( anIt == aResMap.end() ) continue;
747       std::vector<int> aVec = (*anIt).second;
748       nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
749       if(IsFirst) {
750         IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]);
751         IsFirst = false;
752       }
753     }
754   }
755   // find face opposite to 1 face
756   int OppNum = 0;
757   for(i=2; i<=6; i++) {
758     bool IsOpposite = true;
759     for(TopExp_Explorer exp(aFaces.Value(i), TopAbs_EDGE); exp.More(); exp.Next()) {
760       if( Edges1.Contains(exp.Current()) ) {
761         IsOpposite = false;
762         break;
763       }
764     }
765     if(IsOpposite) {
766       OppNum = i;
767       break;
768     }
769   }
770   // find number of 2d elems on side faces
771   int nb2d = 0;
772   for(i=2; i<=6; i++) {
773     if( i == OppNum ) continue;
774     MapShapeNbElemsItr anIt = aResMap.find( meshFaces[i-1] );
775     if( anIt == aResMap.end() ) continue;
776     std::vector<int> aVec = (*anIt).second;
777     nb2d += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
778   }
779   
780   MapShapeNbElemsItr anIt = aResMap.find( meshFaces[0] );
781   std::vector<int> aVec = (*anIt).second;
782   int nb2d_face0 = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
783   int nb0d_face0 = aVec[SMDSEntity_Node];
784
785   std::vector<int> aResVec(SMDSEntity_Last);
786   for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
787   if(IsQuadratic) {
788     aResVec[SMDSEntity_Quad_Hexa] = nb2d_face0 * ( nb2d/nb1d );
789     int nb1d_face0_int = ( nb2d_face0*4 - nb1d ) / 2;
790     aResVec[SMDSEntity_Node] = nb0d_face0 * ( 2*nb2d/nb1d - 1 ) - nb1d_face0_int * nb2d/nb1d;
791   }
792   else {
793     aResVec[SMDSEntity_Node] = nb0d_face0 * ( nb2d/nb1d - 1 );
794     aResVec[SMDSEntity_Hexa] = nb2d_face0 * ( nb2d/nb1d );
795   }
796   SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);
797   aResMap.insert(std::make_pair(sm,aResVec));
798
799   return true;
800 }
801
802 //================================================================================
803 /*!
804  * \brief Computes hexahedral mesh from 2D mesh of block
805  */
806 //================================================================================
807
808 bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh & aMesh, SMESH_MesherHelper* aHelper)
809 {
810   static StdMeshers_HexaFromSkin_3D * algo = 0;
811   if ( !algo ) {
812     SMESH_Gen* gen = aMesh.GetGen();
813     algo = new StdMeshers_HexaFromSkin_3D( gen->GetANewId(), 0, gen );
814   }
815   algo->InitComputeError();
816   algo->Compute( aMesh, aHelper );
817   return error( algo->GetComputeError());
818 }
819
820 //================================================================================
821 /*!
822  * \brief Return true if the algorithm can mesh this shape
823  *  \param [in] aShape - shape to check
824  *  \param [in] toCheckAll - if true, this check returns OK if all shapes are OK,
825  *              else, returns OK if at least one shape is OK
826  */
827 //================================================================================
828
829 bool StdMeshers_Hexa_3D::IsApplicable( const TopoDS_Shape & aShape, bool toCheckAll )
830 {
831   TopExp_Explorer exp0( aShape, TopAbs_SOLID );
832   if ( !exp0.More() ) return false;
833
834   for ( ; exp0.More(); exp0.Next() )
835   {
836     int nbFoundShells = 0;
837     TopExp_Explorer exp1( exp0.Current(), TopAbs_SHELL );
838     for ( ; exp1.More(); exp1.Next(), ++nbFoundShells)
839       if ( nbFoundShells == 2 ) break;
840     if ( nbFoundShells != 1 ) {
841       if ( toCheckAll ) return false;
842       continue;
843     }   
844     exp1.Init( exp0.Current(), TopAbs_FACE );
845     int nbEdges = SMESH_MesherHelper::Count( exp1.Current(), TopAbs_EDGE, /*ignoreSame=*/true );
846     bool ok = ( nbEdges > 3 );
847     if ( toCheckAll && !ok ) return false;
848     if ( !toCheckAll && ok ) return true;
849   }
850   return toCheckAll;
851 };
852
853 //=======================================================================
854 //function : ComputePentahedralMesh
855 //purpose  : 
856 //=======================================================================
857
858 SMESH_ComputeErrorPtr ComputePentahedralMesh(SMESH_Mesh &          aMesh,
859                                              const TopoDS_Shape &  aShape,
860                                              SMESH_ProxyMesh*      proxyMesh)
861 {
862   SMESH_ComputeErrorPtr err = SMESH_ComputeError::New();
863   if ( proxyMesh )
864   {
865     err->myName = COMPERR_BAD_INPUT_MESH;
866     err->myComment = "Can't build pentahedral mesh on viscous layers";
867     return err;
868   }
869   bool bOK;
870   StdMeshers_Penta_3D anAlgo;
871   //
872   bOK=anAlgo.Compute(aMesh, aShape);
873   //
874   err = anAlgo.GetComputeError();
875   //
876   if ( !bOK && anAlgo.ErrorStatus() == 5 )
877   {
878     static StdMeshers_Prism_3D * aPrism3D = 0;
879     if ( !aPrism3D ) {
880       SMESH_Gen* gen = aMesh.GetGen();
881       aPrism3D = new StdMeshers_Prism_3D( gen->GetANewId(), 0, gen );
882     }
883     SMESH_Hypothesis::Hypothesis_Status aStatus;
884     if ( aPrism3D->CheckHypothesis( aMesh, aShape, aStatus ) ) {
885       aPrism3D->InitComputeError();
886       bOK = aPrism3D->Compute( aMesh, aShape );
887       err = aPrism3D->GetComputeError();
888     }
889   }
890   return err;
891 }
892
893
894 //=======================================================================
895 //function : EvaluatePentahedralMesh
896 //purpose  : 
897 //=======================================================================
898
899 bool EvaluatePentahedralMesh(SMESH_Mesh & aMesh,
900                              const TopoDS_Shape & aShape,
901                              MapShapeNbElems& aResMap)
902 {
903   StdMeshers_Penta_3D anAlgo;
904   bool bOK = anAlgo.Evaluate(aMesh, aShape, aResMap);
905
906   //err = anAlgo.GetComputeError();
907   //if ( !bOK && anAlgo.ErrorStatus() == 5 )
908   if( !bOK ) {
909     static StdMeshers_Prism_3D * aPrism3D = 0;
910     if ( !aPrism3D ) {
911       SMESH_Gen* gen = aMesh.GetGen();
912       aPrism3D = new StdMeshers_Prism_3D( gen->GetANewId(), 0, gen );
913     }
914     SMESH_Hypothesis::Hypothesis_Status aStatus;
915     if ( aPrism3D->CheckHypothesis( aMesh, aShape, aStatus ) ) {
916       return aPrism3D->Evaluate(aMesh, aShape, aResMap);
917     }
918   }
919
920   return bOK;
921 }