Salome HOME
Fix compilation problems on Mandriva64 and Mandriva
[modules/smesh.git] / src / StdMeshers / StdMeshers_Penta_3D.cxx
1 //  SMESH StdMeshers_Penta_3D implementaion of SMESH idl descriptions
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
5 // 
6 //  This library is free software; you can redistribute it and/or 
7 //  modify it under the terms of the GNU Lesser General Public 
8 //  License as published by the Free Software Foundation; either 
9 //  version 2.1 of the License. 
10 // 
11 //  This library is distributed in the hope that it will be useful, 
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
14 //  Lesser General Public License for more details. 
15 // 
16 //  You should have received a copy of the GNU Lesser General Public 
17 //  License along with this library; if not, write to the Free Software 
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
19 // 
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //
23 //
24 //  File   : StdMeshers_Penta_3D.cxx
25 //  Module : SMESH
26
27 #include "StdMeshers_Penta_3D.hxx"
28
29 #include "utilities.h"
30 #include "Utils_ExceptHandlers.hxx"
31
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_MeshElement.hxx"
34 #include "SMDS_VolumeOfNodes.hxx"
35 #include "SMDS_VolumeTool.hxx"
36 #include "SMESHDS_SubMesh.hxx"
37 #include "SMESH_Mesh.hxx"
38 #include "SMESH_MeshEditor.hxx"
39 #include "SMESH_subMesh.hxx"
40 #include "SMESH_subMeshEventListener.hxx"
41 #include "SMESH_Comment.hxx"
42
43 #include <BRepTools.hxx>
44 #include <BRepTools_WireExplorer.hxx>
45 #include <BRep_Tool.hxx>
46 #include <TopAbs_ShapeEnum.hxx>
47 #include <TopExp.hxx>
48 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
49 #include <TopTools_IndexedMapOfShape.hxx>
50 #include <TopTools_IndexedMapOfShape.hxx>
51 #include <TopTools_ListIteratorOfListOfShape.hxx>
52 #include <TopTools_ListOfShape.hxx>
53 #include <TopTools_MapOfShape.hxx>
54 #include <TopoDS.hxx>
55 #include <TopoDS_Edge.hxx>
56 #include <TopoDS_Shell.hxx>
57 #include <TopoDS_Vertex.hxx>
58 #include <gp_Pnt.hxx>
59 #include <BRepTools.hxx>
60 #include <BRepTools_WireExplorer.hxx>
61 #include <TopTools_MapOfShape.hxx>
62
63 #include <stdio.h>
64 #include <algorithm>
65
66 using namespace std;
67
68 typedef map < int, int, less<int> >::iterator   \
69   StdMeshers_IteratorOfDataMapOfIntegerInteger;
70
71 enum { NB_WALL_FACES = 4 };
72
73 //=======================================================================
74 //function : StdMeshers_Penta_3D
75 //purpose  : 
76 //=======================================================================
77 StdMeshers_Penta_3D::StdMeshers_Penta_3D()
78 : myErrorStatus(SMESH_ComputeError::New())
79 {
80   myTol3D=0.1;
81   myWallNodesMaps.resize( SMESH_Block::NbFaces() );
82   myShapeXYZ.resize( SMESH_Block::NbSubShapes() );
83   myTool = 0;
84 }
85
86 //=======================================================================
87 //function : ~StdMeshers_Penta_3D
88 //purpose  : 
89 //=======================================================================
90
91 StdMeshers_Penta_3D::~StdMeshers_Penta_3D()
92 {
93 }
94
95 //=======================================================================
96 //function : Compute
97 //purpose  : 
98 //=======================================================================
99 bool StdMeshers_Penta_3D::Compute(SMESH_Mesh& aMesh, 
100                                   const TopoDS_Shape& aShape)
101 {
102   MESSAGE("StdMeshers_Penta_3D::Compute()");
103   //
104   bool bOK=false;
105   //
106   myShape=aShape;
107   SetMesh(aMesh);
108   //
109   CheckData();
110   if (!myErrorStatus->IsOK()) {
111     return bOK;
112   }
113
114   SMESH_MesherHelper helper(aMesh);
115   myTool = &helper;
116   myCreateQuadratic = myTool->IsQuadraticSubMesh(aShape);
117
118   //
119   MakeBlock();
120   if (!myErrorStatus->IsOK()) {
121     return bOK;
122   }
123   //
124   ClearMeshOnFxy1();
125   if (!myErrorStatus->IsOK()) {
126     return bOK;
127   }
128   //
129   MakeNodes();
130   if (!myErrorStatus->IsOK()) {
131     return bOK;
132   }
133   //
134   MakeConnectingMap();
135   //
136   MakeMeshOnFxy1();
137   if (!myErrorStatus->IsOK()) {
138     return bOK;
139   }
140   //
141   MakeVolumeMesh();
142   //
143   return !bOK;
144 }
145
146 //=======================================================================
147 //function : MakeNodes
148 //purpose  : 
149 //=======================================================================
150 void StdMeshers_Penta_3D::MakeNodes()
151 {
152   const int aNbSIDs=9;
153   int i, j, k, ij, iNbN, aNodeID, aSize, iErr;
154   double aX, aY, aZ;
155   SMESH_Block::TShapeID aSID, aSIDs[aNbSIDs]={
156     SMESH_Block::ID_V000, SMESH_Block::ID_V100, 
157     SMESH_Block::ID_V110, SMESH_Block::ID_V010,
158     SMESH_Block::ID_Ex00, SMESH_Block::ID_E1y0, 
159     SMESH_Block::ID_Ex10, SMESH_Block::ID_E0y0,
160     SMESH_Block::ID_Fxy0
161   }; 
162   //
163   SMESH_Mesh* pMesh=GetMesh();
164   //
165   // 1. Define the sizes of mesh
166   //
167   // 1.1 Horizontal size
168   myJSize=0;
169   for (i=0; i<aNbSIDs; ++i) {
170     const TopoDS_Shape& aS = myBlock.Shape(aSIDs[i]);
171     SMESH_subMesh *aSubMesh = pMesh->GetSubMeshContaining(aS);
172     ASSERT(aSubMesh);
173     SMESHDS_SubMesh *aSM = aSubMesh->GetSubMeshDS();
174     if(!myCreateQuadratic) {
175       iNbN = aSM->NbNodes();
176     }
177     else {
178       iNbN = 0;
179       SMDS_NodeIteratorPtr itn = aSM->GetNodes();
180       while(itn->more()) {
181         const SMDS_MeshNode* aNode = itn->next();
182         if(myTool->IsMedium(aNode))
183           continue;
184         iNbN++;
185       }
186     }
187     myJSize += iNbN;
188   }
189   //printf("***  Horizontal: number of nodes summary=%d\n", myJSize);
190   //
191   // 1.2 Vertical size
192   myISize=2;
193   {
194     const TopoDS_Shape& aS=myBlock.Shape(SMESH_Block::ID_E00z);
195     SMESH_subMesh *aSubMesh = pMesh->GetSubMeshContaining(aS);
196     ASSERT(aSubMesh);
197     SMESHDS_SubMesh *aSM = aSubMesh->GetSubMeshDS();
198     if(!myCreateQuadratic) {
199       iNbN = aSM->NbNodes();
200     }
201     else {
202       iNbN = 0;
203       SMDS_NodeIteratorPtr itn = aSM->GetNodes();
204       while(itn->more()) {
205         const SMDS_MeshNode* aNode = itn->next();
206         if(myTool->IsMedium(aNode))
207           continue;
208         iNbN++;
209       }
210     }
211     myISize += iNbN;
212   }
213   //printf("***  Vertical: number of nodes on edges and vertices=%d\n", myISize);
214   //
215   aSize=myISize*myJSize;
216   myTNodes.resize(aSize);
217   //
218   StdMeshers_TNode aTNode;
219   gp_XYZ aCoords;
220   gp_Pnt aP3D;
221   //
222   // 2. Fill the repers on base face (Z=0)
223   i=0; j=0;
224   // vertices
225   for (k=0; k<aNbSIDs; ++k) {
226     aSID=aSIDs[k];
227     const TopoDS_Shape& aS = myBlock.Shape(aSID);
228     SMDS_NodeIteratorPtr ite = pMesh->GetSubMeshContaining(aS)->GetSubMeshDS()->GetNodes();
229     while(ite->more()) {
230       const SMDS_MeshNode* aNode = ite->next();
231       if(myTool->IsMedium(aNode))
232         continue;
233       aNodeID=aNode->GetID();
234       //
235       aTNode.SetNode(aNode);
236       aTNode.SetShapeSupportID(aSID);
237       aTNode.SetBaseNodeID(aNodeID);
238       //
239       if ( SMESH_Block::IsEdgeID (aSID)) {
240         const SMDS_EdgePosition* epos =
241           static_cast<const SMDS_EdgePosition*>(aNode->GetPosition().get());
242         myBlock.ComputeParameters( epos->GetUParameter(), aS, aCoords );
243       }
244       else {
245         aX=aNode->X();
246         aY=aNode->Y();
247         aZ=aNode->Z();
248         aP3D.SetCoord(aX, aY, aZ);
249         myBlock.ComputeParameters(aP3D, aS, aCoords);
250       }
251       iErr = myBlock.ErrorStatus();
252       if (iErr) {
253         MESSAGE("StdMeshers_Penta_3D::MakeNodes()," <<
254                 "SMESHBlock: ComputeParameters operation failed");
255         myErrorStatus=myBlock.GetError();
256         return;
257       }
258       aTNode.SetNormCoord(aCoords);
259       ij=i*myJSize+j;
260       myTNodes[ij]=aTNode;
261       ++j;
262     }
263   }
264
265   // 3.1 Fill maps of wall nodes
266   SMESH_Block::TShapeID wallFaceID[ NB_WALL_FACES ] = {
267     SMESH_Block::ID_Fx0z, SMESH_Block::ID_Fx1z,
268     SMESH_Block::ID_F0yz, SMESH_Block::ID_F1yz
269     };
270   SMESH_Block::TShapeID baseEdgeID[ NB_WALL_FACES ] = {
271     SMESH_Block::ID_Ex00, SMESH_Block::ID_Ex10,
272     SMESH_Block::ID_E0y0, SMESH_Block::ID_E1y0
273     };
274   for ( i = 0; i < NB_WALL_FACES ; ++i ) {
275     int fIndex = SMESH_Block::ShapeIndex( wallFaceID[ i ]);
276     bool ok = LoadIJNodes (myWallNodesMaps[ fIndex ],
277                            TopoDS::Face( myBlock.Shape( wallFaceID[ i ] )),
278                            TopoDS::Edge( myBlock.Shape( baseEdgeID[ i ] )),
279                            pMesh->GetMeshDS());
280     if ( !ok ) {
281       myErrorStatus->myName = COMPERR_BAD_INPUT_MESH;
282       myErrorStatus->myComment = SMESH_Comment() <<
283         "Can't find regular quadrangle mesh on a side face #" <<
284         pMesh->GetMeshDS()->ShapeToIndex( myBlock.Shape( wallFaceID[ i ]));
285       return;
286     }
287   }
288
289   // 3.2 find node columns for vertical edges and edge IDs
290   vector<const SMDS_MeshNode*> * verticEdgeNodes[ NB_WALL_FACES ];
291   SMESH_Block::TShapeID          verticEdgeID   [ NB_WALL_FACES ];
292   for ( i = 0; i < NB_WALL_FACES ; ++i ) { // 4 first base nodes are nodes on vertices
293     // edge ID
294     SMESH_Block::TShapeID eID, vID = aSIDs[ i ];
295     ShapeSupportID(false, vID, eID);
296     verticEdgeID[ i ] = eID;
297     // column nodes
298     StdMeshers_TNode& aTNode = myTNodes[ i ];
299     verticEdgeNodes[ i ] = 0;
300     for ( j = 0; j < NB_WALL_FACES ; ++j ) { // loop on 4 wall faces
301       int fIndex = SMESH_Block::ShapeIndex( wallFaceID[ j ]);
302       StdMeshers_IJNodeMap & ijNodes= myWallNodesMaps[ fIndex ];
303       if ( ijNodes.begin()->second[0] == aTNode.Node() )
304         verticEdgeNodes[ i ] = & ijNodes.begin()->second;
305       else if ( ijNodes.rbegin()->second[0] == aTNode.Node() )
306         verticEdgeNodes[ i ] = & ijNodes.rbegin()->second;
307       if ( verticEdgeNodes[ i ] )
308         break;
309     }
310   }
311
312   // 3.3 set XYZ of vertices, and initialize of the rest
313   SMESHDS_Mesh* aMesh = GetMesh()->GetMeshDS();
314   for ( int id = SMESH_Block::ID_V000; id < SMESH_Block::ID_Shell; ++id ) {
315     if ( SMESH_Block::IsVertexID( id )) {
316       TopoDS_Shape V = myBlock.Shape( id );
317       SMESHDS_SubMesh* sm = aMesh->MeshElements( V );
318       const SMDS_MeshNode* n = sm->GetNodes()->next();
319       myShapeXYZ[ id ].SetCoord( n->X(), n->Y(), n->Z() );
320     }
321     else
322       myShapeXYZ[ id ].SetCoord( 0., 0., 0. );
323   }
324
325
326   // 4. Fill the rest repers
327   bool bIsUpperLayer;
328   int iBNID;
329   SMESH_Block::TShapeID aSSID, aBNSSID;
330   StdMeshers_TNode aTN;
331   //
332
333   // create top face and find UV for it's corners
334   const TopoDS_Face& TopFace = TopoDS::Face(myBlock.Shape(SMESH_Block::ID_Fxy1));
335   SMESHDS_Mesh* meshDS = pMesh->GetMeshDS();
336   int topfaceID = meshDS->ShapeToIndex(TopFace);
337   const TopoDS_Vertex& v001 = TopoDS::Vertex(myBlock.Shape(SMESH_Block::ID_V001));
338   SMDS_NodeIteratorPtr itn = pMesh->GetSubMeshContaining(v001)->GetSubMeshDS()->GetNodes();
339   const SMDS_MeshNode* N = itn->next();
340   gp_XY UV001 = myTool->GetNodeUV(TopFace,N);
341   const TopoDS_Vertex& v101 = TopoDS::Vertex(myBlock.Shape(SMESH_Block::ID_V101));
342   itn = pMesh->GetSubMeshContaining(v101)->GetSubMeshDS()->GetNodes();
343   N = itn->next();
344   gp_XY UV101 = myTool->GetNodeUV(TopFace,N);
345   const TopoDS_Vertex& v011 = TopoDS::Vertex(myBlock.Shape(SMESH_Block::ID_V011));
346   itn = pMesh->GetSubMeshContaining(v011)->GetSubMeshDS()->GetNodes();
347   N = itn->next();
348   gp_XY UV011 = myTool->GetNodeUV(TopFace,N);
349   const TopoDS_Vertex& v111 = TopoDS::Vertex(myBlock.Shape(SMESH_Block::ID_V111));
350   itn = pMesh->GetSubMeshContaining(v111)->GetSubMeshDS()->GetNodes();
351   N = itn->next();
352   gp_XY UV111 = myTool->GetNodeUV(TopFace,N);
353
354   for (j=0; j<myJSize; ++j) { // loop on all nodes of the base face (ID_Fxy0)
355     // base node info
356     const StdMeshers_TNode& aBN = myTNodes[j];
357     aBNSSID = (SMESH_Block::TShapeID)aBN.ShapeSupportID();
358     iBNID = aBN.BaseNodeID();
359     const gp_XYZ& aBNXYZ = aBN.NormCoord();
360     bool createNode = ( aBNSSID == SMESH_Block::ID_Fxy0 ); // if base node is inside a bottom face
361     //
362     // set XYZ on horizontal edges and get node columns of faces:
363     // 2 columns for each face, between which a base node is located
364     vector<const SMDS_MeshNode*>* nColumns[8];
365     double ratio[ NB_WALL_FACES ]; // base node position between columns [0.-1.]
366     if ( createNode ) {
367       for ( k = 0; k < NB_WALL_FACES ; ++k ) {
368         ratio[ k ] = SetHorizEdgeXYZ (aBNXYZ, wallFaceID[ k ],
369                                       nColumns[k*2], nColumns[k*2+1]);
370       }
371     }
372     //
373     // XYZ on the bottom and top faces
374     const SMDS_MeshNode* n = aBN.Node();
375     myShapeXYZ[ SMESH_Block::ID_Fxy0 ].SetCoord( n->X(), n->Y(), n->Z() );
376     myShapeXYZ[ SMESH_Block::ID_Fxy1 ].SetCoord( 0., 0., 0. );
377     //
378     // first create or find a top node, then the rest ones in a column
379     for (i=myISize-1; i>0; --i) // vertical loop, from top to bottom
380     {
381       bIsUpperLayer = (i==(myISize-1));
382       gp_XY UV_Ex01, UV_Ex11, UV_E0y1, UV_E1y1;
383       if ( createNode ) // a base node is inside a top face
384       {
385         // set XYZ on vertical edges and faces
386         for ( k = 0; k < NB_WALL_FACES ; ++k ) {
387           // XYZ on a vertical edge 
388           const SMDS_MeshNode* n = (*verticEdgeNodes[ k ]) [ i ];
389           myShapeXYZ[ verticEdgeID[ k ] ].SetCoord( n->X(), n->Y(), n->Z() );
390           // XYZ on a face (part 1 from one column)
391           n = (*nColumns[k*2]) [ i ];
392           gp_XYZ xyz( n->X(), n->Y(), n->Z() );
393           myShapeXYZ[ wallFaceID[ k ]] = ( 1. - ratio[ k ]) * xyz;
394           gp_XY tmp1;
395           if( bIsUpperLayer ) {
396             tmp1 = myTool->GetNodeUV(TopFace,n);
397             tmp1 = ( 1. - ratio[ k ]) * tmp1;
398           }
399           // XYZ on a face (part 2 from other column)
400           n = (*nColumns[k*2+1]) [ i ];
401           xyz.SetCoord( n->X(), n->Y(), n->Z() );
402           myShapeXYZ[ wallFaceID[ k ]] += ratio[ k ] * xyz;
403           if( bIsUpperLayer ) {
404             gp_XY tmp2 = myTool->GetNodeUV(TopFace,n);
405             tmp1 +=  ratio[ k ] * tmp2;
406             if( k==0 )
407               UV_Ex01 = tmp1;
408             else if( k==1 )
409               UV_Ex11 = tmp1;
410             else if( k==2 )
411               UV_E0y1 = tmp1;
412             else
413               UV_E1y1 = tmp1;
414           }
415         }
416       }
417       // fill current node info
418       //   -index in aTNodes
419       ij=i*myJSize+j; 
420       //   -normalized coordinates  
421       aX=aBNXYZ.X();  
422       aY=aBNXYZ.Y();
423       //aZ=aZL[i];
424       aZ=(double)i/(double)(myISize-1);
425       aCoords.SetCoord(aX, aY, aZ);
426       //
427       //   suporting shape ID
428       ShapeSupportID(bIsUpperLayer, aBNSSID, aSSID);
429       if (!myErrorStatus->IsOK()) {
430         MESSAGE("StdMeshers_Penta_3D::MakeNodes() ");
431         return;
432       }
433       //
434       aTN.SetShapeSupportID(aSSID);
435       aTN.SetNormCoord(aCoords);
436       aTN.SetBaseNodeID(iBNID);
437       //
438       if (aSSID!=SMESH_Block::ID_NONE){
439         // try to find the node
440         const TopoDS_Shape& aS=myBlock.Shape((int)aSSID);
441         FindNodeOnShape(aS, aCoords, i, aTN);
442       }
443       else{
444         // create node and get it id
445         CreateNode (bIsUpperLayer, aCoords, aTN);
446         //
447         if ( bIsUpperLayer ) {
448           const SMDS_MeshNode* n = aTN.Node();
449           myShapeXYZ[ SMESH_Block::ID_Fxy1 ].SetCoord( n->X(), n->Y(), n->Z() );
450           // set node on top face:
451           // find UV parameter for this node
452           //              UV_Ex11
453           //   UV011+-----+----------+UV111
454           //        |                |
455           //        |                |
456           // UV_E0y1+     +node      +UV_E1y1
457           //        |                |
458           //        |                |
459           //        |                |
460           //   UV001+-----+----------+UV101
461           //              UV_Ex01
462           gp_Pnt2d aP;
463           double u = aCoords.X(), v = aCoords.Y();
464           double u1 = ( 1. - u ), v1 = ( 1. - v );
465           aP.ChangeCoord()  = UV_Ex01 * v1;
466           aP.ChangeCoord() += UV_Ex11 * v;
467           aP.ChangeCoord() += UV_E0y1 * u1;
468           aP.ChangeCoord() += UV_E1y1 * u;
469           aP.ChangeCoord() -= UV001 * u1 * v1;
470           aP.ChangeCoord() -= UV101 * u  * v1;
471           aP.ChangeCoord() -= UV011 * u1 * v;
472           aP.ChangeCoord() -= UV111 * u  * v;
473           meshDS->SetNodeOnFace((SMDS_MeshNode*)n, topfaceID, aP.X(), aP.Y());
474         }
475       }
476       if (!myErrorStatus->IsOK()) {
477         MESSAGE("StdMeshers_Penta_3D::MakeNodes() ");
478         return;
479       }
480       //
481       myTNodes[ij]=aTN;
482     }
483   }
484   //DEB
485   /*
486   {
487     int iSSID, iBNID, aID;
488     //
489     for (i=0; i<myISize; ++i) {
490       printf(" Layer# %d\n", i);
491       for (j=0; j<myJSize; ++j) {
492         ij=i*myJSize+j; 
493         const StdMeshers_TNode& aTN=myTNodes[ij];
494         //const StdMeshers_TNode& aTN=aTNodes[ij];
495         const gp_XYZ& aXYZ=aTN.NormCoord();
496         iSSID=aTN.ShapeSupportID();
497         iBNID=aTN.BaseNodeID();
498         //
499         const SMDS_MeshNode* aNode=aTN.Node();
500         aID=aNode->GetID(); 
501         aX=aNode->X();
502         aY=aNode->Y();
503         aZ=aNode->Z();
504         printf("*** j:%d BNID#%d iSSID:%d ID:%d { %lf %lf %lf },  { %lf %lf %lf }\n",
505                j,  iBNID, iSSID, aID, aXYZ.X(),  aXYZ.Y(), aXYZ.Z(), aX, aY, aZ);
506       }
507     }
508   }
509   */
510   //DEB t
511 }
512
513
514 //=======================================================================
515 //function : FindNodeOnShape
516 //purpose  : 
517 //=======================================================================
518
519 void StdMeshers_Penta_3D::FindNodeOnShape(const TopoDS_Shape& aS,
520                                           const gp_XYZ&       aParams,
521                                           const int           z,
522                                           StdMeshers_TNode&   aTN)
523 {
524   double aX, aY, aZ, aD, aTol2, minD;
525   gp_Pnt aP1, aP2;
526   //
527   SMESH_Mesh* pMesh = GetMesh();
528   aTol2 = myTol3D*myTol3D;
529   minD = 1.e100;
530   SMDS_MeshNode* pNode = NULL;
531   //
532   if ( aS.ShapeType() == TopAbs_FACE ||
533        aS.ShapeType() == TopAbs_EDGE ) {
534     // find a face ID to which aTN belongs to
535     int faceID;
536     if ( aS.ShapeType() == TopAbs_FACE )
537       faceID = myBlock.ShapeID( aS );
538     else { // edge maybe vertical or top horizontal
539       gp_XYZ aCoord = aParams;
540       if ( aCoord.Z() == 1. )
541         aCoord.SetZ( 0.5 ); // move from top down
542       else
543         aCoord.SetX( 0.5 ); // move along X
544       faceID = SMESH_Block::GetShapeIDByParams( aCoord );
545     }
546     ASSERT( SMESH_Block::IsFaceID( faceID ));
547     int fIndex = SMESH_Block::ShapeIndex( faceID );
548     StdMeshers_IJNodeMap & ijNodes = myWallNodesMaps[ fIndex ];
549     // look for a base node in ijNodes
550     const SMDS_MeshNode* baseNode = pMesh->GetMeshDS()->FindNode( aTN.BaseNodeID() );
551     StdMeshers_IJNodeMap::const_iterator par_nVec = ijNodes.begin();
552     for ( ; par_nVec != ijNodes.end(); par_nVec++ )
553       if ( par_nVec->second[ 0 ] == baseNode ) {
554         pNode = (SMDS_MeshNode*)par_nVec->second.at( z );
555         aTN.SetNode(pNode);
556         return;
557       }
558   }
559   //
560   myBlock.Point(aParams, aS, aP1);
561   //
562   SMDS_NodeIteratorPtr ite=
563     pMesh->GetSubMeshContaining(aS)->GetSubMeshDS()->GetNodes();
564   while(ite->more()) {
565     const SMDS_MeshNode* aNode = ite->next();
566     if(myTool->IsMedium(aNode))
567       continue;
568     aX=aNode->X();
569     aY=aNode->Y();
570     aZ=aNode->Z();
571     aP2.SetCoord(aX, aY, aZ);
572     aD=(double)aP1.SquareDistance(aP2);
573     //printf("** D=%lf ", aD, aTol2);
574     if (aD < minD) {
575       pNode=(SMDS_MeshNode*)aNode;
576       aTN.SetNode(pNode);
577       minD = aD;
578       //printf(" Ok\n");
579       if (aD<aTol2)
580         return; 
581     }
582   }
583   //
584   //printf(" KO\n");
585   //aTN.SetNode(pNode);
586   //MESSAGE("StdMeshers_Penta_3D::FindNodeOnShape(), can not find the node");
587   //myErrorStatus=11; // can not find the node;
588 }
589
590
591 //=======================================================================
592 //function : SetHorizEdgeXYZ
593 //purpose  : 
594 //=======================================================================
595
596 double StdMeshers_Penta_3D::SetHorizEdgeXYZ(const gp_XYZ&                  aBaseNodeParams,
597                                             const int                      aFaceID,
598                                             vector<const SMDS_MeshNode*>*& aCol1,
599                                             vector<const SMDS_MeshNode*>*& aCol2)
600 {
601   // find base and top edges of the face
602   enum { BASE = 0, TOP };
603   vector< int > edgeVec; // 0-base, 1-top
604   SMESH_Block::GetFaceEdgesIDs( aFaceID, edgeVec );
605   //
606   int coord = SMESH_Block::GetCoordIndOnEdge( edgeVec[ BASE ] );
607   bool isForward = myBlock.IsForwadEdge( edgeVec[ BASE ] );
608
609   double param = aBaseNodeParams.Coord( coord );
610   if ( !isForward)
611     param = 1. - param;
612   //
613   // look for columns around param
614   StdMeshers_IJNodeMap & ijNodes =
615     myWallNodesMaps[ SMESH_Block::ShapeIndex( aFaceID )];
616   StdMeshers_IJNodeMap::iterator par_nVec_1 = ijNodes.begin();
617   while ( par_nVec_1->first < param )
618     par_nVec_1++;
619   StdMeshers_IJNodeMap::iterator par_nVec_2 = par_nVec_1;
620   //
621   double r = 0;
622   if ( par_nVec_1 != ijNodes.begin() ) {
623     par_nVec_1--;
624     r = ( param - par_nVec_1->first ) / ( par_nVec_2->first - par_nVec_1->first );
625   }
626   aCol1 = & par_nVec_1->second;
627   aCol2 = & par_nVec_2->second;
628
629   // top edge
630   if (1) {
631     // this variant is better for cases with curved edges and
632     // different nodes distribution on top and base edges
633     const SMDS_MeshNode* n1 = aCol1->back();
634     const SMDS_MeshNode* n2 = aCol2->back();
635     gp_XYZ xyz1( n1->X(), n1->Y(), n1->Z() );
636     gp_XYZ xyz2( n2->X(), n2->Y(), n2->Z() );
637     myShapeXYZ[ edgeVec[ 1 ] ] = ( 1. - r ) * xyz1 + r * xyz2;
638   }
639   else {
640     // this variant is better for other cases
641 //   SMESH_MesherHelper helper( *GetMesh() );
642 //   const TopoDS_Edge & edge = TopoDS::Edge( myBlock.Shape( edgeVec[ TOP ]));
643 //   double u1 = helper.GetNodeU( edge, n1 );
644 //   double u2 = helper.GetNodeU( edge, n2 );
645 //   double u = ( 1. - r ) * u1 + r * u2;
646 //   gp_XYZ topNodeParams;
647 //   myBlock.Block().EdgeParameters( edgeVec[ TOP ], u, topNodeParams );
648 //   myBlock.Block().EdgePoint( edgeVec[ TOP ],
649 //                              topNodeParams,
650 //                              myShapeXYZ[ edgeVec[ TOP ]]);
651   }
652
653   // base edge
654   myBlock.Block().EdgePoint( edgeVec[ BASE ],
655                              aBaseNodeParams,
656                              myShapeXYZ[ edgeVec[ BASE ]]);
657   return r;
658 }
659
660
661 //=======================================================================
662 //function : MakeVolumeMesh
663 //purpose  : 
664 //=======================================================================
665 void StdMeshers_Penta_3D::MakeVolumeMesh()
666 {
667   int i, j, ij, ik, i1, i2, aSSID; 
668   //
669   SMESH_Mesh*   pMesh = GetMesh();
670   SMESHDS_Mesh* meshDS = pMesh->GetMeshDS();
671   //
672   int shapeID = meshDS->ShapeToIndex( myShape );
673   //
674   // 1. Set Node In Volume
675   ik = myISize-1;
676   for (i=1; i<ik; ++i){
677     for (j=0; j<myJSize; ++j){
678       ij=i*myJSize+j;
679       const StdMeshers_TNode& aTN = myTNodes[ij];
680       aSSID=aTN.ShapeSupportID();
681       if (aSSID==SMESH_Block::ID_NONE) {
682         SMDS_MeshNode* aNode = (SMDS_MeshNode*)aTN.Node();
683         meshDS->SetNodeInVolume(aNode, shapeID);
684       }
685     }
686   }
687   //
688   // 2. Make pentahedrons
689   int aID0, k , aJ[3];
690   vector<const SMDS_MeshNode*> aN;
691   //
692   SMDS_ElemIteratorPtr itf, aItNodes;
693   //
694   const TopoDS_Face& aFxy0=
695     TopoDS::Face(myBlock.Shape(SMESH_Block::ID_Fxy0));
696   SMESH_subMesh *aSubMesh0 = pMesh->GetSubMeshContaining(aFxy0);
697   SMESHDS_SubMesh *aSM0 = aSubMesh0->GetSubMeshDS();
698   //
699   itf = aSM0->GetElements();
700   while(itf->more()) {
701     const SMDS_MeshElement* pE0 = itf->next();
702     //
703     int nbFaceNodes = pE0->NbNodes();
704     if(myCreateQuadratic)
705       nbFaceNodes = nbFaceNodes/2;
706     if ( aN.size() < nbFaceNodes * 2 )
707       aN.resize( nbFaceNodes * 2 );
708     //
709     k=0;
710     aItNodes=pE0->nodesIterator();
711     while (aItNodes->more()) {
712       //const SMDS_MeshElement* pNode = aItNodes->next();
713       const SMDS_MeshNode* pNode =
714         static_cast<const SMDS_MeshNode*> (aItNodes->next());
715       if(myTool->IsMedium(pNode))
716         continue;
717       aID0 = pNode->GetID();
718       aJ[k] = GetIndexOnLayer(aID0);
719       if (!myErrorStatus->IsOK()) {
720         MESSAGE("StdMeshers_Penta_3D::MakeVolumeMesh");
721         return;
722       }
723       //
724       ++k;
725     }
726     //
727     bool forward = true;
728     for (i=0; i<ik; ++i) {
729       i1=i;
730       i2=i+1;
731       for(j=0; j<nbFaceNodes; ++j) {
732         ij = i1*myJSize+aJ[j];
733         const StdMeshers_TNode& aTN1 = myTNodes[ij];
734         const SMDS_MeshNode* aN1 = aTN1.Node();
735         aN[j]=aN1;
736         //
737         ij=i2*myJSize+aJ[j];
738         const StdMeshers_TNode& aTN2 = myTNodes[ij];
739         const SMDS_MeshNode* aN2 = aTN2.Node();
740         aN[j+nbFaceNodes] = aN2;
741       }
742       // check if volume orientation will be ok
743       if ( i == 0 ) {
744         SMDS_VolumeTool vTool;
745         switch ( nbFaceNodes ) {
746         case 3: {
747           SMDS_VolumeOfNodes tmpVol (aN[0], aN[1], aN[2],
748                                      aN[3], aN[4], aN[5]);
749           vTool.Set( &tmpVol );
750           break;
751         }
752         case 4: {
753           SMDS_VolumeOfNodes tmpVol(aN[0], aN[1], aN[2], aN[3],
754                                     aN[4], aN[5], aN[6], aN[7]);
755           vTool.Set( &tmpVol );
756           break;
757         }
758         default:
759           continue;
760         }
761         forward = vTool.IsForward();
762       }
763       // add volume
764       SMDS_MeshVolume* aV = 0;
765       switch ( nbFaceNodes ) {
766       case 3:
767         if ( forward ) {
768           //aV = meshDS->AddVolume(aN[0], aN[1], aN[2],
769           //                       aN[3], aN[4], aN[5]);
770           aV = myTool->AddVolume(aN[0], aN[1], aN[2], aN[3], aN[4], aN[5]);
771         }
772         else {
773           //aV = meshDS->AddVolume(aN[0], aN[2], aN[1],
774           //                       aN[3], aN[5], aN[4]);
775           aV = myTool->AddVolume(aN[0], aN[2], aN[1], aN[3], aN[5], aN[4]);
776         }
777         break;
778       case 4:
779         if ( forward ) {
780           //aV = meshDS->AddVolume(aN[0], aN[1], aN[2], aN[3],
781           //                       aN[4], aN[5], aN[6], aN[7]);
782           aV = myTool->AddVolume(aN[0], aN[1], aN[2], aN[3],
783                                  aN[4], aN[5], aN[6], aN[7]);
784         }
785         else {
786           //aV = meshDS->AddVolume(aN[0], aN[3], aN[2], aN[1],
787           //                       aN[4], aN[7], aN[6], aN[5]);
788           aV = myTool->AddVolume(aN[0], aN[3], aN[2], aN[1],
789                                  aN[4], aN[7], aN[6], aN[5]);
790         }
791         break;
792       default:
793         continue;
794       }
795       meshDS->SetMeshElementOnShape(aV, shapeID);
796     }
797   }
798 }
799
800 //=======================================================================
801 //function : MakeMeshOnFxy1
802 //purpose  : 
803 //=======================================================================
804 void StdMeshers_Penta_3D::MakeMeshOnFxy1()
805 {
806   int aID0, aJ, aLevel, ij, aNbNodes, k;
807   //
808   SMDS_NodeIteratorPtr itn;
809   SMDS_ElemIteratorPtr itf, aItNodes;
810   SMDSAbs_ElementType aElementType;
811   //
812   const TopoDS_Face& aFxy0=
813     TopoDS::Face(myBlock.Shape(SMESH_Block::ID_Fxy0));
814   const TopoDS_Face& aFxy1=
815     TopoDS::Face(myBlock.Shape(SMESH_Block::ID_Fxy1));
816   SMESH_MesherHelper faceHelper( *GetMesh() );
817   faceHelper.IsQuadraticSubMesh(aFxy1);
818   //
819   SMESH_Mesh* pMesh = GetMesh();
820   SMESHDS_Mesh * meshDS = pMesh->GetMeshDS();
821   //
822   SMESH_subMesh *aSubMesh1 = pMesh->GetSubMeshContaining(aFxy1);
823   SMESH_subMesh *aSubMesh0 = pMesh->GetSubMeshContaining(aFxy0);
824   SMESHDS_SubMesh *aSM0 = aSubMesh0->GetSubMeshDS();
825   //
826   // set nodes on aFxy1
827   aLevel = myISize-1;
828   itn = aSM0->GetNodes();
829   aNbNodes = aSM0->NbNodes();
830   //printf("** aNbNodes=%d\n", aNbNodes);
831
832   //
833   // set elements on aFxy1
834   vector<const SMDS_MeshNode*> aNodes1;
835   //
836   itf = aSM0->GetElements();
837   while(itf->more()) {
838     const SMDS_MeshElement* pE0 = itf->next();
839     aElementType = pE0->GetType();
840     if (!aElementType==SMDSAbs_Face) {
841       continue;
842     }
843     aNbNodes = pE0->NbNodes();
844     if(myCreateQuadratic)
845       aNbNodes = aNbNodes/2;
846     if ( aNodes1.size() < aNbNodes )
847       aNodes1.resize( aNbNodes );
848     //
849     k = aNbNodes-1; // reverse a face
850     aItNodes = pE0->nodesIterator();
851     while (aItNodes->more()) {
852       const SMDS_MeshNode* pNode =
853         static_cast<const SMDS_MeshNode*> (aItNodes->next());
854       if(myTool->IsMedium(pNode))
855         continue;
856       aID0 = pNode->GetID();
857       aJ = GetIndexOnLayer(aID0);
858       if (!myErrorStatus->IsOK()) {
859         MESSAGE("StdMeshers_Penta_3D::MakeMeshOnFxy1() ");
860         return;
861       }
862       //
863       ij = aLevel*myJSize + aJ;
864       const StdMeshers_TNode& aTN1 = myTNodes[ij];
865       const SMDS_MeshNode* aN1 = aTN1.Node();
866       aNodes1[k] = aN1;
867       --k;
868     }
869     SMDS_MeshFace * face = 0;
870     switch ( aNbNodes ) {
871     case 3:
872       face = faceHelper.AddFace(aNodes1[0], aNodes1[1], aNodes1[2]);
873       break;
874     case 4:
875       face = faceHelper.AddFace(aNodes1[0], aNodes1[1], aNodes1[2], aNodes1[3]);
876       break;
877     default:
878       continue;
879     }
880     meshDS->SetMeshElementOnShape(face, aFxy1);
881   }
882
883   // update compute state of top face submesh
884   aSubMesh1->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
885
886   // assure that mesh on the top face will be cleaned when it is cleaned
887   // on the bottom face
888   SMESH_subMesh* volSM = pMesh->GetSubMesh( myTool->GetSubShape() );
889   volSM->SetEventListener( new SMESH_subMeshEventListener(true),
890                            SMESH_subMeshEventListenerData::MakeData( aSubMesh1 ),
891                            aSubMesh0 ); // translate CLEAN event of aSubMesh0 to aSubMesh1
892 }
893
894 //=======================================================================
895 //function : ClearMeshOnFxy1
896 //purpose  : 
897 //=======================================================================
898 void StdMeshers_Penta_3D::ClearMeshOnFxy1()
899 {
900   SMESH_subMesh* aSubMesh;
901   SMESH_Mesh* pMesh=GetMesh();
902   //
903   const TopoDS_Shape& aFxy1=myBlock.Shape(SMESH_Block::ID_Fxy1);
904   aSubMesh = pMesh->GetSubMeshContaining(aFxy1);
905   if (aSubMesh)
906     aSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
907 }
908
909 //=======================================================================
910 //function : GetIndexOnLayer
911 //purpose  : 
912 //=======================================================================
913 int StdMeshers_Penta_3D::GetIndexOnLayer(const int aID)
914 {
915   int j=-1;
916   StdMeshers_IteratorOfDataMapOfIntegerInteger aMapIt;
917   //
918   aMapIt=myConnectingMap.find(aID);
919   if (aMapIt==myConnectingMap.end()) {
920     myErrorStatus->myName    = 200;
921     myErrorStatus->myComment = "Internal error of StdMeshers_Penta_3D";
922     return j;
923   }
924   j=(*aMapIt).second;
925   return j;
926 }
927
928 //=======================================================================
929 //function : MakeConnectingMap
930 //purpose  : 
931 //=======================================================================
932 void StdMeshers_Penta_3D::MakeConnectingMap()
933 {
934   int j, aBNID;
935   //
936   for (j=0; j<myJSize; ++j) {
937     const StdMeshers_TNode& aBN=myTNodes[j];
938     aBNID=aBN.BaseNodeID();
939     myConnectingMap[aBNID]=j;
940   }
941 }
942
943 //=======================================================================
944 //function : CreateNode
945 //purpose  : 
946 //=======================================================================
947 void StdMeshers_Penta_3D::CreateNode(const bool bIsUpperLayer,
948                                      const gp_XYZ& aParams,
949                                      StdMeshers_TNode& aTN)
950 {
951   double aX, aY, aZ;
952   //
953   gp_Pnt aP;
954   //
955   SMDS_MeshNode* pNode=NULL; 
956   aTN.SetNode(pNode);  
957   //
958 //   if (bIsUpperLayer) {
959 //     // point on face Fxy1
960 //     const TopoDS_Shape& aS=myBlock.Shape(SMESH_Block::ID_Fxy1);
961 //     myBlock.Point(aParams, aS, aP);
962 //   }
963 //   else {
964 //     // point inside solid
965 //     myBlock.Point(aParams, aP);
966 //   }
967   if (bIsUpperLayer) {
968     double u = aParams.X(), v = aParams.Y();
969     double u1 = ( 1. - u ), v1 = ( 1. - v );
970     aP.ChangeCoord()  = myShapeXYZ[ SMESH_Block::ID_Ex01 ] * v1;
971     aP.ChangeCoord() += myShapeXYZ[ SMESH_Block::ID_Ex11 ] * v;
972     aP.ChangeCoord() += myShapeXYZ[ SMESH_Block::ID_E0y1 ] * u1;
973     aP.ChangeCoord() += myShapeXYZ[ SMESH_Block::ID_E1y1 ] * u;
974
975     aP.ChangeCoord() -= myShapeXYZ[ SMESH_Block::ID_V001 ] * u1 * v1;
976     aP.ChangeCoord() -= myShapeXYZ[ SMESH_Block::ID_V101 ] * u  * v1;
977     aP.ChangeCoord() -= myShapeXYZ[ SMESH_Block::ID_V011 ] * u1 * v;
978     aP.ChangeCoord() -= myShapeXYZ[ SMESH_Block::ID_V111 ] * u  * v;
979   }
980   else {
981     SMESH_Block::ShellPoint( aParams, myShapeXYZ, aP.ChangeCoord() );
982   }
983   //
984 //   iErr=myBlock.ErrorStatus();
985 //   if (iErr) {
986 //     myErrorStatus=12; // can not find the node point;
987 //     return;
988 //   }
989   //
990   aX=aP.X(); aY=aP.Y(); aZ=aP.Z(); 
991   //
992   SMESH_Mesh* pMesh = GetMesh();
993   SMESHDS_Mesh* pMeshDS = pMesh->GetMeshDS();
994   //
995   pNode = pMeshDS->AddNode(aX, aY, aZ);
996   
997   aTN.SetNode(pNode);
998 }
999
1000 //=======================================================================
1001 //function : ShapeSupportID
1002 //purpose  : 
1003 //=======================================================================
1004 void StdMeshers_Penta_3D::ShapeSupportID(const bool bIsUpperLayer,
1005                                          const SMESH_Block::TShapeID aBNSSID,
1006                                          SMESH_Block::TShapeID& aSSID)
1007 {
1008   switch (aBNSSID) {
1009     case SMESH_Block::ID_V000:
1010       aSSID=(bIsUpperLayer) ?  SMESH_Block::ID_V001 : SMESH_Block::ID_E00z;
1011       break;
1012     case SMESH_Block::ID_V100:
1013       aSSID=(bIsUpperLayer) ?  SMESH_Block::ID_V101 : SMESH_Block::ID_E10z;
1014       break; 
1015     case SMESH_Block::ID_V110:
1016       aSSID=(bIsUpperLayer) ?  SMESH_Block::ID_V111 : SMESH_Block::ID_E11z;
1017       break;
1018     case SMESH_Block::ID_V010:
1019       aSSID=(bIsUpperLayer) ?  SMESH_Block::ID_V011 : SMESH_Block::ID_E01z;
1020       break;
1021     case SMESH_Block::ID_Ex00:
1022       aSSID=(bIsUpperLayer) ?  SMESH_Block::ID_Ex01 : SMESH_Block::ID_Fx0z;
1023       break;
1024     case SMESH_Block::ID_Ex10:
1025       aSSID=(bIsUpperLayer) ?  SMESH_Block::ID_Ex11 : SMESH_Block::ID_Fx1z;
1026       break; 
1027     case SMESH_Block::ID_E0y0:
1028       aSSID=(bIsUpperLayer) ?  SMESH_Block::ID_E0y1 : SMESH_Block::ID_F0yz;
1029       break; 
1030     case SMESH_Block::ID_E1y0:
1031       aSSID=(bIsUpperLayer) ?  SMESH_Block::ID_E1y1 : SMESH_Block::ID_F1yz;
1032       break; 
1033     case SMESH_Block::ID_Fxy0:
1034       aSSID=SMESH_Block::ID_NONE;//(bIsUpperLayer) ?  Shape_ID_Fxy1 : Shape_ID_NONE;
1035       break;   
1036     default:
1037       aSSID=SMESH_Block::ID_NONE;
1038       myErrorStatus->myName=10; // Can not find supporting shape ID
1039       myErrorStatus->myComment = "Internal error of StdMeshers_Penta_3D";
1040       break;
1041   }
1042   return;
1043 }
1044 //=======================================================================
1045 //function : MakeBlock
1046 //purpose  : 
1047 //=======================================================================
1048 void StdMeshers_Penta_3D::MakeBlock()
1049 {
1050   bool bFound;
1051   int i, j, iNbEV, iNbE, iErr, iCnt, iNbNodes, iNbF;
1052   //
1053   TopoDS_Vertex aV000, aV001;
1054   TopoDS_Shape aFTr;
1055   TopTools_IndexedDataMapOfShapeListOfShape aMVES;
1056   TopTools_IndexedMapOfShape aME ,aMEV, aM;
1057   TopTools_ListIteratorOfListOfShape aIt;
1058   //
1059   TopExp::MapShapes(myShape, TopAbs_FACE, aM);
1060   //
1061   // 0. Find triangulated face aFTr
1062   SMDSAbs_ElementType aElementType;
1063   SMESH_Mesh* pMesh=GetMesh();
1064   //
1065   iCnt = 0;
1066   iNbF = aM.Extent();
1067   for (i=1; i<=iNbF; ++i) {
1068     const TopoDS_Shape& aF = aM(i);
1069     SMESH_subMesh *aSubMesh = pMesh->GetSubMeshContaining(aF);
1070     ASSERT(aSubMesh);
1071     SMESHDS_SubMesh *aSM = aSubMesh->GetSubMeshDS();
1072     SMDS_ElemIteratorPtr itf = aSM->GetElements();
1073     while(itf->more()) {
1074       const SMDS_MeshElement * pElement = itf->next();
1075       aElementType = pElement->GetType();
1076       if (aElementType==SMDSAbs_Face) {
1077         iNbNodes = pElement->NbNodes();
1078         if ( iNbNodes==3 || (myCreateQuadratic && iNbNodes==6) ) {
1079           aFTr = aF;
1080           ++iCnt;
1081           if (iCnt>1) {
1082             // \begin{E.A.}
1083             // The current algorithm fails if there is more that one
1084             // face wich contains triangles ...
1085             // In that case, replace return by break to try another
1086             // method (coded in "if (iCnt != 1) { ... }")
1087             //
1088             // MESSAGE("StdMeshers_Penta_3D::MakeBlock() ");
1089             // myErrorStatus=5; // more than one face has triangulation
1090             // return;
1091             break;
1092             // \end{E.A.}
1093           }
1094           break; // next face
1095         }
1096       }
1097     }
1098   }
1099   //
1100   // \begin{E.A.}
1101   // The current algorithm fails if "iCnt != 1", the case "iCnt == 0"
1102   // was not reached 'cause it was not called from Hexa_3D ... Now it
1103   // can occurs and in my opinion, it is the most common case.
1104   //
1105   if (iCnt != 1) {
1106     // The suggested algorithm is the following :
1107     //
1108     // o Check that nb_of_faces == 6 and nb_of_edges == 12
1109     //   then the shape is tologically equivalent to a box
1110     // o In a box, there are three set of four // edges ...
1111     //   In the cascade notation, it seems to be the edges
1112     //   numbered : 
1113     //     - 1, 3, 5, 7
1114     //     - 2, 4, 6, 8
1115     //     - 9, 10, 11, 12
1116     // o For each one of this set, check if the four edges
1117     //   have the same number of element.
1118     // o If so, check if the "corresponding" // faces contains
1119     //   only quads. It's the faces numbered:
1120     //     - 1, 2, 3, 4
1121     //     - 1, 2, 5, 6
1122     //     - 3, 4, 5, 6
1123     // o If so, check if the opposite edges of each // faces
1124     //   have the same number of elements. It is the edges
1125     //   numbered :
1126     //     - 2 and 4, 6 and 8, 9 and 10, 11 and 12
1127     //     - 1 and 3, 5 and 7, 9 and 11, 10 and 12
1128     //     - 1 and 5, 3 and 7, 4 and 8, 2 and 6
1129     // o If so, check if the two other faces have the same
1130     //   number of elements. It is the faces numbered:
1131     //     - 5, 6
1132     //     - 3, 4
1133     //     - 1, 2
1134     //   This test should be improved to test if the nodes
1135     //   of the two faces are really "en face".
1136     // o If so, one of the two faces is a candidate to an extrusion,
1137     //   It is the faces numbered :
1138     //     - 5
1139     //     - 3
1140     //     - 1
1141     // o Finally, if there is only one candidate, let do the
1142     //   extrusion job for the corresponding face
1143     //
1144     int isOK = 0;
1145     //
1146     int iNbF = aM.Extent();
1147     if (iNbF == 6) {
1148       //
1149       int nb_f1 = pMesh->GetSubMeshContaining(aM(1))->GetSubMeshDS()->NbElements();
1150       int nb_f2 = pMesh->GetSubMeshContaining(aM(2))->GetSubMeshDS()->NbElements();
1151       int nb_f3 = pMesh->GetSubMeshContaining(aM(3))->GetSubMeshDS()->NbElements();
1152       int nb_f4 = pMesh->GetSubMeshContaining(aM(4))->GetSubMeshDS()->NbElements();
1153       int nb_f5 = pMesh->GetSubMeshContaining(aM(5))->GetSubMeshDS()->NbElements();
1154       int nb_f6 = pMesh->GetSubMeshContaining(aM(6))->GetSubMeshDS()->NbElements();
1155       //
1156       int has_only_quad_f1 = 1;
1157       int has_only_quad_f2 = 1;
1158       int has_only_quad_f3 = 1;
1159       int has_only_quad_f4 = 1;
1160       int has_only_quad_f5 = 1;
1161       int has_only_quad_f6 = 1;
1162       //
1163       for (i=1; i<=iNbF; ++i) {
1164         int ok = 1;
1165         const TopoDS_Shape& aF = aM(i);
1166         SMESH_subMesh *aSubMesh = pMesh->GetSubMeshContaining(aF);
1167         SMESHDS_SubMesh *aSM = aSubMesh->GetSubMeshDS();
1168         SMDS_ElemIteratorPtr itf = aSM->GetElements();
1169         while(itf->more()) {
1170           const SMDS_MeshElement * pElement = itf->next();
1171           aElementType = pElement->GetType();
1172           if (aElementType==SMDSAbs_Face) {
1173             iNbNodes = pElement->NbNodes();
1174             if ( iNbNodes!=4 ) {
1175               ok = 0;
1176               break ;
1177             }
1178           }
1179         }
1180         if (i==1) has_only_quad_f1 = ok ;
1181         if (i==2) has_only_quad_f2 = ok ;
1182         if (i==3) has_only_quad_f3 = ok ;
1183         if (i==4) has_only_quad_f4 = ok ;
1184         if (i==5) has_only_quad_f5 = ok ;
1185         if (i==6) has_only_quad_f6 = ok ;
1186       }
1187       //
1188       TopTools_IndexedMapOfShape aE;
1189       TopExp::MapShapes(myShape, TopAbs_EDGE, aE);
1190       int iNbE = aE.Extent();
1191       if (iNbE == 12) {
1192         //
1193         int nb_e01 = pMesh->GetSubMeshContaining(aE(1))->GetSubMeshDS()->NbElements();
1194         int nb_e02 = pMesh->GetSubMeshContaining(aE(2))->GetSubMeshDS()->NbElements();
1195         int nb_e03 = pMesh->GetSubMeshContaining(aE(3))->GetSubMeshDS()->NbElements();
1196         int nb_e04 = pMesh->GetSubMeshContaining(aE(4))->GetSubMeshDS()->NbElements();
1197         int nb_e05 = pMesh->GetSubMeshContaining(aE(5))->GetSubMeshDS()->NbElements();
1198         int nb_e06 = pMesh->GetSubMeshContaining(aE(6))->GetSubMeshDS()->NbElements();
1199         int nb_e07 = pMesh->GetSubMeshContaining(aE(7))->GetSubMeshDS()->NbElements();
1200         int nb_e08 = pMesh->GetSubMeshContaining(aE(8))->GetSubMeshDS()->NbElements();
1201         int nb_e09 = pMesh->GetSubMeshContaining(aE(9))->GetSubMeshDS()->NbElements();
1202         int nb_e10 = pMesh->GetSubMeshContaining(aE(10))->GetSubMeshDS()->NbElements();
1203         int nb_e11 = pMesh->GetSubMeshContaining(aE(11))->GetSubMeshDS()->NbElements();
1204         int nb_e12 = pMesh->GetSubMeshContaining(aE(12))->GetSubMeshDS()->NbElements();
1205         //
1206         int nb_ok = 0 ;
1207         //
1208         if ( (nb_e01==nb_e03) && (nb_e03==nb_e05) && (nb_e05==nb_e07) ) {
1209           if ( has_only_quad_f1 && has_only_quad_f2 && has_only_quad_f3 && has_only_quad_f4 ) {
1210             if ( (nb_e09==nb_e10) && (nb_e08==nb_e06) && (nb_e11==nb_e12) && (nb_e04==nb_e02) ) {
1211               if (nb_f5==nb_f6) {
1212                 nb_ok += 1;
1213                 aFTr = aM(5);
1214               }
1215             }
1216           }
1217         }
1218         if ( (nb_e02==nb_e04) && (nb_e04==nb_e06) && (nb_e06==nb_e08) ) {
1219           if ( has_only_quad_f1 && has_only_quad_f2 && has_only_quad_f5 && has_only_quad_f6 ) {
1220             if ( (nb_e01==nb_e03) && (nb_e10==nb_e12) && (nb_e05==nb_e07) && (nb_e09==nb_e11) ) {
1221               if (nb_f3==nb_f4) {
1222                 nb_ok += 1;
1223                 aFTr = aM(3);
1224               }
1225             }
1226           }
1227         }
1228         if ( (nb_e09==nb_e10) && (nb_e10==nb_e11) && (nb_e11==nb_e12) ) {
1229           if ( has_only_quad_f3 && has_only_quad_f4 && has_only_quad_f5 && has_only_quad_f6 ) {
1230             if ( (nb_e01==nb_e05) && (nb_e02==nb_e06) && (nb_e03==nb_e07) && (nb_e04==nb_e08) ) {
1231               if (nb_f1==nb_f2) {
1232                 nb_ok += 1;
1233                 aFTr = aM(1);
1234               }
1235             }
1236           }
1237         }
1238         //
1239         if ( nb_ok == 1 ) {
1240           isOK = 1;
1241         }
1242         //
1243       }
1244     }
1245     if (!isOK) {
1246       myErrorStatus->myName=5; // more than one face has triangulation
1247       myErrorStatus->myComment="Incorrect input mesh";
1248       return;
1249     }
1250   }
1251   // \end{E.A.}
1252   // 
1253   // 1. Vetrices V00, V001;
1254   //
1255   TopExp::MapShapes(aFTr, TopAbs_EDGE, aME);
1256   TopExp::MapShapesAndAncestors(myShape, TopAbs_VERTEX, TopAbs_EDGE, aMVES);
1257   //
1258   // 1.1 Base vertex V000
1259   iNbE = aME.Extent();
1260   if (iNbE!= NB_WALL_FACES ){
1261     MESSAGE("StdMeshers_Penta_3D::MakeBlock() ");
1262     myErrorStatus->myName=7; // too few edges are in base face aFTr
1263     myErrorStatus->myComment=SMESH_Comment("Not a quadrilateral face #")
1264       <<pMesh->GetMeshDS()->ShapeToIndex( aFTr )<<": "<<iNbE<<" edges" ;
1265     return;
1266   }
1267   const TopoDS_Edge& aE1=TopoDS::Edge(aME(1));
1268   aV000=TopExp::FirstVertex(aE1);
1269   //
1270   const TopTools_ListOfShape& aLE=aMVES.FindFromKey(aV000);
1271   aIt.Initialize(aLE);
1272   for (; aIt.More(); aIt.Next()) {
1273     const TopoDS_Shape& aEx=aIt.Value();
1274     aMEV.Add(aEx);
1275   }
1276   iNbEV=aMEV.Extent();
1277   if (iNbEV!=3){
1278     MESSAGE("StdMeshers_Penta_3D::MakeBlock() ");
1279     myErrorStatus->myName=7; // too few edges meet in base vertex 
1280     myErrorStatus->myComment=SMESH_Comment("3 edges must share vertex #")
1281       <<pMesh->GetMeshDS()->ShapeToIndex( aV000 )<<" but there are "<<iNbEV<<" edges";
1282     return;
1283   }
1284   //
1285   // 1.2 Vertex V001
1286   bFound=false;
1287   for (j=1; j<=iNbEV; ++j) {
1288     const TopoDS_Shape& aEx=aMEV(j);
1289     if (!aME.Contains(aEx)) {
1290       TopoDS_Vertex aV[2];
1291       //
1292       const TopoDS_Edge& aE=TopoDS::Edge(aEx);
1293       TopExp::Vertices(aE, aV[0], aV[1]);
1294       for (i=0; i<2; ++i) {
1295         if (!aV[i].IsSame(aV000)) {
1296           aV001=aV[i];
1297           bFound=!bFound;
1298           break;
1299         }
1300       }
1301     }
1302   }
1303   //
1304   if (!bFound) {
1305     MESSAGE("StdMeshers_Penta_3D::MakeBlock() ");
1306     myErrorStatus->myName=8; // can not find reper V001
1307     myErrorStatus->myComment=SMESH_Comment("Can't find opposite vertex for vertex #")
1308       <<pMesh->GetMeshDS()->ShapeToIndex( aV000 );
1309     return;
1310   }
1311   //DEB
1312   //gp_Pnt aP000, aP001;
1313   //
1314   //aP000=BRep_Tool::Pnt(TopoDS::Vertex(aV000));
1315   //printf("*** aP000 { %lf, %lf, %lf }\n", aP000.X(), aP000.Y(), aP000.Z());
1316   //aP001=BRep_Tool::Pnt(TopoDS::Vertex(aV001));
1317   //printf("*** aP001 { %lf, %lf, %lf }\n", aP001.X(), aP001.Y(), aP001.Z());
1318   //DEB
1319   //
1320   aME.Clear();
1321   TopExp::MapShapes(myShape, TopAbs_SHELL, aME);
1322   iNbE=aME.Extent();
1323   if (iNbE!=1) {
1324     MESSAGE("StdMeshers_Penta_3D::MakeBlock() ");
1325     myErrorStatus->myName=9; // number of shells in source shape !=1
1326     myErrorStatus->myComment=SMESH_Comment("Unexpected nb of shells ")<<iNbE;
1327     return;
1328   }
1329   //
1330   // 2. Load Block
1331   const TopoDS_Shell& aShell=TopoDS::Shell(aME(1));
1332   myBlock.Load(aShell, aV000, aV001);
1333   iErr = myBlock.ErrorStatus();
1334   if (iErr) {
1335     MESSAGE("StdMeshers_Penta_3D::MakeBlock() ");
1336     myErrorStatus=myBlock.GetError(); // SMESHBlock: Load operation failed
1337     return;
1338   }
1339 }
1340 //=======================================================================
1341 //function : CheckData
1342 //purpose  : 
1343 //=======================================================================
1344 void StdMeshers_Penta_3D::CheckData()
1345 {
1346   int i, iNb;
1347   int iNbEx[]={8, 12, 6};
1348   //
1349   TopAbs_ShapeEnum aST;
1350   TopAbs_ShapeEnum aSTEx[]={
1351     TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE
1352   }; 
1353   TopTools_IndexedMapOfShape aM;
1354   //
1355   if (myShape.IsNull()){
1356     MESSAGE("StdMeshers_Penta_3D::CheckData() ");
1357     myErrorStatus->myName=2; // null shape
1358     myErrorStatus->myComment="Null shape";
1359     return;
1360   }
1361   //
1362   aST=myShape.ShapeType();
1363   if (!(aST==TopAbs_SOLID || aST==TopAbs_SHELL)) {
1364     MESSAGE("StdMeshers_Penta_3D::CheckData() ");
1365     myErrorStatus->myName=3; // not compatible type of shape
1366     myErrorStatus->myComment=SMESH_Comment("Wrong shape type (TopAbs_ShapeEnum) ")<<aST;
1367     return;
1368   }
1369   //
1370   for (i=0; i<3; ++i) {
1371     aM.Clear();
1372     TopExp::MapShapes(myShape, aSTEx[i], aM);
1373     iNb=aM.Extent();
1374     if (iNb!=iNbEx[i]){
1375       MESSAGE("StdMeshers_Penta_3D::CheckData() ");
1376       myErrorStatus->myName=4; // number of subshape is not compatible
1377       myErrorStatus->myComment="Wrong number of subshapes of a block";
1378       return;
1379     }
1380   }
1381 }
1382
1383 //=======================================================================
1384 //function : LoadIJNodes
1385 //purpose  : Load nodes bound to theFace into column (vectors) and rows
1386 //           of theIJNodes.
1387 //           The value of theIJNodes map is a vector of ordered nodes so
1388 //           that the 0-the one lies on theBaseEdge.
1389 //           The key of theIJNodes map is a normalized parameter of each
1390 //           0-the node on theBaseEdge.
1391 //=======================================================================
1392
1393 bool StdMeshers_Penta_3D::LoadIJNodes(StdMeshers_IJNodeMap & theIJNodes,
1394                                       const TopoDS_Face&     theFace,
1395                                       const TopoDS_Edge&     theBaseEdge,
1396                                       SMESHDS_Mesh*          theMesh)
1397 {
1398   // get vertices of theBaseEdge
1399   TopoDS_Vertex vfb, vlb, vft; // first and last, bottom and top vertices
1400   TopoDS_Edge eFrw = TopoDS::Edge( theBaseEdge.Oriented( TopAbs_FORWARD ));
1401   TopExp::Vertices( eFrw, vfb, vlb );
1402
1403   // find the other edges of theFace and orientation of e1
1404   TopoDS_Edge e1, e2, eTop;
1405   bool rev1, CumOri = false;
1406   TopExp_Explorer exp( theFace, TopAbs_EDGE );
1407   int nbEdges = 0;
1408   for ( ; exp.More(); exp.Next() ) {
1409     if ( ++nbEdges > NB_WALL_FACES ) {
1410       return false; // more than 4 edges in theFace
1411     }
1412     TopoDS_Edge e = TopoDS::Edge( exp.Current() );
1413     if ( theBaseEdge.IsSame( e ))
1414       continue;
1415     TopoDS_Vertex vCommon;
1416     if ( !TopExp::CommonVertex( theBaseEdge, e, vCommon ))
1417       eTop = e;
1418     else if ( vCommon.IsSame( vfb )) {
1419       e1 = e;
1420       vft = TopExp::LastVertex( e1, CumOri );
1421       rev1 = vfb.IsSame( vft );
1422       if ( rev1 )
1423         vft = TopExp::FirstVertex( e1, CumOri );
1424     }
1425     else
1426       e2 = e;
1427   }
1428   if ( nbEdges < NB_WALL_FACES ) {
1429     return false; // less than 4 edges in theFace
1430   }
1431
1432   // submeshes corresponding to shapes
1433   SMESHDS_SubMesh* smFace = theMesh->MeshElements( theFace );
1434   SMESHDS_SubMesh* smb = theMesh->MeshElements( theBaseEdge );
1435   SMESHDS_SubMesh* smt = theMesh->MeshElements( eTop );
1436   SMESHDS_SubMesh* sm1 = theMesh->MeshElements( e1 );
1437   SMESHDS_SubMesh* sm2 = theMesh->MeshElements( e2 );
1438   SMESHDS_SubMesh* smVfb = theMesh->MeshElements( vfb );
1439   SMESHDS_SubMesh* smVlb = theMesh->MeshElements( vlb );
1440   SMESHDS_SubMesh* smVft = theMesh->MeshElements( vft );
1441   if (!smFace || !smb || !smt || !sm1 || !sm2 || !smVfb || !smVlb || !smVft ) {
1442     MESSAGE( "NULL submesh " <<smFace<<" "<<smb<<" "<<smt<<" "<<
1443             sm1<<" "<<sm2<<" "<<smVfb<<" "<<smVlb<<" "<<smVft);
1444     return false;
1445   }
1446   if ( smb->NbNodes() != smt->NbNodes() || sm1->NbNodes() != sm2->NbNodes() ) {
1447     MESSAGE(" Diff nb of nodes on opposite edges" );
1448     return false;
1449   }
1450   if (smVfb->NbNodes() != 1 || smVlb->NbNodes() != 1 || smVft->NbNodes() != 1) {
1451     MESSAGE("Empty submesh of vertex");
1452     return false;
1453   }
1454   if ( sm1->NbNodes() * smb->NbNodes() != smFace->NbNodes() ) {
1455     // check quadratic case
1456     if ( myCreateQuadratic ) {
1457       int n1 = sm1->NbNodes()/2;
1458       int n2 = smb->NbNodes()/2;
1459       int n3 = sm1->NbNodes() - n1;
1460       int n4 = smb->NbNodes() - n2;
1461       int nf = sm1->NbNodes()*smb->NbNodes() - n3*n4;
1462       if( nf != smFace->NbNodes() ) {
1463         MESSAGE( "Wrong nb face nodes: " <<
1464                 sm1->NbNodes()<<" "<<smb->NbNodes()<<" "<<smFace->NbNodes());
1465         return false;
1466       }
1467     }
1468     else {
1469       MESSAGE( "Wrong nb face nodes: " <<
1470               sm1->NbNodes()<<" "<<smb->NbNodes()<<" "<<smFace->NbNodes());
1471       return false;
1472     }
1473   }
1474   // IJ size
1475   int vsize = sm1->NbNodes() + 2;
1476   int hsize = smb->NbNodes() + 2;
1477   if(myCreateQuadratic) {
1478     vsize = vsize - sm1->NbNodes()/2 -1;
1479     hsize = hsize - smb->NbNodes()/2 -1;
1480   }
1481
1482   // load nodes from theBaseEdge
1483
1484   set<const SMDS_MeshNode*> loadedNodes;
1485   const SMDS_MeshNode* nullNode = 0;
1486
1487   vector<const SMDS_MeshNode*> & nVecf = theIJNodes[ 0.];
1488   nVecf.resize( vsize, nullNode );
1489   loadedNodes.insert( nVecf[ 0 ] = smVfb->GetNodes()->next() );
1490
1491   vector<const SMDS_MeshNode*> & nVecl = theIJNodes[ 1.];
1492   nVecl.resize( vsize, nullNode );
1493   loadedNodes.insert( nVecl[ 0 ] = smVlb->GetNodes()->next() );
1494
1495   double f, l;
1496   BRep_Tool::Range( eFrw, f, l );
1497   double range = l - f;
1498   SMDS_NodeIteratorPtr nIt = smb->GetNodes();
1499   const SMDS_MeshNode* node;
1500   while ( nIt->more() ) {
1501     node = nIt->next();
1502     if(myTool->IsMedium(node))
1503       continue;
1504     const SMDS_EdgePosition* pos =
1505       dynamic_cast<const SMDS_EdgePosition*>( node->GetPosition().get() );
1506     if ( !pos ) {
1507       return false;
1508     }
1509     double u = ( pos->GetUParameter() - f ) / range;
1510     vector<const SMDS_MeshNode*> & nVec = theIJNodes[ u ];
1511     nVec.resize( vsize, nullNode );
1512     loadedNodes.insert( nVec[ 0 ] = node );
1513   }
1514   if ( theIJNodes.size() != hsize ) {
1515     MESSAGE( "Wrong node positions on theBaseEdge" );
1516     return false;
1517   }
1518
1519   // load nodes from e1
1520
1521   map< double, const SMDS_MeshNode*> sortedNodes; // sort by param on edge
1522   nIt = sm1->GetNodes();
1523   while ( nIt->more() ) {
1524     node = nIt->next();
1525     if(myTool->IsMedium(node))
1526       continue;
1527     const SMDS_EdgePosition* pos =
1528       dynamic_cast<const SMDS_EdgePosition*>( node->GetPosition().get() );
1529     if ( !pos ) {
1530       return false;
1531     }
1532     sortedNodes.insert( make_pair( pos->GetUParameter(), node ));
1533   }
1534   loadedNodes.insert( nVecf[ vsize - 1 ] = smVft->GetNodes()->next() );
1535   map< double, const SMDS_MeshNode*>::iterator u_n = sortedNodes.begin();
1536   int row = rev1 ? vsize - 1 : 0;
1537   for ( ; u_n != sortedNodes.end(); u_n++ ) {
1538     if ( rev1 ) row--;
1539     else        row++;
1540     loadedNodes.insert( nVecf[ row ] = u_n->second );
1541   }
1542
1543   // try to load the rest nodes
1544
1545   // get all faces from theFace
1546   TIDSortedElemSet allFaces, foundFaces;
1547   SMDS_ElemIteratorPtr eIt = smFace->GetElements();
1548   while ( eIt->more() ) {
1549     const SMDS_MeshElement* e = eIt->next();
1550     if ( e->GetType() == SMDSAbs_Face )
1551       allFaces.insert( e );
1552   }
1553   // Starting from 2 neighbour nodes on theBaseEdge, look for a face
1554   // the nodes belong to, and between the nodes of the found face,
1555   // look for a not loaded node considering this node to be the next
1556   // in a column of the starting second node. Repeat, starting
1557   // from nodes next to the previous starting nodes in their columns,
1558   // and so on while a face can be found. Then go the the next pair
1559   // of nodes on theBaseEdge.
1560   StdMeshers_IJNodeMap::iterator par_nVec_1 = theIJNodes.begin();
1561   StdMeshers_IJNodeMap::iterator par_nVec_2 = par_nVec_1;
1562   // loop on columns
1563   int col = 0;
1564   for ( par_nVec_2++; par_nVec_2 != theIJNodes.end(); par_nVec_1++, par_nVec_2++ ) {
1565     col++;
1566     row = 0;
1567     const SMDS_MeshNode* n1 = par_nVec_1->second[ row ];
1568     const SMDS_MeshNode* n2 = par_nVec_2->second[ row ];
1569     const SMDS_MeshElement* face = 0;
1570     do {
1571       // look for a face by 2 nodes
1572       face = SMESH_MeshEditor::FindFaceInSet( n1, n2, allFaces, foundFaces );
1573       if ( face ) {
1574         int nbFaceNodes = face->NbNodes();
1575         if ( (!myCreateQuadratic && nbFaceNodes>4) ||
1576              (myCreateQuadratic && nbFaceNodes>8) ) {
1577           MESSAGE(" Too many nodes in a face: " << nbFaceNodes );
1578           return false;
1579         }
1580         // look for a not loaded node of the <face>
1581         bool found = false;
1582         const SMDS_MeshNode* n3 = 0; // a node defferent from n1 and n2
1583         eIt = face->nodesIterator() ;
1584         while ( !found && eIt->more() ) {
1585           node = static_cast<const SMDS_MeshNode*>( eIt->next() );
1586           if(myTool->IsMedium(node))
1587             continue;
1588           found = loadedNodes.insert( node ).second;
1589           if ( !found && node != n1 && node != n2 )
1590             n3 = node;
1591         }
1592         if ( found ) {
1593           if ( ++row > vsize - 1 ) {
1594             MESSAGE( "Too many nodes in column "<< col <<": "<< row+1);
1595             return false;
1596           }
1597           par_nVec_2->second[ row ] = node;
1598           foundFaces.insert( face );
1599           n2 = node;
1600           if ( nbFaceNodes==4 || (myCreateQuadratic && nbFaceNodes==8) ) {
1601             n1 = par_nVec_1->second[ row ];
1602           }
1603         }
1604         else if ( (nbFaceNodes==3 || (myCreateQuadratic && nbFaceNodes==6) )  &&
1605                  n3 == par_nVec_1->second[ row ] ) {
1606           n1 = n3;
1607         }
1608         else {
1609           MESSAGE( "Not quad mesh, column "<< col );
1610           return false;
1611         }
1612       }
1613     }
1614     while ( face && n1 && n2 );
1615
1616     if ( row < vsize - 1 ) {
1617       MESSAGE( "Too few nodes in column "<< col <<": "<< row+1);
1618       MESSAGE( "Base node 1: "<< par_nVec_1->second[0]);
1619       MESSAGE( "Base node 2: "<< par_nVec_2->second[0]);
1620       MESSAGE( "Current node 1: "<< n1);
1621       MESSAGE( "Current node 2: "<< n2);
1622       MESSAGE( "first base node: "<< theIJNodes.begin()->second[0]);
1623       MESSAGE( "last base node: "<< theIJNodes.rbegin()->second[0]);
1624       return false;
1625     }
1626   } // loop on columns
1627
1628   return true;
1629 }
1630
1631 //////////////////////////////////////////////////////////////////////////
1632 //
1633 //   StdMeshers_SMESHBlock
1634 //
1635 //////////////////////////////////////////////////////////////////////////
1636
1637 //=======================================================================
1638 //function : StdMeshers_SMESHBlock
1639 //purpose  : 
1640 //=======================================================================
1641 StdMeshers_SMESHBlock::StdMeshers_SMESHBlock()
1642 {
1643   myErrorStatus=1;
1644   myIsEdgeForward.resize( SMESH_Block::NbEdges(), -1 );
1645 }
1646
1647 //=======================================================================
1648 //function : IsForwadEdge
1649 //purpose  : 
1650 //=======================================================================
1651
1652 bool StdMeshers_SMESHBlock::IsForwadEdge(const int theEdgeID)
1653 {
1654   int index = myTBlock.ShapeIndex( theEdgeID );
1655   if ( !myTBlock.IsEdgeID( theEdgeID ))
1656     return false;
1657
1658   if ( myIsEdgeForward[ index ] < 0 )
1659     myIsEdgeForward[ index ] =
1660       myTBlock.IsForwardEdge( TopoDS::Edge( Shape( theEdgeID )), myShapeIDMap );
1661
1662   return myIsEdgeForward[ index ];
1663 }
1664
1665 //=======================================================================
1666 //function : ErrorStatus
1667 //purpose  : 
1668 //=======================================================================
1669 int StdMeshers_SMESHBlock::ErrorStatus() const
1670 {
1671   return myErrorStatus;
1672 }
1673
1674 //================================================================================
1675 /*!
1676  * \brief Return problem description
1677  */
1678 //================================================================================
1679
1680 SMESH_ComputeErrorPtr StdMeshers_SMESHBlock::GetError() const
1681 {
1682   SMESH_ComputeErrorPtr err = SMESH_ComputeError::New();
1683   string & text = err->myComment;
1684   switch ( myErrorStatus ) {
1685   case 2:
1686   case 3: text = "Internal error of StdMeshers_Penta_3D"; break; 
1687   case 4: text = "Can't compute normalized parameters of a point inside a block"; break;
1688   case 5: text = "Can't compute coordinates by normalized parameters inside a block"; break;
1689   case 6: text = "Can't detect block subshapes. Not a block?"; break;
1690   }
1691   if (!text.empty())
1692     err->myName = myErrorStatus;
1693   return err;
1694 }
1695
1696 //=======================================================================
1697 //function : Load
1698 //purpose  : 
1699 //=======================================================================
1700 void StdMeshers_SMESHBlock::Load(const TopoDS_Shell& theShell)
1701 {
1702   TopoDS_Vertex aV000, aV001;
1703   //
1704   Load(theShell, aV000, aV001);
1705 }
1706
1707 //=======================================================================
1708 //function : Load
1709 //purpose  : 
1710 //=======================================================================
1711 void StdMeshers_SMESHBlock::Load(const TopoDS_Shell& theShell,
1712                                  const TopoDS_Vertex& theV000,
1713                                  const TopoDS_Vertex& theV001)
1714 {
1715   myErrorStatus=0;
1716   //
1717   myShell=theShell;
1718   //
1719   bool bOk;
1720   //
1721   myShapeIDMap.Clear();  
1722   bOk = myTBlock.LoadBlockShapes(myShell, theV000, theV001, myShapeIDMap);
1723   if (!bOk) {
1724     myErrorStatus=6;
1725     return;
1726   }
1727 }
1728
1729 //=======================================================================
1730 //function : ComputeParameters
1731 //purpose  : 
1732 //=======================================================================
1733 void StdMeshers_SMESHBlock::ComputeParameters(const gp_Pnt& thePnt, 
1734                                               gp_XYZ& theXYZ)
1735 {
1736   ComputeParameters(thePnt, myShell, theXYZ);
1737 }
1738
1739 //=======================================================================
1740 //function : ComputeParameters
1741 //purpose  : 
1742 //=======================================================================
1743 void StdMeshers_SMESHBlock::ComputeParameters(const gp_Pnt& thePnt,
1744                                               const TopoDS_Shape& theShape,
1745                                               gp_XYZ& theXYZ)
1746 {
1747   myErrorStatus=0;
1748   //
1749   int aID;
1750   bool bOk;
1751   //
1752   aID = ShapeID(theShape);
1753   if (myErrorStatus) {
1754     return;
1755   }
1756   bOk = myTBlock.ComputeParameters(thePnt, theXYZ, aID);
1757   if (!bOk) {
1758     myErrorStatus=4; // problems with computation Parameters 
1759     return;
1760   }
1761 }
1762
1763 //=======================================================================
1764 //function : ComputeParameters
1765 //purpose  : 
1766 //=======================================================================
1767
1768 void StdMeshers_SMESHBlock::ComputeParameters(const double& theU,
1769                                               const TopoDS_Shape& theShape,
1770                                               gp_XYZ& theXYZ)
1771 {
1772   myErrorStatus=0;
1773   //
1774   int aID;
1775   bool bOk=false;
1776   //
1777   aID = ShapeID(theShape);
1778   if (myErrorStatus) {
1779     return;
1780   }
1781   if ( SMESH_Block::IsEdgeID( aID ))
1782       bOk = myTBlock.EdgeParameters( aID, theU, theXYZ );
1783   if (!bOk) {
1784     myErrorStatus=4; // problems with computation Parameters 
1785     return;
1786   }
1787 }
1788
1789 //=======================================================================
1790 //function : Point
1791 //purpose  : 
1792 //=======================================================================
1793  void StdMeshers_SMESHBlock::Point(const gp_XYZ& theParams,
1794                                    gp_Pnt& aP3D)
1795 {
1796   TopoDS_Shape aS;
1797   //
1798   Point(theParams, aS, aP3D);
1799 }
1800
1801 //=======================================================================
1802 //function : Point
1803 //purpose  : 
1804 //=======================================================================
1805  void StdMeshers_SMESHBlock::Point(const gp_XYZ& theParams,
1806                                    const TopoDS_Shape& theShape,
1807                                    gp_Pnt& aP3D)
1808 {
1809   myErrorStatus = 0;
1810   //
1811   int aID;
1812   bool bOk = false;
1813   gp_XYZ aXYZ(99.,99.,99.);
1814   aP3D.SetXYZ(aXYZ);
1815   //
1816   if (theShape.IsNull()) {
1817     bOk = myTBlock.ShellPoint(theParams, aXYZ);
1818   }
1819   //
1820   else {
1821     aID=ShapeID(theShape);
1822     if (myErrorStatus) {
1823       return;
1824     }
1825     //
1826     if (SMESH_Block::IsVertexID(aID)) {
1827       bOk = myTBlock.VertexPoint(aID, aXYZ);
1828     }
1829     else if (SMESH_Block::IsEdgeID(aID)) {
1830       bOk = myTBlock.EdgePoint(aID, theParams, aXYZ);
1831     }
1832     //
1833     else if (SMESH_Block::IsFaceID(aID)) {
1834       bOk = myTBlock.FacePoint(aID, theParams, aXYZ);
1835     }
1836   }
1837   if (!bOk) {
1838     myErrorStatus=5; // problems with point computation 
1839     return;
1840   }
1841   aP3D.SetXYZ(aXYZ);
1842 }
1843
1844 //=======================================================================
1845 //function : ShapeID
1846 //purpose  : 
1847 //=======================================================================
1848 int StdMeshers_SMESHBlock::ShapeID(const TopoDS_Shape& theShape)
1849 {
1850   myErrorStatus=0;
1851   //
1852   int aID=-1;
1853   TopoDS_Shape aSF, aSR;
1854   //
1855   aSF=theShape;
1856   aSF.Orientation(TopAbs_FORWARD);
1857   aSR=theShape;
1858   aSR.Orientation(TopAbs_REVERSED);
1859   //
1860   if (myShapeIDMap.Contains(aSF)) {
1861     aID=myShapeIDMap.FindIndex(aSF);
1862     return aID;
1863   }
1864   if (myShapeIDMap.Contains(aSR)) {
1865     aID=myShapeIDMap.FindIndex(aSR);
1866     return aID;
1867   }
1868   myErrorStatus=2; // unknown shape;
1869   return aID;
1870 }
1871
1872 //=======================================================================
1873 //function : Shape
1874 //purpose  : 
1875 //=======================================================================
1876 const TopoDS_Shape& StdMeshers_SMESHBlock::Shape(const int theID)
1877 {
1878   myErrorStatus=0;
1879   //
1880   int aNb;
1881   //
1882   aNb=myShapeIDMap.Extent();
1883   if (theID<1 || theID>aNb) {
1884     myErrorStatus=3; // ID is out of range
1885     return myEmptyShape;
1886   }
1887   //
1888   const TopoDS_Shape& aS=myShapeIDMap.FindKey(theID);
1889   return aS;
1890 }
1891
1892