Salome HOME
Merge from V6_main 11/02/2013
[modules/smesh.git] / src / StdMeshers / StdMeshers_Prism_3D.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File      : StdMeshers_Prism_3D.cxx
24 // Module    : SMESH
25 // Created   : Fri Oct 20 11:37:07 2006
26 // Author    : Edward AGAPOV (eap)
27 //
28 #include "StdMeshers_Prism_3D.hxx"
29
30 #include "SMDS_EdgePosition.hxx"
31 #include "SMDS_VolumeOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMESH_Comment.hxx"
34 #include "SMESH_Gen.hxx"
35 #include "SMESH_HypoFilter.hxx"
36 #include "SMESH_MesherHelper.hxx"
37 #include "StdMeshers_FaceSide.hxx"
38 #include "StdMeshers_ProjectionSource1D.hxx"
39 #include "StdMeshers_ProjectionSource2D.hxx"
40 #include "StdMeshers_ProjectionUtils.hxx"
41 #include "StdMeshers_Projection_1D.hxx"
42 #include "StdMeshers_Projection_1D2D.hxx"
43 #include "StdMeshers_Quadrangle_2D.hxx"
44
45 #include "utilities.h"
46
47 #include <BRepAdaptor_CompCurve.hxx>
48 #include <BRep_Tool.hxx>
49 #include <Bnd_B3d.hxx>
50 #include <Geom2dAdaptor_Curve.hxx>
51 #include <Geom2d_Line.hxx>
52 #include <Geom_Curve.hxx>
53 #include <TopExp.hxx>
54 #include <TopExp_Explorer.hxx>
55 #include <TopTools_ListIteratorOfListOfShape.hxx>
56 #include <TopTools_ListOfShape.hxx>
57 #include <TopTools_MapOfShape.hxx>
58 #include <TopTools_SequenceOfShape.hxx>
59 #include <TopoDS.hxx>
60 #include <gp_Ax2.hxx>
61 #include <gp_Ax3.hxx>
62
63 using namespace std;
64
65 #define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; }
66 #define gpXYZ(n) gp_XYZ(n->X(),n->Y(),n->Z())
67 #define SHOWYXZ(msg, xyz) // {\
68 // gp_Pnt p (xyz); \
69 // cout << msg << " ("<< p.X() << "; " <<p.Y() << "; " <<p.Z() << ") " <<endl;\
70 // }
71
72 typedef StdMeshers_ProjectionUtils TAssocTool;
73 typedef SMESH_Comment              TCom;
74
75 enum { ID_BOT_FACE = SMESH_Block::ID_Fxy0,
76        ID_TOP_FACE = SMESH_Block::ID_Fxy1,
77        BOTTOM_EDGE = 0, TOP_EDGE, V0_EDGE, V1_EDGE, // edge IDs in face
78        NB_WALL_FACES = 4 }; //
79
80 namespace {
81
82   //=======================================================================
83   /*!
84    * \brief Quadrangle algorithm
85    */
86   struct TQuadrangleAlgo : public StdMeshers_Quadrangle_2D
87   {
88     TQuadrangleAlgo(int studyId, SMESH_Gen* gen)
89       : StdMeshers_Quadrangle_2D( gen->GetANewId(), studyId, gen)
90     {
91     }
92     static StdMeshers_Quadrangle_2D* instance( SMESH_Algo*         fatherAlgo,
93                                                SMESH_MesherHelper* helper=0)
94     {
95       static TQuadrangleAlgo* algo = new TQuadrangleAlgo( fatherAlgo->GetStudyId(),
96                                                           fatherAlgo->GetGen() );
97       if ( helper &&
98            algo->myProxyMesh &&
99            algo->myProxyMesh->GetMesh() != helper->GetMesh() )
100         algo->myProxyMesh.reset( new SMESH_ProxyMesh( *helper->GetMesh() ));
101
102       algo->myQuadStruct.reset();
103
104       if ( helper )
105         algo->_quadraticMesh = helper->GetIsQuadratic();
106
107       return algo;
108     }
109   };
110   //=======================================================================
111   /*!
112    * \brief Algorithm projecting 1D mesh
113    */
114   struct TProjction1dAlgo : public StdMeshers_Projection_1D
115   {
116     StdMeshers_ProjectionSource1D myHyp;
117
118     TProjction1dAlgo(int studyId, SMESH_Gen* gen)
119       : StdMeshers_Projection_1D( gen->GetANewId(), studyId, gen),
120         myHyp( gen->GetANewId(), studyId, gen)
121     {
122       StdMeshers_Projection_1D::_sourceHypo = & myHyp;
123     }
124     static TProjction1dAlgo* instance( SMESH_Algo* fatherAlgo )
125     {
126       static TProjction1dAlgo* algo = new TProjction1dAlgo( fatherAlgo->GetStudyId(),
127                                                             fatherAlgo->GetGen() );
128       return algo;
129     }
130   };
131   //=======================================================================
132   /*!
133    * \brief Algorithm projecting 2D mesh
134    */
135   struct TProjction2dAlgo : public StdMeshers_Projection_1D2D
136   {
137     StdMeshers_ProjectionSource2D myHyp;
138
139     TProjction2dAlgo(int studyId, SMESH_Gen* gen)
140       : StdMeshers_Projection_1D2D( gen->GetANewId(), studyId, gen),
141         myHyp( gen->GetANewId(), studyId, gen)
142     {
143       StdMeshers_Projection_2D::_sourceHypo = & myHyp;
144     }
145     static TProjction2dAlgo* instance( SMESH_Algo* fatherAlgo )
146     {
147       static TProjction2dAlgo* algo = new TProjction2dAlgo( fatherAlgo->GetStudyId(),
148                                                             fatherAlgo->GetGen() );
149       return algo;
150     }
151   };
152
153   //================================================================================
154   /*!
155    * \brief Make \a botE be the BOTTOM_SIDE of \a quad.
156    *        Return false if the BOTTOM_SIDE is composite
157    */
158   //================================================================================
159
160   bool setBottomEdge( const TopoDS_Edge&   botE,
161                       faceQuadStruct::Ptr& quad,
162                       const TopoDS_Shape&  face)
163   {
164     quad->side[ QUAD_TOP_SIDE  ]->Reverse();
165     quad->side[ QUAD_LEFT_SIDE ]->Reverse();
166     int edgeIndex = 0;
167     for ( size_t i = 0; i < quad->side.size(); ++i )
168     {
169       StdMeshers_FaceSide* quadSide = quad->side[i];
170       for ( int iE = 0; iE < quadSide->NbEdges(); ++iE )
171         if ( botE.IsSame( quadSide->Edge( iE )))
172         {
173           if ( quadSide->NbEdges() > 1 )
174             return false;
175           edgeIndex = i;
176           i = quad->side.size(); // to quit from the outer loop
177           break;
178         }
179     }
180     if ( edgeIndex != QUAD_BOTTOM_SIDE )
181       quad->shift( quad->side.size() - edgeIndex, /*keepUnitOri=*/false );
182
183     quad->face = TopoDS::Face( face );
184
185     return true;
186   }
187
188   //================================================================================
189   /*!
190    * \brief Return iterator pointing to node column for the given parameter
191    * \param columnsMap - node column map
192    * \param parameter - parameter
193    * \retval TParam2ColumnMap::iterator - result
194    *
195    * it returns closest left column
196    */
197   //================================================================================
198
199   TParam2ColumnIt getColumn( const TParam2ColumnMap* columnsMap,
200                              const double            parameter )
201   {
202     TParam2ColumnIt u_col = columnsMap->upper_bound( parameter );
203     if ( u_col != columnsMap->begin() )
204       --u_col;
205     return u_col; // return left column
206   }
207
208   //================================================================================
209   /*!
210    * \brief Return nodes around given parameter and a ratio
211    * \param column - node column
212    * \param param - parameter
213    * \param node1 - lower node
214    * \param node2 - upper node
215    * \retval double - ratio
216    */
217   //================================================================================
218
219   double getRAndNodes( const TNodeColumn*     column,
220                        const double           param,
221                        const SMDS_MeshNode* & node1,
222                        const SMDS_MeshNode* & node2)
223   {
224     if ( param >= 1.0 || column->size() == 1) {
225       node1 = node2 = column->back();
226       return 0;
227     }
228
229     int i = int( param * ( column->size() - 1 ));
230     double u0 = double( i )/ double( column->size() - 1 );
231     double r = ( param - u0 ) * ( column->size() - 1 );
232
233     node1 = (*column)[ i ];
234     node2 = (*column)[ i + 1];
235     return r;
236   }
237
238   //================================================================================
239   /*!
240    * \brief Compute boundary parameters of face parts
241     * \param nbParts - nb of parts to split columns into
242     * \param columnsMap - node columns of the face to split
243     * \param params - computed parameters
244    */
245   //================================================================================
246
247   void splitParams( const int               nbParts,
248                     const TParam2ColumnMap* columnsMap,
249                     vector< double > &      params)
250   {
251     params.clear();
252     params.reserve( nbParts + 1 );
253     TParam2ColumnIt last_par_col = --columnsMap->end();
254     double par = columnsMap->begin()->first; // 0.
255     double parLast = last_par_col->first;
256     params.push_back( par );
257     for ( int i = 0; i < nbParts - 1; ++ i )
258     {
259       double partSize = ( parLast - par ) / double ( nbParts - i );
260       TParam2ColumnIt par_col = getColumn( columnsMap, par + partSize );
261       if ( par_col->first == par ) {
262         ++par_col;
263         if ( par_col == last_par_col ) {
264           while ( i < nbParts - 1 )
265             params.push_back( par + partSize * i++ );
266           break;
267         }
268       }
269       par = par_col->first;
270       params.push_back( par );
271     }
272     params.push_back( parLast ); // 1.
273   }
274
275   //================================================================================
276   /*!
277    * \brief Return coordinate system for z-th layer of nodes
278    */
279   //================================================================================
280
281   gp_Ax2 getLayerCoordSys(const int                           z,
282                           const vector< const TNodeColumn* >& columns,
283                           int&                                xColumn)
284   {
285     // gravity center of a layer
286     gp_XYZ O(0,0,0);
287     int vertexCol = -1;
288     for ( int i = 0; i < columns.size(); ++i )
289     {
290       O += gpXYZ( (*columns[ i ])[ z ]);
291       if ( vertexCol < 0 &&
292            columns[ i ]->front()->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
293         vertexCol = i;
294     }
295     O /= columns.size();
296
297     // Z axis
298     gp_Vec Z(0,0,0);
299     int iPrev = columns.size()-1;
300     for ( int i = 0; i < columns.size(); ++i )
301     {
302       gp_Vec v1( O, gpXYZ( (*columns[ iPrev ])[ z ]));
303       gp_Vec v2( O, gpXYZ( (*columns[ i ]    )[ z ]));
304       Z += v1 ^ v2;
305       iPrev = i;
306     }
307
308     if ( vertexCol >= 0 )
309     {
310       O = gpXYZ( (*columns[ vertexCol ])[ z ]);
311     }
312     if ( xColumn < 0 || xColumn >= columns.size() )
313     {
314       // select a column for X dir
315       double maxDist = 0;
316       for ( int i = 0; i < columns.size(); ++i )
317       {
318         double dist = ( O - gpXYZ((*columns[ i ])[ z ])).SquareModulus();
319         if ( dist > maxDist )
320         {
321           xColumn = i;
322           maxDist = dist;
323         }
324       }
325     }
326
327     // X axis
328     gp_Vec X( O, gpXYZ( (*columns[ xColumn ])[ z ]));
329
330     return gp_Ax2( O, Z, X);
331   }
332
333   //================================================================================
334   /*!
335    * \brief Removes submeshes that are or can be meshed with regular grid from given list
336    *  \retval int - nb of removed submeshes
337    */
338   //================================================================================
339
340   int removeQuasiQuads(list< SMESH_subMesh* >&   notQuadSubMesh,
341                        SMESH_MesherHelper*       helper,
342                        StdMeshers_Quadrangle_2D* quadAlgo)
343   {
344     int nbRemoved = 0;
345     //SMESHDS_Mesh* mesh = notQuadSubMesh.front()->GetFather()->GetMeshDS();
346     list< SMESH_subMesh* >::iterator smIt = notQuadSubMesh.begin();
347     while ( smIt != notQuadSubMesh.end() )
348     {
349       SMESH_subMesh* faceSm = *smIt;
350       SMESHDS_SubMesh* faceSmDS = faceSm->GetSubMeshDS();
351       int nbQuads = faceSmDS ? faceSmDS->NbElements() : 0;
352       bool toRemove;
353       if ( nbQuads > 0 )
354         toRemove = helper->IsStructured( faceSm );
355       else
356         toRemove = quadAlgo->CheckNbEdges( *helper->GetMesh(),
357                                            faceSm->GetSubShape() );
358       nbRemoved += toRemove;
359       if ( toRemove )
360         smIt = notQuadSubMesh.erase( smIt );
361       else
362         ++smIt;
363     }
364
365     return nbRemoved;
366   }
367
368 } // namespace
369
370 //=======================================================================
371 //function : StdMeshers_Prism_3D
372 //purpose  : 
373 //=======================================================================
374
375 StdMeshers_Prism_3D::StdMeshers_Prism_3D(int hypId, int studyId, SMESH_Gen* gen)
376   :SMESH_3D_Algo(hypId, studyId, gen)
377 {
378   _name                    = "Prism_3D";
379   _shapeType               = (1 << TopAbs_SOLID); // 1 bit per shape type
380   _onlyUnaryInput          = false; // accept all SOLIDs at once
381   _requireDiscreteBoundary = false; // mesh FACEs and EDGEs by myself
382   _supportSubmeshes        = true;  // "source" FACE must be meshed by other algo
383   _neededLowerHyps[ 1 ]    = true;  // suppress warning on hiding a global 1D algo
384   _neededLowerHyps[ 2 ]    = true;  // suppress warning on hiding a global 2D algo
385
386   //myProjectTriangles       = false;
387   mySetErrorToSM           = true;  // to pass an error to a sub-mesh of a current solid or not
388 }
389
390 //================================================================================
391 /*!
392  * \brief Destructor
393  */
394 //================================================================================
395
396 StdMeshers_Prism_3D::~StdMeshers_Prism_3D()
397 {}
398
399 //=======================================================================
400 //function : CheckHypothesis
401 //purpose  : 
402 //=======================================================================
403
404 bool StdMeshers_Prism_3D::CheckHypothesis(SMESH_Mesh&                          aMesh,
405                                           const TopoDS_Shape&                  aShape,
406                                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
407 {
408   // Check shape geometry
409 /*  PAL16229
410   aStatus = SMESH_Hypothesis::HYP_BAD_GEOMETRY;
411
412   // find not quadrangle faces
413   list< TopoDS_Shape > notQuadFaces;
414   int nbEdge, nbWire, nbFace = 0;
415   TopExp_Explorer exp( aShape, TopAbs_FACE );
416   for ( ; exp.More(); exp.Next() ) {
417     ++nbFace;
418     const TopoDS_Shape& face = exp.Current();
419     nbEdge = TAssocTool::Count( face, TopAbs_EDGE, 0 );
420     nbWire = TAssocTool::Count( face, TopAbs_WIRE, 0 );
421     if (  nbEdge!= 4 || nbWire!= 1 ) {
422       if ( !notQuadFaces.empty() ) {
423         if ( TAssocTool::Count( notQuadFaces.back(), TopAbs_EDGE, 0 ) != nbEdge ||
424              TAssocTool::Count( notQuadFaces.back(), TopAbs_WIRE, 0 ) != nbWire )
425           RETURN_BAD_RESULT("Different not quad faces");
426       }
427       notQuadFaces.push_back( face );
428     }
429   }
430   if ( !notQuadFaces.empty() )
431   {
432     if ( notQuadFaces.size() != 2 )
433       RETURN_BAD_RESULT("Bad nb not quad faces: " << notQuadFaces.size());
434
435     // check total nb faces
436     nbEdge = TAssocTool::Count( notQuadFaces.back(), TopAbs_EDGE, 0 );
437     if ( nbFace != nbEdge + 2 )
438       RETURN_BAD_RESULT("Bad nb of faces: " << nbFace << " but must be " << nbEdge + 2);
439   }
440 */
441   // no hypothesis
442   aStatus = SMESH_Hypothesis::HYP_OK;
443   return true;
444 }
445
446 //=======================================================================
447 //function : Compute
448 //purpose  : Compute mesh on a COMPOUND of SOLIDs
449 //=======================================================================
450
451 bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape)
452 {
453   SMESH_MesherHelper helper( theMesh );
454   myHelper = &helper;
455
456   int nbSolids = helper.Count( theShape, TopAbs_SOLID, /*skipSame=*/false );
457   if ( nbSolids < 1 )
458     return true;
459
460   Prism_3D::TPrismTopo prism;
461
462   if ( nbSolids == 1 )
463   {
464     return ( initPrism( prism, TopExp_Explorer( theShape, TopAbs_SOLID ).Current() ) &&
465              compute( prism ));
466   }
467
468   TopTools_IndexedDataMapOfShapeListOfShape faceToSolids;
469   TopExp::MapShapesAndAncestors( theShape, TopAbs_FACE, TopAbs_SOLID, faceToSolids );
470
471   // look for meshed FACEs ("source" FACEs) that must be prism bottoms
472   list< TopoDS_Face > meshedFaces;//, notQuadMeshedFaces, notQuadFaces;
473   const bool meshHasQuads = ( theMesh.NbQuadrangles() > 0 );
474   for ( int iF = 1; iF < faceToSolids.Extent(); ++iF )
475   {
476     const TopoDS_Face& face = TopoDS::Face( faceToSolids.FindKey( iF ));
477     SMESH_subMesh*   faceSM = theMesh.GetSubMesh( face );
478     if ( !faceSM->IsEmpty() )
479     {
480       if ( !meshHasQuads ||
481            !helper.IsSameElemGeometry( faceSM->GetSubMeshDS(), SMDSGeom_QUADRANGLE ) ||
482            !helper.IsStructured( faceSM ))
483         // notQuadMeshedFaces are of higher priority
484         meshedFaces.push_front( face );
485       else
486         meshedFaces.push_back( face );
487     }
488   }
489   //meshedFaces.splice( meshedFaces.begin(), notQuadMeshedFaces );
490
491   // if ( meshedFaces.empty() )
492   //   return error( COMPERR_BAD_INPUT_MESH, "No meshed source faces found" );
493
494   TopTools_MapOfShape meshedSolids;
495   list< Prism_3D::TPrismTopo > meshedPrism;
496   TopTools_ListIteratorOfListOfShape solidIt;
497
498   while ( meshedSolids.Extent() < nbSolids )
499   {
500     if ( _computeCanceled )
501       return toSM( error( SMESH_ComputeError::New(COMPERR_CANCELED)));
502
503     // compute prisms having avident computed source FACE
504     while ( !meshedFaces.empty() )
505     {
506       TopoDS_Face face = meshedFaces.front();
507       meshedFaces.pop_front();
508       TopTools_ListOfShape& solidList = faceToSolids.ChangeFromKey( face );
509       while ( !solidList.IsEmpty() )
510       {
511         TopoDS_Shape solid = solidList.First();
512         solidList.RemoveFirst();
513         if ( meshedSolids.Add( solid ))
514         {
515           prism.Clear();
516           prism.myBottom = face;
517           if ( !initPrism( prism, solid ) ||
518                !compute( prism ))
519             return false;
520
521           meshedFaces.push_front( prism.myTop );
522           meshedPrism.push_back( prism );
523         }
524       }
525     }
526     if ( meshedSolids.Extent() == nbSolids )
527       break;
528
529     // below in the loop we try to find source FACEs somehow
530
531     // project mesh from source FACEs of computed prisms to
532     // prisms sharing wall FACEs
533     list< Prism_3D::TPrismTopo >::iterator prismIt = meshedPrism.begin();
534     for ( ; prismIt != meshedPrism.end(); ++prismIt )
535     {
536       for ( size_t iW = 0; iW < prismIt->myWallQuads.size(); ++iW )
537       {
538         Prism_3D::TQuadList::iterator wQuad = prismIt->myWallQuads[iW].begin();
539         for ( ; wQuad != prismIt->myWallQuads[iW].end(); ++ wQuad )
540         {
541           const TopoDS_Face& wFace = (*wQuad)->face;
542           TopTools_ListOfShape& solidList = faceToSolids.ChangeFromKey( wFace );
543           solidIt.Initialize( solidList );
544           while ( solidIt.More() )
545           {
546             const TopoDS_Shape& solid = solidIt.Value();
547             if ( meshedSolids.Contains( solid )) {
548               solidList.Remove( solidIt );
549               continue; // already computed prism
550             }
551             // find a source FACE of the SOLID: it's a FACE sharing a bottom EDGE with wFace
552             const TopoDS_Edge& wEdge = (*wQuad)->side[ QUAD_TOP_SIDE ]->Edge(0);
553             PShapeIteratorPtr faceIt = myHelper->GetAncestors( wEdge, *myHelper->GetMesh(),
554                                                                TopAbs_FACE);
555             while ( const TopoDS_Shape* f = faceIt->next() )
556             {
557               const TopoDS_Face& candidateF = TopoDS::Face( *f );
558               prism.Clear();
559               prism.myBottom  = candidateF;
560               mySetErrorToSM = false;
561               if ( !myHelper->IsSubShape( candidateF, prismIt->myShape3D ) &&
562                    !myHelper->GetMesh()->GetSubMesh( candidateF )->IsMeshComputed() &&
563                    initPrism( prism, solid ) &&
564                    project2dMesh( prismIt->myBottom, candidateF))
565               {
566                 mySetErrorToSM = true;
567                 if ( !compute( prism ))
568                   return false;
569                 meshedFaces.push_front( prism.myTop );
570                 meshedFaces.push_front( prism.myBottom );
571                 meshedPrism.push_back( prism );
572                 meshedSolids.Add( solid );
573               }
574               InitComputeError();
575             }
576             mySetErrorToSM = true;
577             InitComputeError();
578             if ( meshedSolids.Contains( solid ))
579               solidList.Remove( solidIt );
580             else
581               solidIt.Next();
582           }
583         }
584       }
585       if ( !meshedFaces.empty() )
586         break; // to compute prisms with avident sources
587     }
588
589     // find FACEs with local 1D hyps, which has to be computed by now,
590     // or at least any computed FACEs
591     for ( int iF = 1; ( meshedFaces.empty() && iF < faceToSolids.Extent() ); ++iF )
592     {
593       const TopoDS_Face&               face = TopoDS::Face( faceToSolids.FindKey( iF ));
594       const TopTools_ListOfShape& solidList = faceToSolids.FindFromKey( face );
595       if ( solidList.IsEmpty() ) continue;
596       SMESH_subMesh*                 faceSM = theMesh.GetSubMesh( face );
597       if ( !faceSM->IsEmpty() )
598       {
599         meshedFaces.push_back( face ); // lower priority
600       }
601       else
602       {
603         bool allSubMeComputed = true;
604         SMESH_subMeshIteratorPtr smIt = faceSM->getDependsOnIterator(false,true);
605         while ( smIt->more() && allSubMeComputed )
606           allSubMeComputed = smIt->next()->IsMeshComputed();
607         if ( allSubMeComputed )
608         {
609           faceSM->ComputeStateEngine( SMESH_subMesh::COMPUTE );
610           if ( !faceSM->IsEmpty() )
611             meshedFaces.push_front( face ); // higher priority
612           else
613             faceSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
614         }
615       }
616     }
617
618
619     // TODO. there are other ways to find out the source FACE:
620     // propagation, topological similarity, ect.
621
622
623     if ( meshedFaces.empty() ) // set same error to 10 not-computed solids
624     {
625       SMESH_ComputeErrorPtr err = SMESH_ComputeError::New
626         ( COMPERR_BAD_INPUT_MESH, "No meshed source face found", this );
627
628       const int maxNbErrors = 10; // limit nb errors not to overload the Compute dialog
629       TopExp_Explorer solid( theShape, TopAbs_SOLID );
630       for ( int i = 0; ( i < maxNbErrors && solid.More() ); ++i, solid.Next() )
631         if ( !meshedSolids.Contains( solid.Current() ))
632         {
633           SMESH_subMesh* sm = theMesh.GetSubMesh( solid.Current() );
634           sm->GetComputeError() = err;
635         }
636       return false;
637     }
638   }
639   return true;
640 }
641
642 //================================================================================
643 /*!
644  * \brief Find wall faces by bottom edges
645  */
646 //================================================================================
647
648 bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism,
649                                         const int              totalNbFaces)
650 {
651   thePrism.myWallQuads.clear();
652
653   SMESH_Mesh* mesh = myHelper->GetMesh();
654
655   StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this, myHelper );
656
657   TopTools_MapOfShape faceMap;
658   TopTools_IndexedDataMapOfShapeListOfShape edgeToFaces;   
659   TopExp::MapShapesAndAncestors( thePrism.myShape3D,
660                                  TopAbs_EDGE, TopAbs_FACE, edgeToFaces );
661
662   // ------------------------------
663   // Get the 1st row of wall FACEs
664   // ------------------------------
665
666   list< TopoDS_Edge >::iterator edge = thePrism.myBottomEdges.begin();
667   std::list< int >::iterator     nbE = thePrism.myNbEdgesInWires.begin();
668   int iE = 0;
669   while ( edge != thePrism.myBottomEdges.end() )
670   {
671     ++iE;
672     if ( BRep_Tool::Degenerated( *edge ))
673     {
674       edge = thePrism.myBottomEdges.erase( edge );
675       --iE;
676       --(*nbE);
677     }
678     else
679     {
680       TopTools_ListIteratorOfListOfShape faceIt( edgeToFaces.FindFromKey( *edge ));
681       for ( ; faceIt.More(); faceIt.Next() )
682       {
683         const TopoDS_Face& face = TopoDS::Face( faceIt.Value() );
684         if ( !thePrism.myBottom.IsSame( face ))
685         {
686           Prism_3D::TQuadList quadList( 1, quadAlgo->CheckNbEdges( *mesh, face ));
687           if ( !quadList.back() )
688             return toSM( error(TCom("Side face #") << shapeID( face )
689                                << " not meshable with quadrangles"));
690           if ( ! setBottomEdge( *edge, quadList.back(), face ))
691             return toSM( error(TCom("Composite 'horizontal' edges are not supported")));
692           thePrism.myWallQuads.push_back( quadList );
693           faceMap.Add( face );
694           break;
695         }
696       }
697       ++edge;
698     }
699     if ( iE == *nbE )
700     {
701       iE = 0;
702       ++nbE;
703     }
704   }
705
706   // -------------------------
707   // Find the rest wall FACEs
708   // -------------------------
709
710   // Compose a vector of indixes of right neighbour FACE for each wall FACE
711   // that is not so evident in case of several WIREs
712   thePrism.myRightQuadIndex.clear();
713   for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i )
714     thePrism.myRightQuadIndex.push_back( i+1 );
715   list< int >::iterator nbEinW = thePrism.myNbEdgesInWires.begin();
716   for ( int iLeft = 0; nbEinW != thePrism.myNbEdgesInWires.end(); ++nbEinW )
717   {
718     thePrism.myRightQuadIndex[ iLeft + *nbEinW - 1 ] = iLeft; // 1st EDGE index of a current WIRE
719     iLeft += *nbEinW;
720   }
721
722   while ( totalNbFaces - faceMap.Extent() > 2 )
723   {
724     // find wall FACEs adjacent to each of wallQuads by the right side EDGE
725     int nbKnownFaces;
726     do {
727       nbKnownFaces = faceMap.Extent();
728       StdMeshers_FaceSide *rightSide, *topSide; // sides of the quad
729       for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i )
730       {
731         rightSide = thePrism.myWallQuads[i].back()->side[ QUAD_RIGHT_SIDE ];
732         for ( int iE = 0; iE < rightSide->NbEdges(); ++iE ) // rightSide can be composite
733         {
734           const TopoDS_Edge & rightE = rightSide->Edge( iE );
735           TopTools_ListIteratorOfListOfShape face( edgeToFaces.FindFromKey( rightE ));
736           for ( ; face.More(); face.Next() )
737             if ( faceMap.Add( face.Value() ))
738             {
739               // a new wall FACE encountered, store it in thePrism.myWallQuads
740               const int iRight = thePrism.myRightQuadIndex[i];
741               topSide = thePrism.myWallQuads[ iRight ].back()->side[ QUAD_TOP_SIDE ];
742               const TopoDS_Edge&   newBotE = topSide->Edge(0);
743               const TopoDS_Shape& newWallF = face.Value();
744               thePrism.myWallQuads[ iRight ].push_back( quadAlgo->CheckNbEdges( *mesh, newWallF ));
745               if ( !thePrism.myWallQuads[ iRight ].back() )
746                 return toSM( error(TCom("Side face #") << shapeID( newWallF ) <<
747                                    " not meshable with quadrangles"));
748               if ( ! setBottomEdge( newBotE, thePrism.myWallQuads[ iRight ].back(), newWallF ))
749                 return toSM( error(TCom("Composite 'horizontal' edges are not supported")));
750             }
751         }
752       }
753     } while ( nbKnownFaces != faceMap.Extent() );
754
755     // find wall FACEs adjacent to each of thePrism.myWallQuads by the top side EDGE
756     if ( totalNbFaces - faceMap.Extent() > 2 )
757     {
758       for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i )
759       {
760         StdMeshers_FaceSide* topSide = thePrism.myWallQuads[i].back()->side[ QUAD_TOP_SIDE ];
761         const TopoDS_Edge &     topE = topSide->Edge( 0 );
762         if ( topSide->NbEdges() > 1 )
763           return toSM( error(COMPERR_BAD_SHAPE, TCom("Side face #") <<
764                              shapeID( thePrism.myWallQuads[i].back()->face )
765                              << " has a composite top edge"));
766         TopTools_ListIteratorOfListOfShape faceIt( edgeToFaces.FindFromKey( topE ));
767         for ( ; faceIt.More(); faceIt.Next() )
768           if ( faceMap.Add( faceIt.Value() ))
769           {
770             // a new wall FACE encountered, store it in wallQuads
771             thePrism.myWallQuads[ i ].push_back( quadAlgo->CheckNbEdges( *mesh, faceIt.Value() ));
772             if ( !thePrism.myWallQuads[ i ].back() )
773               return toSM( error(TCom("Side face #") << shapeID( faceIt.Value() ) <<
774                                  " not meshable with quadrangles"));
775             if ( ! setBottomEdge( topE, thePrism.myWallQuads[ i ].back(), faceIt.Value() ))
776               return toSM( error(TCom("Composite 'horizontal' edges are not supported")));
777             if ( totalNbFaces - faceMap.Extent() == 2 )
778             {
779               i = thePrism.myWallQuads.size(); // to quit from the outer loop
780               break;
781             }
782           }
783       }
784     }
785   } // while ( totalNbFaces - faceMap.Extent() > 2 )
786
787   // ------------------
788   // Find the top FACE
789   // ------------------
790
791   if ( thePrism.myTop.IsNull() )
792   {
793     // now only top and bottom FACEs are not in the faceMap
794     faceMap.Add( thePrism.myBottom );
795     for ( TopExp_Explorer f( thePrism.myShape3D, TopAbs_FACE );f.More(); f.Next() )
796       if ( !faceMap.Contains( f.Current() )) {
797         thePrism.myTop = TopoDS::Face( f.Current() );
798         break;
799       }
800     if ( thePrism.myTop.IsNull() )
801       return toSM( error("Top face not found"));
802   }
803
804   // Check that the top FACE shares all the top EDGEs
805   for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i )
806   {
807     StdMeshers_FaceSide* topSide = thePrism.myWallQuads[i].back()->side[ QUAD_TOP_SIDE ];
808     const TopoDS_Edge &     topE = topSide->Edge( 0 );
809     if ( !myHelper->IsSubShape( topE, thePrism.myTop ))
810       return toSM( error( TCom("Wrong source face (#") << shapeID( thePrism.myBottom )));
811   }
812
813   return true;
814 }
815
816 //=======================================================================
817 //function : compute
818 //purpose  : Compute mesh on a SOLID
819 //=======================================================================
820
821 bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism)
822 {
823   myHelper->IsQuadraticSubMesh( thePrism.myShape3D );
824   if ( _computeCanceled )
825     return toSM( error( SMESH_ComputeError::New(COMPERR_CANCELED)));
826
827   // Make all side FACEs of thePrism meshed with quads
828   if ( !computeWalls( thePrism ))
829     return false;
830
831   // Analyse mesh and geometry to find block sub-shapes and submeshes
832   if ( !myBlock.Init( myHelper, thePrism ))
833     return toSM( error( myBlock.GetError()));
834
835   SMESHDS_Mesh* meshDS = myHelper->GetMeshDS();
836
837   int volumeID = meshDS->ShapeToIndex( thePrism.myShape3D );
838
839
840   // To compute coordinates of a node inside a block, it is necessary to know
841   // 1. normalized parameters of the node by which
842   // 2. coordinates of node projections on all block sub-shapes are computed
843
844   // So we fill projections on vertices at once as they are same for all nodes
845   myShapeXYZ.resize( myBlock.NbSubShapes() );
846   for ( int iV = SMESH_Block::ID_FirstV; iV < SMESH_Block::ID_FirstE; ++iV ) {
847     myBlock.VertexPoint( iV, myShapeXYZ[ iV ]);
848     SHOWYXZ("V point " <<iV << " ", myShapeXYZ[ iV ]);
849   }
850
851   // Projections on the top and bottom faces are taken from nodes existing
852   // on these faces; find correspondence between bottom and top nodes
853   myBotToColumnMap.clear();
854   if ( !assocOrProjBottom2Top() ) // it also fills myBotToColumnMap
855     return false;
856
857
858   // Create nodes inside the block
859
860   // try to use transformation (issue 0020680)
861   vector<gp_Trsf> trsf;
862   if ( myBlock.GetLayersTransformation( trsf, thePrism ))
863   {
864     // loop on nodes inside the bottom face
865     TNode2ColumnMap::iterator bot_column = myBotToColumnMap.begin();
866     for ( ; bot_column != myBotToColumnMap.end(); ++bot_column )
867     {
868       const Prism_3D::TNode& tBotNode = bot_column->first; // bottom TNode
869       if ( tBotNode.GetPositionType() != SMDS_TOP_FACE )
870         continue; // node is not inside face 
871
872       // column nodes; middle part of the column are zero pointers
873       TNodeColumn& column = bot_column->second;
874       TNodeColumn::iterator columnNodes = column.begin();
875       for ( int z = 0; columnNodes != column.end(); ++columnNodes, ++z)
876       {
877         const SMDS_MeshNode* & node = *columnNodes;
878         if ( node ) continue; // skip bottom or top node
879
880         gp_XYZ coords = tBotNode.GetCoords();
881         trsf[z-1].Transforms( coords );
882         node = meshDS->AddNode( coords.X(), coords.Y(), coords.Z() );
883         meshDS->SetNodeInVolume( node, volumeID );
884       }
885     } // loop on bottom nodes
886   }
887   else // use block approach
888   {
889     // loop on nodes inside the bottom face
890     Prism_3D::TNode prevBNode;
891     TNode2ColumnMap::iterator bot_column = myBotToColumnMap.begin();
892     for ( ; bot_column != myBotToColumnMap.end(); ++bot_column )
893     {
894       const Prism_3D::TNode& tBotNode = bot_column->first; // bottom TNode
895       if ( tBotNode.GetPositionType() != SMDS_TOP_FACE )
896         continue; // node is not inside face 
897
898       // column nodes; middle part of the column are zero pointers
899       TNodeColumn& column = bot_column->second;
900
901       // compute bottom node parameters
902       gp_XYZ paramHint(-1,-1,-1);
903       if ( prevBNode.IsNeighbor( tBotNode ))
904         paramHint = prevBNode.GetParams();
905       if ( !myBlock.ComputeParameters( tBotNode.GetCoords(), tBotNode.ChangeParams(),
906                                        ID_BOT_FACE, paramHint ))
907         return toSM( error(TCom("Can't compute normalized parameters for node ")
908                            << tBotNode.myNode->GetID() << " on the face #"
909                            << myBlock.SubMesh( ID_BOT_FACE )->GetId() ));
910       prevBNode = tBotNode;
911
912       myShapeXYZ[ ID_BOT_FACE ] = tBotNode.GetCoords();
913       gp_XYZ botParams          = tBotNode.GetParams();
914
915       // compute top node parameters
916       myShapeXYZ[ ID_TOP_FACE ] = gpXYZ( column.back() );
917       gp_XYZ topParams = botParams;
918       topParams.SetZ( 1 );
919       if ( column.size() > 2 ) {
920         gp_Pnt topCoords = myShapeXYZ[ ID_TOP_FACE ];
921         if ( !myBlock.ComputeParameters( topCoords, topParams, ID_TOP_FACE, topParams ))
922           return toSM( error(TCom("Can't compute normalized parameters ")
923                              << "for node " << column.back()->GetID()
924                              << " on the face #"<< column.back()->getshapeId() ));
925       }
926
927       // vertical loop
928       TNodeColumn::iterator columnNodes = column.begin();
929       for ( int z = 0; columnNodes != column.end(); ++columnNodes, ++z)
930       {
931         const SMDS_MeshNode* & node = *columnNodes;
932         if ( node ) continue; // skip bottom or top node
933
934         // params of a node to create
935         double rz = (double) z / (double) ( column.size() - 1 );
936         gp_XYZ params = botParams * ( 1 - rz ) + topParams * rz;
937
938         // set coords on all faces and nodes
939         const int nbSideFaces = 4;
940         int sideFaceIDs[nbSideFaces] = { SMESH_Block::ID_Fx0z,
941                                          SMESH_Block::ID_Fx1z,
942                                          SMESH_Block::ID_F0yz,
943                                          SMESH_Block::ID_F1yz };
944         for ( int iF = 0; iF < nbSideFaces; ++iF )
945           if ( !setFaceAndEdgesXYZ( sideFaceIDs[ iF ], params, z ))
946             return false;
947
948         // compute coords for a new node
949         gp_XYZ coords;
950         if ( !SMESH_Block::ShellPoint( params, myShapeXYZ, coords ))
951           return toSM( error("Can't compute coordinates by normalized parameters"));
952
953         SHOWYXZ("TOPFacePoint ",myShapeXYZ[ ID_TOP_FACE]);
954         SHOWYXZ("BOT Node "<< tBotNode.myNode->GetID(),gpXYZ(tBotNode.myNode));
955         SHOWYXZ("ShellPoint ",coords);
956
957         // create a node
958         node = meshDS->AddNode( coords.X(), coords.Y(), coords.Z() );
959         meshDS->SetNodeInVolume( node, volumeID );
960       }
961     } // loop on bottom nodes
962   }
963
964   // Create volumes
965
966   SMESHDS_SubMesh* smDS = myBlock.SubMeshDS( ID_BOT_FACE );
967   if ( !smDS ) return toSM( error(COMPERR_BAD_INPUT_MESH, "Null submesh"));
968
969   // loop on bottom mesh faces
970   SMDS_ElemIteratorPtr faceIt = smDS->GetElements();
971   while ( faceIt->more() )
972   {
973     const SMDS_MeshElement* face = faceIt->next();
974     if ( !face || face->GetType() != SMDSAbs_Face )
975       continue;
976
977     // find node columns for each node
978     int nbNodes = face->NbCornerNodes();
979     vector< const TNodeColumn* > columns( nbNodes );
980     for ( int i = 0; i < nbNodes; ++i )
981     {
982       const SMDS_MeshNode* n = face->GetNode( i );
983       if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) {
984         TNode2ColumnMap::iterator bot_column = myBotToColumnMap.find( n );
985         if ( bot_column == myBotToColumnMap.end() )
986           return toSM( error(TCom("No nodes found above node ") << n->GetID() ));
987         columns[ i ] = & bot_column->second;
988       }
989       else {
990         columns[ i ] = myBlock.GetNodeColumn( n );
991         if ( !columns[ i ] )
992           return toSM( error(TCom("No side nodes found above node ") << n->GetID() ));
993       }
994     }
995     // create prisms
996     AddPrisms( columns, myHelper );
997
998   } // loop on bottom mesh faces
999
1000   // clear data
1001   myBotToColumnMap.clear();
1002   myBlock.Clear();
1003         
1004   return true;
1005 }
1006
1007 //=======================================================================
1008 //function : computeWalls
1009 //purpose  : Compute 2D mesh on walls FACEs of a prism
1010 //=======================================================================
1011
1012 bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism)
1013 {
1014   SMESH_Mesh*     mesh = myHelper->GetMesh();
1015   SMESHDS_Mesh* meshDS = myHelper->GetMeshDS();
1016
1017   TProjction1dAlgo* projector1D = TProjction1dAlgo::instance( this );
1018   StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this, myHelper );
1019
1020   SMESH_HypoFilter hyp1dFilter( SMESH_HypoFilter::IsAlgo(),/*not=*/true);
1021   hyp1dFilter.And( SMESH_HypoFilter::HasDim( 1 ));
1022   hyp1dFilter.And( SMESH_HypoFilter::IsMoreLocalThan( thePrism.myShape3D, *mesh ));
1023
1024   // Discretize equally 'vertical' EDGEs
1025   // -----------------------------------
1026   // find source FACE sides for projection: either already computed ones or
1027   // the 'most composite' ones
1028   multimap< int, int > wgt2quad;
1029   for ( size_t iW = 0; iW != thePrism.myWallQuads.size(); ++iW )
1030   {
1031     Prism_3D::TQuadList::const_iterator quad = thePrism.myWallQuads[iW].begin();
1032     int wgt = 0; // "weight"
1033     for ( ; quad != thePrism.myWallQuads[iW].end(); ++quad )
1034     {
1035       StdMeshers_FaceSide* lftSide = (*quad)->side[ QUAD_LEFT_SIDE ];
1036       for ( int i = 0; i < lftSide->NbEdges(); ++i )
1037       {
1038         ++wgt;
1039         const TopoDS_Edge& E = lftSide->Edge(i);
1040         if ( mesh->GetSubMesh( E )->IsMeshComputed() )
1041           wgt += 10;
1042         else if ( mesh->GetHypothesis( E, hyp1dFilter, true )) // local hypothesis!
1043           wgt += 100;
1044       }
1045     }
1046     wgt2quad.insert( make_pair( wgt, iW ));
1047
1048     // in quadratic mesh, pass ignoreMediumNodes to quad sides
1049     if ( myHelper->GetIsQuadratic() )
1050     {
1051       quad = thePrism.myWallQuads[iW].begin();
1052       for ( ; quad != thePrism.myWallQuads[iW].end(); ++quad )
1053         for ( int i = 0; i < NB_QUAD_SIDES; ++i )
1054           (*quad)->side[ i ]->SetIgnoreMediumNodes( true );
1055     }
1056   }
1057
1058   // Project 'vertical' EDGEs, from left to right
1059   multimap< int, int >::reverse_iterator w2q = wgt2quad.rbegin();
1060   for ( ; w2q != wgt2quad.rend(); ++w2q )
1061   {
1062     const int iW = w2q->second;
1063     const Prism_3D::TQuadList&         quads = thePrism.myWallQuads[ iW ];
1064     Prism_3D::TQuadList::const_iterator quad = quads.begin();
1065     for ( ; quad != quads.end(); ++quad )
1066     {
1067       StdMeshers_FaceSide* rgtSide = (*quad)->side[ QUAD_RIGHT_SIDE ]; // tgt
1068       StdMeshers_FaceSide* lftSide = (*quad)->side[ QUAD_LEFT_SIDE ];  // src
1069       bool swapLeftRight = ( lftSide->NbSegments( /*update=*/true ) == 0 &&
1070                              rgtSide->NbSegments( /*update=*/true )  > 0 );
1071       if ( swapLeftRight )
1072         std::swap( lftSide, rgtSide );
1073
1074       // assure that all the source (left) EDGEs are meshed
1075       int nbSrcSegments = 0;
1076       for ( int i = 0; i < lftSide->NbEdges(); ++i )
1077       {
1078         const TopoDS_Edge& srcE = lftSide->Edge(i);
1079         SMESH_subMesh*    srcSM = mesh->GetSubMesh( srcE );
1080         if ( !srcSM->IsMeshComputed() ) {
1081           srcSM->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE );
1082           srcSM->ComputeStateEngine       ( SMESH_subMesh::COMPUTE );
1083           if ( !srcSM->IsMeshComputed() )
1084             return false;
1085         }
1086         nbSrcSegments += srcSM->GetSubMeshDS()->NbElements();
1087       }
1088       // check target EDGEs
1089       int nbTgtMeshed = 0, nbTgtSegments = 0;
1090       vector< bool > isTgtEdgeComputed( rgtSide->NbEdges() );
1091       for ( int i = 0; i < rgtSide->NbEdges(); ++i )
1092       {
1093         const TopoDS_Edge& tgtE = rgtSide->Edge(i);
1094         SMESH_subMesh*    tgtSM = mesh->GetSubMesh( tgtE );
1095         if (( isTgtEdgeComputed[ i ] = tgtSM->IsMeshComputed() )) {
1096           ++nbTgtMeshed;
1097           nbTgtSegments += tgtSM->GetSubMeshDS()->NbElements();
1098         }
1099       }
1100       if ( rgtSide->NbEdges() == nbTgtMeshed ) // all tgt EDGEs meshed
1101       {
1102         if ( nbTgtSegments != nbSrcSegments )
1103         {
1104           for ( int i = 0; i < lftSide->NbEdges(); ++i )
1105             addBadInputElements( meshDS->MeshElements( lftSide->Edge( i )));
1106           for ( int i = 0; i < rgtSide->NbEdges(); ++i )
1107             addBadInputElements( meshDS->MeshElements( rgtSide->Edge( i )));
1108           return toSM( error( TCom("Different nb of segment on logically vertical edges #")
1109                               << shapeID( lftSide->Edge(0) ) << " and #"
1110                               << shapeID( rgtSide->Edge(0) ) << ": "
1111                               << nbSrcSegments << " != " << nbTgtSegments ));
1112         }
1113         continue;
1114       }
1115       // Compute
1116       if ( nbTgtMeshed == 0 )
1117       {
1118         // compute nodes on target VERTEXes
1119         const UVPtStructVec&  srcNodeStr = lftSide->GetUVPtStruct();
1120         if ( srcNodeStr.size() == 0 )
1121           return toSM( error( TCom("Invalid node positions on edge #") <<
1122                               shapeID( lftSide->Edge(0) )));
1123         vector< SMDS_MeshNode* > newNodes( srcNodeStr.size() );
1124         for ( int is2ndV = 0; is2ndV < 2; ++is2ndV )
1125         {
1126           const TopoDS_Edge& E = rgtSide->Edge( is2ndV ? rgtSide->NbEdges()-1 : 0 );
1127           TopoDS_Vertex      v = myHelper->IthVertex( is2ndV, E );
1128           mesh->GetSubMesh( v )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
1129           const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, meshDS );
1130           newNodes[ is2ndV ? 0 : newNodes.size()-1 ] = (SMDS_MeshNode*) n;
1131         }
1132
1133         // compute nodes on target EDGEs
1134         rgtSide->Reverse(); // direct it same as the lftSide
1135         myHelper->SetElementsOnShape( false );
1136         TopoDS_Edge tgtEdge;
1137         for ( size_t iN = 1; iN < srcNodeStr.size()-1; ++iN ) // add nodes
1138         {
1139           gp_Pnt       p = rgtSide->Value3d  ( srcNodeStr[ iN ].normParam );
1140           double       u = rgtSide->Parameter( srcNodeStr[ iN ].normParam, tgtEdge );
1141           newNodes[ iN ] = meshDS->AddNode( p.X(), p.Y(), p.Z() );
1142           meshDS->SetNodeOnEdge( newNodes[ iN ], tgtEdge, u );
1143         }
1144         for ( size_t iN = 1; iN < srcNodeStr.size(); ++iN ) // add segments
1145         {
1146           SMDS_MeshElement* newEdge = myHelper->AddEdge( newNodes[ iN-1 ], newNodes[ iN ] );
1147           std::pair<int, TopAbs_ShapeEnum> id2type = 
1148             myHelper->GetMediumPos( newNodes[ iN-1 ], newNodes[ iN ] );
1149           if ( id2type.second == TopAbs_EDGE )
1150           {
1151             meshDS->SetMeshElementOnShape( newEdge, id2type.first );
1152           }
1153           else // new nodes are on different EDGEs; put one of them on VERTEX
1154           {
1155             const int      edgeIndex = rgtSide->EdgeIndex( srcNodeStr[ iN-1 ].normParam );
1156             const double vertexParam = rgtSide->LastParameter( edgeIndex );
1157             const gp_Pnt           p = BRep_Tool::Pnt( rgtSide->LastVertex( edgeIndex ));
1158             const int         isPrev = ( Abs( srcNodeStr[ iN-1 ].normParam - vertexParam ) <
1159                                          Abs( srcNodeStr[ iN   ].normParam - vertexParam ));
1160             meshDS->SetMeshElementOnShape( newEdge, newNodes[ iN-(1-isPrev) ]->getshapeId() );
1161             meshDS->UnSetNodeOnShape( newNodes[ iN-isPrev ] );
1162             meshDS->SetNodeOnVertex ( newNodes[ iN-isPrev ], rgtSide->LastVertex( edgeIndex ));
1163             meshDS->MoveNode( newNodes[ iN-isPrev ], p.X(), p.Y(), p.Z() );
1164           }
1165         }
1166         myHelper->SetElementsOnShape( true );
1167         for ( int i = 0; i < rgtSide->NbEdges(); ++i ) // update state of sub-meshes
1168         {
1169           const TopoDS_Edge& E = rgtSide->Edge( i );
1170           SMESH_subMesh* tgtSM = mesh->GetSubMesh( E );
1171           tgtSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
1172         }
1173
1174         // to continue projection from the just computed side as a source
1175         if ( !swapLeftRight && rgtSide->NbEdges() > 1 && w2q->second == iW )
1176         {
1177           std::pair<int,int> wgt2quadKeyVal( w2q->first + 1, thePrism.myRightQuadIndex[ iW ]);
1178           wgt2quad.insert( wgt2quadKeyVal ); // it will be skipped by ++w2q
1179           wgt2quad.insert( wgt2quadKeyVal );
1180           w2q = wgt2quad.rbegin();
1181         }
1182       }
1183       else
1184       {
1185         // HOPE assigned hypotheses are OK, so that equal nb of segments will be generated
1186         //return toSM( error("Partial projection not implemented"));
1187       }
1188     } // loop on quads of a composite wall side
1189   } // loop on the ordered wall sides
1190
1191
1192
1193   for ( size_t iW = 0; iW != thePrism.myWallQuads.size(); ++iW )
1194   {
1195     Prism_3D::TQuadList::const_iterator quad = thePrism.myWallQuads[iW].begin();
1196     for ( ; quad != thePrism.myWallQuads[iW].end(); ++quad )
1197     {
1198       // Top EDGEs must be projections from the bottom ones
1199       // to compute stuctured quad mesh on wall FACEs
1200       // ---------------------------------------------------
1201       const TopoDS_Edge& botE = (*quad)->side[ QUAD_BOTTOM_SIDE ]->Edge(0);
1202       const TopoDS_Edge& topE = (*quad)->side[ QUAD_TOP_SIDE    ]->Edge(0);
1203
1204       projector1D->myHyp.SetSourceEdge( botE );
1205
1206       SMESH_subMesh* tgtEdgeSm = mesh->GetSubMesh( topE );
1207       if ( !tgtEdgeSm->IsMeshComputed() )
1208       {
1209         // compute nodes on VERTEXes
1210         tgtEdgeSm->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE );
1211         // project segments
1212         projector1D->InitComputeError();
1213         bool ok = projector1D->Compute( *mesh, topE );
1214         if ( !ok )
1215         {
1216           SMESH_ComputeErrorPtr err = projector1D->GetComputeError();
1217           if ( err->IsOK() ) err->myName = COMPERR_ALGO_FAILED;
1218           tgtEdgeSm->GetComputeError() = err;
1219           return false;
1220         }
1221       }
1222       tgtEdgeSm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
1223
1224       // Compute quad mesh on wall FACEs
1225       // -------------------------------
1226       const TopoDS_Face& face = (*quad)->face;
1227       SMESH_subMesh* fSM = mesh->GetSubMesh( face );
1228       if ( ! fSM->IsMeshComputed() )
1229       {
1230         // make all EDGES meshed
1231         fSM->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE );
1232         if ( !fSM->SubMeshesComputed() )
1233           return toSM( error( COMPERR_BAD_INPUT_MESH,
1234                               "Not all edges have valid algorithm and hypothesis"));
1235         // mesh the <face>
1236         quadAlgo->InitComputeError();
1237         bool ok = quadAlgo->Compute( *mesh, face );
1238         fSM->GetComputeError() = quadAlgo->GetComputeError();
1239         if ( !ok )
1240           return false;
1241         fSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
1242       }
1243       if ( myHelper->GetIsQuadratic() )
1244       {
1245         // fill myHelper with medium nodes built by quadAlgo
1246         SMDS_ElemIteratorPtr fIt = fSM->GetSubMeshDS()->GetElements();
1247         while ( fIt->more() )
1248           myHelper->AddTLinks( dynamic_cast<const SMDS_MeshFace*>( fIt->next() ));
1249       }
1250     }
1251   }
1252
1253   return true;
1254 }
1255
1256 //=======================================================================
1257 //function : Evaluate
1258 //purpose  : 
1259 //=======================================================================
1260
1261 bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh&         theMesh,
1262                                    const TopoDS_Shape& theShape,
1263                                    MapShapeNbElems&    aResMap)
1264 {
1265   if ( theShape.ShapeType() == TopAbs_COMPOUND )
1266   {
1267     bool ok = true;
1268     for ( TopoDS_Iterator it( theShape ); it.More(); it.Next() )
1269       ok &= Evaluate( theMesh, it.Value(), aResMap );
1270     return ok;
1271   }
1272   SMESH_MesherHelper helper( theMesh );
1273   myHelper = &helper;
1274   myHelper->SetSubShape( theShape );
1275
1276   // find face contains only triangles
1277   vector < SMESH_subMesh * >meshFaces;
1278   TopTools_SequenceOfShape aFaces;
1279   int NumBase = 0, i = 0, NbQFs = 0;
1280   for (TopExp_Explorer exp(theShape, TopAbs_FACE); exp.More(); exp.Next()) {
1281     i++;
1282     aFaces.Append(exp.Current());
1283     SMESH_subMesh *aSubMesh = theMesh.GetSubMesh(exp.Current());
1284     meshFaces.push_back(aSubMesh);
1285     MapShapeNbElemsItr anIt = aResMap.find(meshFaces[i-1]);
1286     if( anIt==aResMap.end() )
1287       return toSM( error( "Submesh can not be evaluated"));
1288
1289     std::vector<int> aVec = (*anIt).second;
1290     int nbtri = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
1291     int nbqua = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
1292     if( nbtri==0 && nbqua>0 ) {
1293       NbQFs++;
1294     }
1295     if( nbtri>0 ) {
1296       NumBase = i;
1297     }
1298   }
1299
1300   if(NbQFs<4) {
1301     std::vector<int> aResVec(SMDSEntity_Last);
1302     for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
1303     SMESH_subMesh * sm = theMesh.GetSubMesh(theShape);
1304     aResMap.insert(std::make_pair(sm,aResVec));
1305     return toSM( error( "Submesh can not be evaluated" ));
1306   }
1307
1308   if(NumBase==0) NumBase = 1; // only quads => set 1 faces as base
1309
1310   // find number of 1d elems for base face
1311   int nb1d = 0;
1312   TopTools_MapOfShape Edges1;
1313   for (TopExp_Explorer exp(aFaces.Value(NumBase), TopAbs_EDGE); exp.More(); exp.Next()) {
1314     Edges1.Add(exp.Current());
1315     SMESH_subMesh *sm = theMesh.GetSubMesh(exp.Current());
1316     if( sm ) {
1317       MapShapeNbElemsItr anIt = aResMap.find(sm);
1318       if( anIt == aResMap.end() ) continue;
1319       std::vector<int> aVec = (*anIt).second;
1320       nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
1321     }
1322   }
1323   // find face opposite to base face
1324   int OppNum = 0;
1325   for(i=1; i<=6; i++) {
1326     if(i==NumBase) continue;
1327     bool IsOpposite = true;
1328     for(TopExp_Explorer exp(aFaces.Value(i), TopAbs_EDGE); exp.More(); exp.Next()) {
1329       if( Edges1.Contains(exp.Current()) ) {
1330         IsOpposite = false;
1331         break;
1332       }
1333     }
1334     if(IsOpposite) {
1335       OppNum = i;
1336       break;
1337     }
1338   }
1339   // find number of 2d elems on side faces
1340   int nb2d = 0;
1341   for(i=1; i<=6; i++) {
1342     if( i==OppNum || i==NumBase ) continue;
1343     MapShapeNbElemsItr anIt = aResMap.find( meshFaces[i-1] );
1344     if( anIt == aResMap.end() ) continue;
1345     std::vector<int> aVec = (*anIt).second;
1346     nb2d += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
1347   }
1348   
1349   MapShapeNbElemsItr anIt = aResMap.find( meshFaces[NumBase-1] );
1350   std::vector<int> aVec = (*anIt).second;
1351   bool IsQuadratic = (aVec[SMDSEntity_Quad_Triangle]>aVec[SMDSEntity_Triangle]) ||
1352                      (aVec[SMDSEntity_Quad_Quadrangle]>aVec[SMDSEntity_Quadrangle]);
1353   int nb2d_face0_3 = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
1354   int nb2d_face0_4 = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
1355   int nb0d_face0 = aVec[SMDSEntity_Node];
1356   int nb1d_face0_int = ( nb2d_face0_3*3 + nb2d_face0_4*4 - nb1d ) / 2;
1357
1358   std::vector<int> aResVec(SMDSEntity_Last);
1359   for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
1360   if(IsQuadratic) {
1361     aResVec[SMDSEntity_Quad_Penta] = nb2d_face0_3 * ( nb2d/nb1d );
1362     aResVec[SMDSEntity_Quad_Hexa] = nb2d_face0_4 * ( nb2d/nb1d );
1363     aResVec[SMDSEntity_Node] = nb0d_face0 * ( 2*nb2d/nb1d - 1 ) - nb1d_face0_int * nb2d/nb1d;
1364   }
1365   else {
1366     aResVec[SMDSEntity_Node] = nb0d_face0 * ( nb2d/nb1d - 1 );
1367     aResVec[SMDSEntity_Penta] = nb2d_face0_3 * ( nb2d/nb1d );
1368     aResVec[SMDSEntity_Hexa] = nb2d_face0_4 * ( nb2d/nb1d );
1369   }
1370   SMESH_subMesh * sm = theMesh.GetSubMesh(theShape);
1371   aResMap.insert(std::make_pair(sm,aResVec));
1372
1373   return true;
1374 }
1375
1376 //================================================================================
1377 /*!
1378  * \brief Create prisms
1379  * \param columns - columns of nodes generated from nodes of a mesh face
1380  * \param helper - helper initialized by mesh and shape to add prisms to
1381  */
1382 //================================================================================
1383
1384 void StdMeshers_Prism_3D::AddPrisms( vector<const TNodeColumn*> & columns,
1385                                      SMESH_MesherHelper*          helper)
1386 {
1387   int nbNodes = columns.size();
1388   int nbZ     = columns[0]->size();
1389   if ( nbZ < 2 ) return;
1390
1391   // find out orientation
1392   bool isForward = true;
1393   SMDS_VolumeTool vTool;
1394   int z = 1;
1395   switch ( nbNodes ) {
1396   case 3: {
1397     SMDS_VolumeOfNodes tmpPenta ( (*columns[0])[z-1], // bottom
1398                                   (*columns[1])[z-1],
1399                                   (*columns[2])[z-1],
1400                                   (*columns[0])[z],   // top
1401                                   (*columns[1])[z],
1402                                   (*columns[2])[z] );
1403     vTool.Set( &tmpPenta );
1404     isForward  = vTool.IsForward();
1405     break;
1406   }
1407   case 4: {
1408     SMDS_VolumeOfNodes tmpHex( (*columns[0])[z-1], (*columns[1])[z-1], // bottom
1409                                (*columns[2])[z-1], (*columns[3])[z-1],
1410                                (*columns[0])[z],   (*columns[1])[z],   // top
1411                                (*columns[2])[z],   (*columns[3])[z] );
1412     vTool.Set( &tmpHex );
1413     isForward  = vTool.IsForward();
1414     break;
1415   }
1416   default:
1417     const int di = (nbNodes+1) / 3;
1418     SMDS_VolumeOfNodes tmpVol ( (*columns[0]   )[z-1],
1419                                 (*columns[di]  )[z-1],
1420                                 (*columns[2*di])[z-1],
1421                                 (*columns[0]   )[z],
1422                                 (*columns[di]  )[z],
1423                                 (*columns[2*di])[z] );
1424     vTool.Set( &tmpVol );
1425     isForward  = vTool.IsForward();
1426   }
1427
1428   // vertical loop on columns
1429
1430   helper->SetElementsOnShape( true );
1431
1432   switch ( nbNodes ) {
1433
1434   case 3: { // ---------- pentahedra
1435     const int i1 = isForward ? 1 : 2;
1436     const int i2 = isForward ? 2 : 1;
1437     for ( z = 1; z < nbZ; ++z )
1438       helper->AddVolume( (*columns[0 ])[z-1], // bottom
1439                          (*columns[i1])[z-1],
1440                          (*columns[i2])[z-1],
1441                          (*columns[0 ])[z],   // top
1442                          (*columns[i1])[z],
1443                          (*columns[i2])[z] );
1444     break;
1445   }
1446   case 4: { // ---------- hexahedra
1447     const int i1 = isForward ? 1 : 3;
1448     const int i3 = isForward ? 3 : 1;
1449     for ( z = 1; z < nbZ; ++z )
1450       helper->AddVolume( (*columns[0])[z-1], (*columns[i1])[z-1], // bottom
1451                          (*columns[2])[z-1], (*columns[i3])[z-1],
1452                          (*columns[0])[z],   (*columns[i1])[z],     // top
1453                          (*columns[2])[z],   (*columns[i3])[z] );
1454     break;
1455   }
1456   case 6: { // ---------- octahedra
1457     const int iBase1 = isForward ? -1 : 0;
1458     const int iBase2 = isForward ?  0 :-1;
1459     for ( z = 1; z < nbZ; ++z )
1460       helper->AddVolume( (*columns[0])[z+iBase1], (*columns[1])[z+iBase1], // bottom or top
1461                          (*columns[2])[z+iBase1], (*columns[3])[z+iBase1],
1462                          (*columns[4])[z+iBase1], (*columns[5])[z+iBase1],
1463                          (*columns[0])[z+iBase2], (*columns[1])[z+iBase2], // top or bottom
1464                          (*columns[2])[z+iBase2], (*columns[3])[z+iBase2],
1465                          (*columns[4])[z+iBase2], (*columns[5])[z+iBase2] );
1466     break;
1467   }
1468   default: // ---------- polyhedra
1469     vector<int> quantities( 2 + nbNodes, 4 );
1470     quantities[0] = quantities[1] = nbNodes;
1471     columns.resize( nbNodes + 1 );
1472     columns[ nbNodes ] = columns[ 0 ];
1473     const int i1 = isForward ? 1 : 3;
1474     const int i3 = isForward ? 3 : 1;
1475     const int iBase1 = isForward ? -1 : 0;
1476     const int iBase2 = isForward ?  0 :-1;
1477     vector<const SMDS_MeshNode*> nodes( 2*nbNodes + 4*nbNodes);
1478     for ( z = 1; z < nbZ; ++z )
1479     {
1480       for ( int i = 0; i < nbNodes; ++i ) {
1481         nodes[ i             ] = (*columns[ i ])[z+iBase1]; // bottom or top
1482         nodes[ 2*nbNodes-i-1 ] = (*columns[ i ])[z+iBase2]; // top or bottom
1483         // side
1484         int di = 2*nbNodes + 4*i;
1485         nodes[ di+0 ] = (*columns[i  ])[z  ];
1486         nodes[ di+i1] = (*columns[i+1])[z  ];
1487         nodes[ di+2 ] = (*columns[i+1])[z-1];
1488         nodes[ di+i3] = (*columns[i  ])[z-1];
1489       }
1490       helper->AddPolyhedralVolume( nodes, quantities );
1491     }
1492
1493   } // switch ( nbNodes )
1494 }
1495
1496 //================================================================================
1497 /*!
1498  * \brief Find correspondence between bottom and top nodes
1499  *  If elements on the bottom and top faces are topologically different,
1500  *  and projection is possible and allowed, perform the projection
1501  *  \retval bool - is a success or not
1502  */
1503 //================================================================================
1504
1505 bool StdMeshers_Prism_3D::assocOrProjBottom2Top()
1506 {
1507   SMESH_subMesh * botSM = myBlock.SubMesh( ID_BOT_FACE );
1508   SMESH_subMesh * topSM = myBlock.SubMesh( ID_TOP_FACE );
1509
1510   SMESHDS_SubMesh * botSMDS = botSM->GetSubMeshDS();
1511   SMESHDS_SubMesh * topSMDS = topSM->GetSubMeshDS();
1512
1513   if ( !botSMDS || botSMDS->NbElements() == 0 )
1514     return toSM( error(TCom("No elememts on face #") << botSM->GetId() ));
1515
1516   bool needProject = !topSM->IsMeshComputed();
1517   if ( !needProject && 
1518        (botSMDS->NbElements() != topSMDS->NbElements() ||
1519         botSMDS->NbNodes()    != topSMDS->NbNodes()))
1520   {
1521     MESSAGE("nb elem bot " << botSMDS->NbElements() <<
1522             " top " << ( topSMDS ? topSMDS->NbElements() : 0 ));
1523     MESSAGE("nb node bot " << botSMDS->NbNodes() <<
1524             " top " << ( topSMDS ? topSMDS->NbNodes() : 0 ));
1525     return toSM( error(TCom("Mesh on faces #") << botSM->GetId()
1526                        <<" and #"<< topSM->GetId() << " seems different" ));
1527   }
1528
1529   if ( 0/*needProject && !myProjectTriangles*/ )
1530     return toSM( error(TCom("Mesh on faces #") << botSM->GetId()
1531                        <<" and #"<< topSM->GetId() << " seems different" ));
1532   ///RETURN_BAD_RESULT("Need to project but not allowed");
1533
1534   if ( needProject )
1535   {
1536     return projectBottomToTop();
1537   }
1538
1539   TopoDS_Face botFace = TopoDS::Face( myBlock.Shape( ID_BOT_FACE ));
1540   TopoDS_Face topFace = TopoDS::Face( myBlock.Shape( ID_TOP_FACE ));
1541   // associate top and bottom faces
1542   TAssocTool::TShapeShapeMap shape2ShapeMap;
1543   if ( !TAssocTool::FindSubShapeAssociation( botFace, myBlock.Mesh(),
1544                                              topFace, myBlock.Mesh(),
1545                                              shape2ShapeMap) )
1546     return toSM( error(TCom("Topology of faces #") << botSM->GetId()
1547                        <<" and #"<< topSM->GetId() << " seems different" ));
1548
1549   // Find matching nodes of top and bottom faces
1550   TNodeNodeMap n2nMap;
1551   if ( ! TAssocTool::FindMatchingNodesOnFaces( botFace, myBlock.Mesh(),
1552                                                topFace, myBlock.Mesh(),
1553                                                shape2ShapeMap, n2nMap ))
1554     return toSM( error(TCom("Mesh on faces #") << botSM->GetId()
1555                        <<" and #"<< topSM->GetId() << " seems different" ));
1556
1557   // Fill myBotToColumnMap
1558
1559   int zSize = myBlock.VerticalSize();
1560   //TNode prevTNode;
1561   TNodeNodeMap::iterator bN_tN = n2nMap.begin();
1562   for ( ; bN_tN != n2nMap.end(); ++bN_tN )
1563   {
1564     const SMDS_MeshNode* botNode = bN_tN->first;
1565     const SMDS_MeshNode* topNode = bN_tN->second;
1566     if ( botNode->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE )
1567       continue; // wall columns are contained in myBlock
1568     // create node column
1569     Prism_3D::TNode bN( botNode );
1570     TNode2ColumnMap::iterator bN_col = 
1571       myBotToColumnMap.insert( make_pair ( bN, TNodeColumn() )).first;
1572     TNodeColumn & column = bN_col->second;
1573     column.resize( zSize );
1574     column.front() = botNode;
1575     column.back()  = topNode;
1576   }
1577   return true;
1578 }
1579
1580 //================================================================================
1581 /*!
1582  * \brief Remove quadrangles from the top face and
1583  * create triangles there by projection from the bottom
1584  * \retval bool - a success or not
1585  */
1586 //================================================================================
1587
1588 bool StdMeshers_Prism_3D::projectBottomToTop()
1589 {
1590   SMESHDS_Mesh*  meshDS = myBlock.MeshDS();
1591   SMESH_subMesh * botSM = myBlock.SubMesh( ID_BOT_FACE );
1592   SMESH_subMesh * topSM = myBlock.SubMesh( ID_TOP_FACE );
1593
1594   SMESHDS_SubMesh * botSMDS = botSM->GetSubMeshDS();
1595   SMESHDS_SubMesh * topSMDS = topSM->GetSubMeshDS();
1596
1597   if ( topSMDS && topSMDS->NbElements() > 0 )
1598     topSM->ComputeStateEngine( SMESH_subMesh::CLEAN );
1599
1600   const TopoDS_Shape& botFace = myBlock.Shape( ID_BOT_FACE ); // oriented within the 3D SHAPE
1601   const TopoDS_Shape& topFace = myBlock.Shape( ID_TOP_FACE);
1602   int topFaceID = meshDS->ShapeToIndex( topFace );
1603
1604   // Fill myBotToColumnMap
1605
1606   int zSize = myBlock.VerticalSize();
1607   Prism_3D::TNode prevTNode;
1608   SMDS_NodeIteratorPtr nIt = botSMDS->GetNodes();
1609   while ( nIt->more() )
1610   {
1611     const SMDS_MeshNode* botNode = nIt->next();
1612     if ( botNode->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE )
1613       continue; // strange
1614     // compute bottom node params
1615     Prism_3D::TNode bN( botNode );
1616     gp_XYZ paramHint(-1,-1,-1);
1617     if ( prevTNode.IsNeighbor( bN ))
1618       paramHint = prevTNode.GetParams();
1619     if ( !myBlock.ComputeParameters( bN.GetCoords(), bN.ChangeParams(),
1620                                      ID_BOT_FACE, paramHint ))
1621       return toSM( error(TCom("Can't compute normalized parameters for node ")
1622                          << botNode->GetID() << " on the face #"<< botSM->GetId() ));
1623     prevTNode = bN;
1624     // compute top node coords
1625     gp_XYZ topXYZ; gp_XY topUV;
1626     if ( !myBlock.FacePoint( ID_TOP_FACE, bN.GetParams(), topXYZ ) ||
1627          !myBlock.FaceUV   ( ID_TOP_FACE, bN.GetParams(), topUV ))
1628       return toSM( error(TCom("Can't compute coordinates "
1629                               "by normalized parameters on the face #")<< topSM->GetId() ));
1630     SMDS_MeshNode * topNode = meshDS->AddNode( topXYZ.X(),topXYZ.Y(),topXYZ.Z() );
1631     meshDS->SetNodeOnFace( topNode, topFaceID, topUV.X(), topUV.Y() );
1632     // create node column
1633     TNode2ColumnMap::iterator bN_col = 
1634       myBotToColumnMap.insert( make_pair ( bN, TNodeColumn() )).first;
1635     TNodeColumn & column = bN_col->second;
1636     column.resize( zSize );
1637     column.front() = botNode;
1638     column.back()  = topNode;
1639   }
1640
1641   // Create top faces
1642
1643   const bool oldSetElemsOnShape = myHelper->SetElementsOnShape( false );
1644
1645   // care of orientation;
1646   // if the bottom faces is orienetd OK then top faces must be reversed
1647   bool reverseTop = true;
1648   if ( myHelper->NbAncestors( botFace, *myBlock.Mesh(), TopAbs_SOLID ) > 1 )
1649     reverseTop = ! SMESH_Algo::IsReversedSubMesh( TopoDS::Face( botFace ), meshDS );
1650   int iFrw, iRev, *iPtr = &( reverseTop ? iRev : iFrw );
1651
1652   // loop on bottom mesh faces
1653   SMDS_ElemIteratorPtr faceIt = botSMDS->GetElements();
1654   vector< const SMDS_MeshNode* > nodes;
1655   while ( faceIt->more() )
1656   {
1657     const SMDS_MeshElement* face = faceIt->next();
1658     if ( !face || face->GetType() != SMDSAbs_Face )
1659       continue;
1660
1661     // find top node in columns for each bottom node
1662     int nbNodes = face->NbCornerNodes();
1663     nodes.resize( nbNodes );
1664     for ( iFrw = 0, iRev = nbNodes-1; iFrw < nbNodes; ++iFrw, --iRev )
1665     {
1666       const SMDS_MeshNode* n = face->GetNode( *iPtr );
1667       if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) {
1668         TNode2ColumnMap::iterator bot_column = myBotToColumnMap.find( n );
1669         if ( bot_column == myBotToColumnMap.end() )
1670           return toSM( error(TCom("No nodes found above node ") << n->GetID() ));
1671         nodes[ iFrw ] = bot_column->second.back();
1672       }
1673       else {
1674         const TNodeColumn* column = myBlock.GetNodeColumn( n );
1675         if ( !column )
1676           return toSM( error(TCom("No side nodes found above node ") << n->GetID() ));
1677         nodes[ iFrw ] = column->back();
1678       }
1679     }
1680     SMDS_MeshElement* newFace = 0;
1681     switch ( nbNodes ) {
1682
1683     case 3: {
1684       newFace = myHelper->AddFace(nodes[0], nodes[1], nodes[2]);
1685       break;
1686       }
1687     case 4: {
1688       newFace = myHelper->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] );
1689       break;
1690       }
1691     default:
1692       newFace = meshDS->AddPolygonalFace( nodes );
1693     }
1694     if ( newFace )
1695       meshDS->SetMeshElementOnShape( newFace, topFaceID );
1696   }
1697
1698   myHelper->SetElementsOnShape( oldSetElemsOnShape );  
1699
1700   return true;
1701 }
1702
1703 //=======================================================================
1704 //function : project2dMesh
1705 //purpose  : Project mesh faces from a source FACE of one prism (theSrcFace)
1706 //           to a source FACE of another prism (theTgtFace)
1707 //=======================================================================
1708
1709 bool StdMeshers_Prism_3D::project2dMesh(const TopoDS_Face& theSrcFace,
1710                                         const TopoDS_Face& theTgtFace)
1711 {
1712   TProjction2dAlgo* projector2D = TProjction2dAlgo::instance( this );
1713   projector2D->myHyp.SetSourceFace( theSrcFace );
1714   bool ok = projector2D->Compute( *myHelper->GetMesh(), theTgtFace );
1715
1716   SMESH_subMesh* tgtSM = myHelper->GetMesh()->GetSubMesh( theTgtFace );
1717   tgtSM->ComputeStateEngine       ( SMESH_subMesh::CHECK_COMPUTE_STATE );
1718   tgtSM->ComputeSubMeshStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
1719
1720   return ok;
1721 }
1722
1723 //================================================================================
1724 /*!
1725  * \brief Set projection coordinates of a node to a face and it's sub-shapes
1726  * \param faceID - the face given by in-block ID
1727  * \param params - node normalized parameters
1728  * \retval bool - is a success
1729  */
1730 //================================================================================
1731
1732 bool StdMeshers_Prism_3D::setFaceAndEdgesXYZ( const int faceID, const gp_XYZ& params, int z )
1733 {
1734   // find base and top edges of the face
1735   enum { BASE = 0, TOP, LEFT, RIGHT };
1736   vector< int > edgeVec; // 0-base, 1-top
1737   SMESH_Block::GetFaceEdgesIDs( faceID, edgeVec );
1738
1739   myBlock.EdgePoint( edgeVec[ BASE ], params, myShapeXYZ[ edgeVec[ BASE ]]);
1740   myBlock.EdgePoint( edgeVec[ TOP  ], params, myShapeXYZ[ edgeVec[ TOP ]]);
1741
1742   SHOWYXZ("\nparams ", params);
1743   SHOWYXZ("TOP is " <<edgeVec[ TOP ], myShapeXYZ[ edgeVec[ TOP]]);
1744   SHOWYXZ("BASE is "<<edgeVec[ BASE], myShapeXYZ[ edgeVec[ BASE]]);
1745
1746   if ( faceID == SMESH_Block::ID_Fx0z || faceID == SMESH_Block::ID_Fx1z )
1747   {
1748     myBlock.EdgePoint( edgeVec[ LEFT ], params, myShapeXYZ[ edgeVec[ LEFT ]]);
1749     myBlock.EdgePoint( edgeVec[ RIGHT ], params, myShapeXYZ[ edgeVec[ RIGHT ]]);
1750
1751     SHOWYXZ("VER "<<edgeVec[ LEFT], myShapeXYZ[ edgeVec[ LEFT]]);
1752     SHOWYXZ("VER "<<edgeVec[ RIGHT], myShapeXYZ[ edgeVec[ RIGHT]]);
1753   }
1754   myBlock.FacePoint( faceID, params, myShapeXYZ[ faceID ]);
1755   SHOWYXZ("FacePoint "<<faceID, myShapeXYZ[ faceID]);
1756
1757   return true;
1758 }
1759
1760 //=======================================================================
1761 //function : toSM
1762 //purpose  : If (!isOK), sets the error to a sub-mesh of a current SOLID
1763 //=======================================================================
1764
1765 bool StdMeshers_Prism_3D::toSM( bool isOK )
1766 {
1767   if ( mySetErrorToSM &&
1768        !isOK &&
1769        myHelper &&
1770        !myHelper->GetSubShape().IsNull() &&
1771        myHelper->GetSubShape().ShapeType() == TopAbs_SOLID)
1772   {
1773     SMESH_subMesh* sm = myHelper->GetMesh()->GetSubMesh( myHelper->GetSubShape() );
1774     sm->GetComputeError() = this->GetComputeError();
1775     // clear error in order not to return it twice
1776     _error = COMPERR_OK;
1777     _comment.clear();
1778   }
1779   return isOK;
1780 }
1781
1782 //=======================================================================
1783 //function : shapeID
1784 //purpose  : Return index of a shape
1785 //=======================================================================
1786
1787 int StdMeshers_Prism_3D::shapeID( const TopoDS_Shape& S )
1788 {
1789   if ( S.IsNull() ) return 0;
1790   if ( !myHelper  ) return -3;
1791   return myHelper->GetMeshDS()->ShapeToIndex( S );
1792 }
1793
1794 namespace Prism_3D
1795 {
1796   //================================================================================
1797   /*!
1798    * \brief Return true if this node and other one belong to one face
1799    */
1800   //================================================================================
1801
1802   bool Prism_3D::TNode::IsNeighbor( const Prism_3D::TNode& other ) const
1803   {
1804     if ( !other.myNode || !myNode ) return false;
1805
1806     SMDS_ElemIteratorPtr fIt = other.myNode->GetInverseElementIterator(SMDSAbs_Face);
1807     while ( fIt->more() )
1808       if ( fIt->next()->GetNodeIndex( myNode ) >= 0 )
1809         return true;
1810     return false;
1811   }
1812
1813   //================================================================================
1814   /*!
1815    * \brief Prism initialization
1816    */
1817   //================================================================================
1818
1819   void TPrismTopo::Clear()
1820   {
1821     myShape3D.Nullify();
1822     myTop.Nullify();
1823     myBottom.Nullify();
1824     myWallQuads.clear();
1825     myBottomEdges.clear();
1826     myNbEdgesInWires.clear();
1827     myWallQuads.clear();
1828   }
1829
1830 } // namespace Prism_3D
1831
1832 //================================================================================
1833 /*!
1834  * \brief Constructor. Initialization is needed
1835  */
1836 //================================================================================
1837
1838 StdMeshers_PrismAsBlock::StdMeshers_PrismAsBlock()
1839 {
1840   mySide = 0;
1841 }
1842
1843 StdMeshers_PrismAsBlock::~StdMeshers_PrismAsBlock()
1844 {
1845   Clear();
1846 }
1847 void StdMeshers_PrismAsBlock::Clear()
1848 {
1849   myHelper = 0;
1850   myShapeIDMap.Clear();
1851   myError.reset();
1852
1853   if ( mySide ) {
1854     delete mySide; mySide = 0;
1855   }
1856   myParam2ColumnMaps.clear();
1857   myShapeIndex2ColumnMap.clear();
1858 }
1859
1860 //=======================================================================
1861 //function : initPrism
1862 //purpose  : Analyse shape geometry and mesh.
1863 //           If there are triangles on one of faces, it becomes 'bottom'.
1864 //           thePrism.myBottom can be already set up.
1865 //=======================================================================
1866
1867 bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism,
1868                                     const TopoDS_Shape&   shape3D)
1869 {
1870   myHelper->SetSubShape( shape3D );
1871
1872   SMESH_subMesh* mainSubMesh = myHelper->GetMesh()->GetSubMeshContaining( shape3D );
1873   if ( !mainSubMesh ) return toSM( error(COMPERR_BAD_INPUT_MESH,"Null submesh of shape3D"));
1874
1875   // detect not-quad FACE sub-meshes of the 3D SHAPE
1876   list< SMESH_subMesh* > notQuadGeomSubMesh;
1877   list< SMESH_subMesh* > notQuadElemSubMesh;
1878   int nbFaces = 0;
1879   //
1880   SMESH_subMesh* anyFaceSM = 0;
1881   SMESH_subMeshIteratorPtr smIt = mainSubMesh->getDependsOnIterator(false,true);
1882   while ( smIt->more() )
1883   {
1884     SMESH_subMesh* sm = smIt->next();
1885     const TopoDS_Shape& face = sm->GetSubShape();
1886     if      ( face.ShapeType() > TopAbs_FACE ) break;
1887     else if ( face.ShapeType() < TopAbs_FACE ) continue;
1888     nbFaces++;
1889     anyFaceSM = sm;
1890
1891     // is quadrangle FACE?
1892     list< TopoDS_Edge > orderedEdges;
1893     list< int >         nbEdgesInWires;
1894     int nbWires = SMESH_Block::GetOrderedEdges( TopoDS::Face( face ), orderedEdges,
1895                                                 nbEdgesInWires );
1896     if ( nbWires != 1 || nbEdgesInWires.front() != 4 )
1897       notQuadGeomSubMesh.push_back( sm );
1898
1899     // look for not quadrangle mesh elements
1900     if ( SMESHDS_SubMesh* smDS = sm->GetSubMeshDS() )
1901       if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE ))
1902         notQuadElemSubMesh.push_back( sm );
1903   }
1904
1905   int nbNotQuadMeshed = notQuadElemSubMesh.size();
1906   int       nbNotQuad = notQuadGeomSubMesh.size();
1907   bool     hasNotQuad = ( nbNotQuad || nbNotQuadMeshed );
1908
1909   // detect bad cases
1910   if ( nbNotQuadMeshed > 2 )
1911   {
1912     return toSM( error(COMPERR_BAD_INPUT_MESH,
1913                        TCom("More than 2 faces with not quadrangle elements: ")
1914                        <<nbNotQuadMeshed));
1915   }
1916   if ( nbNotQuad > 2 || !thePrism.myBottom.IsNull() )
1917   {
1918     // Issue 0020843 - one of side FACEs is quasi-quadrilateral (not 4 EDGEs).
1919     // Remove from notQuadGeomSubMesh faces meshed with regular grid
1920     int nbQuasiQuads = removeQuasiQuads( notQuadGeomSubMesh, myHelper,
1921                                          TQuadrangleAlgo::instance(this,myHelper) );
1922     nbNotQuad -= nbQuasiQuads;
1923     if ( nbNotQuad > 2 )
1924       return toSM( error(COMPERR_BAD_SHAPE,
1925                          TCom("More than 2 not quadrilateral faces: ") <<nbNotQuad));
1926     hasNotQuad = ( nbNotQuad || nbNotQuadMeshed );
1927   }
1928
1929   // Analyse mesh and topology of FACEs: choose the bottom sub-mesh.
1930   // If there are not quadrangle FACEs, they are top and bottom ones.
1931   // Not quadrangle FACEs must be only on top and bottom.
1932
1933   SMESH_subMesh * botSM = 0;
1934   SMESH_subMesh * topSM = 0;
1935
1936   if ( hasNotQuad ) // can chose a bottom FACE
1937   {
1938     if ( nbNotQuadMeshed > 0 ) botSM = notQuadElemSubMesh.front();
1939     else                       botSM = notQuadGeomSubMesh.front();
1940     if ( nbNotQuadMeshed > 1 ) topSM = notQuadElemSubMesh.back();
1941     else if ( nbNotQuad  > 1 ) topSM = notQuadGeomSubMesh.back();
1942
1943     if ( topSM == botSM ) {
1944       if ( nbNotQuadMeshed > 1 ) topSM = notQuadElemSubMesh.front();
1945       else                       topSM = notQuadGeomSubMesh.front();
1946     }
1947
1948     // detect mesh triangles on wall FACEs
1949     if ( nbNotQuad == 2 && nbNotQuadMeshed > 0 ) {
1950       bool ok = false;
1951       if ( nbNotQuadMeshed == 1 )
1952         ok = ( find( notQuadGeomSubMesh.begin(),
1953                      notQuadGeomSubMesh.end(), botSM ) != notQuadGeomSubMesh.end() );
1954       else
1955         ok = ( notQuadGeomSubMesh == notQuadElemSubMesh );
1956       if ( !ok )
1957         return toSM( error(COMPERR_BAD_INPUT_MESH,
1958                            "Side face meshed with not quadrangle elements"));
1959     }
1960   }
1961
1962   thePrism.myNotQuadOnTop = ( nbNotQuadMeshed > 1 );
1963
1964   // use thePrism.myBottom
1965   if ( !thePrism.myBottom.IsNull() )
1966   {
1967     if ( botSM ) {
1968       if ( ! botSM->GetSubShape().IsSame( thePrism.myBottom )) {
1969         std::swap( botSM, topSM );
1970         if ( ! botSM->GetSubShape().IsSame( thePrism.myBottom ))
1971           return toSM( error( COMPERR_BAD_INPUT_MESH,
1972                               "Incompatible non-structured sub-meshes"));
1973       }
1974     }
1975     else {
1976       botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom );
1977     }
1978   }
1979   else if ( !botSM ) // find a proper bottom
1980   {
1981     // composite walls or not prism shape
1982     for ( TopExp_Explorer f( shape3D, TopAbs_FACE ); f.More(); f.Next() )
1983     {
1984       int minNbFaces = 2 + myHelper->Count( f.Current(), TopAbs_EDGE, false);
1985       if ( nbFaces >= minNbFaces)
1986       {
1987         thePrism.Clear();
1988         thePrism.myBottom = TopoDS::Face( f.Current() );
1989         if ( initPrism( thePrism, shape3D ))
1990           return true;
1991       }
1992       return toSM( error( COMPERR_BAD_SHAPE ));
1993     }
1994   }
1995
1996   // find vertex 000 - the one with smallest coordinates (for easy DEBUG :-)
1997   TopoDS_Vertex V000;
1998   double minVal = DBL_MAX, minX, val;
1999   for ( TopExp_Explorer exp( botSM->GetSubShape(), TopAbs_VERTEX );
2000         exp.More(); exp.Next() )
2001   {
2002     const TopoDS_Vertex& v = TopoDS::Vertex( exp.Current() );
2003     gp_Pnt P = BRep_Tool::Pnt( v );
2004     val = P.X() + P.Y() + P.Z();
2005     if ( val < minVal || ( val == minVal && P.X() < minX )) {
2006       V000 = v;
2007       minVal = val;
2008       minX = P.X();
2009     }
2010   }
2011
2012   thePrism.myShape3D = shape3D;
2013   if ( thePrism.myBottom.IsNull() )
2014     thePrism.myBottom  = TopoDS::Face( botSM->GetSubShape() );
2015   thePrism.myBottom.Orientation( myHelper->GetSubShapeOri( shape3D,
2016                                                            thePrism.myBottom ));
2017   // Get ordered bottom edges
2018   TopoDS_Face reverseBottom = // to have order of top EDGEs as in the top FACE
2019     TopoDS::Face( thePrism.myBottom.Reversed() );
2020   SMESH_Block::GetOrderedEdges( reverseBottom,
2021                                 thePrism.myBottomEdges,
2022                                 thePrism.myNbEdgesInWires, V000 );
2023
2024   // Get Wall faces corresponding to the ordered bottom edges and the top FACE
2025   if ( !getWallFaces( thePrism, nbFaces ))
2026     return false; //toSM( error(COMPERR_BAD_SHAPE, "Can't find side faces"));
2027
2028   if ( topSM )
2029   {
2030     if ( !thePrism.myTop.IsSame( topSM->GetSubShape() ))
2031       return toSM( error
2032                    (notQuadGeomSubMesh.empty() ? COMPERR_BAD_INPUT_MESH : COMPERR_BAD_SHAPE,
2033                     "Non-quadrilateral faces are not opposite"));
2034
2035     // check that the found top and bottom FACEs are opposite
2036     list< TopoDS_Edge >::iterator edge = thePrism.myBottomEdges.begin();
2037     for ( ; edge != thePrism.myBottomEdges.end(); ++edge )
2038       if ( myHelper->IsSubShape( *edge, thePrism.myTop ))
2039         return toSM( error
2040                      (notQuadGeomSubMesh.empty() ? COMPERR_BAD_INPUT_MESH : COMPERR_BAD_SHAPE,
2041                       "Non-quadrilateral faces are not opposite"));
2042   }
2043
2044   return true;
2045 }
2046
2047 //================================================================================
2048 /*!
2049  * \brief Initialization.
2050  * \param helper - helper loaded with mesh and 3D shape
2051  * \param thePrism - a prosm data
2052  * \retval bool - false if a mesh or a shape are KO
2053  */
2054 //================================================================================
2055
2056 bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper*         helper,
2057                                    const Prism_3D::TPrismTopo& thePrism)
2058 {
2059   if ( mySide ) {
2060     delete mySide; mySide = 0;
2061   }
2062   vector< TSideFace* >         sideFaces( NB_WALL_FACES, 0 );
2063   vector< pair< double, double> > params( NB_WALL_FACES );
2064   mySide = new TSideFace( sideFaces, params );
2065
2066   myHelper = helper;
2067   SMESHDS_Mesh* meshDS = myHelper->GetMeshDS();
2068
2069   SMESH_Block::init();
2070   myShapeIDMap.Clear();
2071   myShapeIndex2ColumnMap.clear();
2072   
2073   int wallFaceIds[ NB_WALL_FACES ] = { // to walk around a block
2074     SMESH_Block::ID_Fx0z, SMESH_Block::ID_F1yz,
2075     SMESH_Block::ID_Fx1z, SMESH_Block::ID_F0yz
2076   };
2077
2078   myError = SMESH_ComputeError::New();
2079
2080   myNotQuadOnTop = thePrism.myNotQuadOnTop;
2081
2082   // Find columns of wall nodes and calculate edges' lengths
2083   // --------------------------------------------------------
2084
2085   myParam2ColumnMaps.clear();
2086   myParam2ColumnMaps.resize( thePrism.myBottomEdges.size() ); // total nb edges
2087
2088   size_t iE, nbEdges = thePrism.myNbEdgesInWires.front(); // nb outer edges
2089   vector< double >    edgeLength( nbEdges );
2090   multimap< double, int > len2edgeMap;
2091
2092   list< TopoDS_Edge >::const_iterator edgeIt = thePrism.myBottomEdges.begin();
2093   for ( iE = 0; iE < nbEdges; ++iE, ++edgeIt )
2094   {
2095     TParam2ColumnMap & faceColumns = myParam2ColumnMaps[ iE ];
2096
2097     Prism_3D::TQuadList::const_iterator quad = thePrism.myWallQuads[ iE ].begin();
2098     for ( ; quad != thePrism.myWallQuads[ iE ].end(); ++quad )
2099     {
2100       const TopoDS_Edge& quadBot = (*quad)->side[ QUAD_BOTTOM_SIDE ]->Edge( 0 );
2101       if ( !myHelper->LoadNodeColumns( faceColumns, (*quad)->face, quadBot, meshDS ))
2102         return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ")
2103                      << "on a side face #" << MeshDS()->ShapeToIndex( (*quad)->face ));
2104     }
2105     SHOWYXZ("\np1 F " <<iE, gpXYZ(faceColumns.begin()->second.front() ));
2106     SHOWYXZ("p2 F "   <<iE, gpXYZ(faceColumns.rbegin()->second.front() ));
2107     SHOWYXZ("V First "<<iE, BRep_Tool::Pnt( TopExp::FirstVertex(*edgeIt,true )));
2108
2109     edgeLength[ iE ] = SMESH_Algo::EdgeLength( *edgeIt );
2110
2111     if ( nbEdges < NB_WALL_FACES ) // fill map used to split faces
2112     {
2113       SMESHDS_SubMesh* smDS = meshDS->MeshElements( *edgeIt);
2114       if ( !smDS )
2115         return error(COMPERR_BAD_INPUT_MESH, TCom("Null submesh on the edge #")
2116                      << MeshDS()->ShapeToIndex( *edgeIt ));
2117       len2edgeMap.insert( make_pair( edgeLength[ iE ], iE ));
2118     }
2119   }
2120   // Load columns of internal edges (forming holes)
2121   // and fill map ShapeIndex to TParam2ColumnMap for them
2122   for ( ; edgeIt != thePrism.myBottomEdges.end() ; ++edgeIt, ++iE )
2123   {
2124     TParam2ColumnMap & faceColumns = myParam2ColumnMaps[ iE ];
2125
2126     Prism_3D::TQuadList::const_iterator quad = thePrism.myWallQuads[ iE ].begin();
2127     for ( ; quad != thePrism.myWallQuads[ iE ].end(); ++quad )
2128     {
2129       const TopoDS_Edge& quadBot = (*quad)->side[ QUAD_BOTTOM_SIDE ]->Edge( 0 );
2130       if ( !myHelper->LoadNodeColumns( faceColumns, (*quad)->face, quadBot, meshDS ))
2131         return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ")
2132                      << "on a side face #" << MeshDS()->ShapeToIndex( (*quad)->face ));
2133     }
2134     // edge columns
2135     int id = MeshDS()->ShapeToIndex( *edgeIt );
2136     bool isForward = true; // meaningless for intenal wires
2137     myShapeIndex2ColumnMap[ id ] = make_pair( & faceColumns, isForward );
2138     // columns for vertices
2139     // 1
2140     const SMDS_MeshNode* n0 = faceColumns.begin()->second.front();
2141     id = n0->getshapeId();
2142     myShapeIndex2ColumnMap[ id ] = make_pair( & faceColumns, isForward );
2143     // 2
2144     const SMDS_MeshNode* n1 = faceColumns.rbegin()->second.front();
2145     id = n1->getshapeId();
2146     myShapeIndex2ColumnMap[ id ] = make_pair( & faceColumns, isForward );
2147
2148     // SHOWYXZ("\np1 F " <<iE, gpXYZ(faceColumns.begin()->second.front() ));
2149     // SHOWYXZ("p2 F "   <<iE, gpXYZ(faceColumns.rbegin()->second.front() ));
2150     // SHOWYXZ("V First "<<iE, BRep_Tool::Pnt( TopExp::FirstVertex(*edgeIt,true )));
2151   }
2152
2153   // Create 4 wall faces of a block
2154   // -------------------------------
2155
2156   if ( nbEdges <= NB_WALL_FACES ) // ************* Split faces if necessary
2157   {
2158     map< int, int > iE2nbSplit;
2159     if ( nbEdges != NB_WALL_FACES ) // define how to split
2160     {
2161       if ( len2edgeMap.size() != nbEdges )
2162         RETURN_BAD_RESULT("Uniqueness of edge lengths not assured");
2163       map< double, int >::reverse_iterator maxLen_i = len2edgeMap.rbegin();
2164       map< double, int >::reverse_iterator midLen_i = ++len2edgeMap.rbegin();
2165       double maxLen = maxLen_i->first;
2166       double midLen = ( len2edgeMap.size() == 1 ) ? 0 : midLen_i->first;
2167       switch ( nbEdges ) {
2168       case 1: // 0-th edge is split into 4 parts
2169         iE2nbSplit.insert( make_pair( 0, 4 )); break;
2170       case 2: // either the longest edge is split into 3 parts, or both edges into halves
2171         if ( maxLen / 3 > midLen / 2 ) {
2172           iE2nbSplit.insert( make_pair( maxLen_i->second, 3 ));
2173         }
2174         else {
2175           iE2nbSplit.insert( make_pair( maxLen_i->second, 2 ));
2176           iE2nbSplit.insert( make_pair( midLen_i->second, 2 ));
2177         }
2178         break;
2179       case 3:
2180         // split longest into halves
2181         iE2nbSplit.insert( make_pair( maxLen_i->second, 2 ));
2182       }
2183     }
2184     // Create TSideFace's
2185     int iSide = 0;
2186     list< TopoDS_Edge >::const_iterator botE = thePrism.myBottomEdges.begin();
2187     for ( iE = 0; iE < nbEdges; ++iE, ++botE )
2188     {
2189       TFaceQuadStructPtr quad = thePrism.myWallQuads[ iE ].front();
2190       // split?
2191       map< int, int >::iterator i_nb = iE2nbSplit.find( iE );
2192       if ( i_nb != iE2nbSplit.end() ) {
2193         // split!
2194         int nbSplit = i_nb->second;
2195         vector< double > params;
2196         splitParams( nbSplit, &myParam2ColumnMaps[ iE ], params );
2197         const bool isForward =
2198           StdMeshers_PrismAsBlock::IsForwardEdge( myHelper->GetMeshDS(),
2199                                                   myParam2ColumnMaps[iE],
2200                                                   *botE, SMESH_Block::ID_Fx0z );
2201         for ( int i = 0; i < nbSplit; ++i ) {
2202           double f = ( isForward ? params[ i ]   : params[ nbSplit - i-1 ]);
2203           double l = ( isForward ? params[ i+1 ] : params[ nbSplit - i ]);
2204           TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ],
2205                                            thePrism.myWallQuads[ iE ], *botE,
2206                                            &myParam2ColumnMaps[ iE ], f, l );
2207           mySide->SetComponent( iSide++, comp );
2208         }
2209       }
2210       else {
2211         TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ],
2212                                          thePrism.myWallQuads[ iE ], *botE,
2213                                          &myParam2ColumnMaps[ iE ]);
2214         mySide->SetComponent( iSide++, comp );
2215       }
2216     }
2217   }
2218   else { // **************************** Unite faces
2219
2220     // unite first faces
2221     int nbExraFaces = nbEdges - 3;
2222     int iSide = 0, iE;
2223     double u0 = 0, sumLen = 0;
2224     for ( iE = 0; iE < nbExraFaces; ++iE )
2225       sumLen += edgeLength[ iE ];
2226
2227     vector< TSideFace* >        components( nbExraFaces );
2228     vector< pair< double, double> > params( nbExraFaces );
2229     list< TopoDS_Edge >::const_iterator botE = thePrism.myBottomEdges.begin();
2230     for ( iE = 0; iE < nbExraFaces; ++iE, ++botE )
2231     {
2232       components[ iE ] = new TSideFace( myHelper, wallFaceIds[ iSide ],
2233                                         thePrism.myWallQuads[ iE ], *botE,
2234                                         &myParam2ColumnMaps[ iE ]);
2235       double u1 = u0 + edgeLength[ iE ] / sumLen;
2236       params[ iE ] = make_pair( u0 , u1 );
2237       u0 = u1;
2238     }
2239     mySide->SetComponent( iSide++, new TSideFace( components, params ));
2240
2241     // fill the rest faces
2242     for ( ; iE < nbEdges; ++iE, ++botE )
2243     {
2244       TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ],
2245                                        thePrism.myWallQuads[ iE ], *botE,
2246                                        &myParam2ColumnMaps[ iE ]);
2247       mySide->SetComponent( iSide++, comp );
2248     }
2249   }
2250
2251
2252   // Fill geometry fields of SMESH_Block
2253   // ------------------------------------
2254
2255   vector< int > botEdgeIdVec;
2256   SMESH_Block::GetFaceEdgesIDs( ID_BOT_FACE, botEdgeIdVec );
2257
2258   bool isForward[NB_WALL_FACES] = { true, true, true, true };
2259   Adaptor2d_Curve2d* botPcurves[NB_WALL_FACES];
2260   Adaptor2d_Curve2d* topPcurves[NB_WALL_FACES];
2261
2262   for ( int iF = 0; iF < NB_WALL_FACES; ++iF )
2263   {
2264     TSideFace * sideFace = mySide->GetComponent( iF );
2265     if ( !sideFace )
2266       RETURN_BAD_RESULT("NULL TSideFace");
2267     int fID = sideFace->FaceID(); // in-block ID
2268
2269     // fill myShapeIDMap
2270     if ( sideFace->InsertSubShapes( myShapeIDMap ) != 8 &&
2271          !sideFace->IsComplex())
2272       MESSAGE( ": Warning : InsertSubShapes() < 8 on side " << iF );
2273
2274     // side faces geometry
2275     Adaptor2d_Curve2d* pcurves[NB_WALL_FACES];
2276     if ( !sideFace->GetPCurves( pcurves ))
2277       RETURN_BAD_RESULT("TSideFace::GetPCurves() failed");
2278
2279     SMESH_Block::TFace& tFace = myFace[ fID - ID_FirstF ];
2280     tFace.Set( fID, sideFace->Surface(), pcurves, isForward );
2281
2282     SHOWYXZ( endl<<"F "<< iF << " id " << fID << " FRW " << sideFace->IsForward(), sideFace->Value(0,0));
2283     // edges 3D geometry
2284     vector< int > edgeIdVec;
2285     SMESH_Block::GetFaceEdgesIDs( fID, edgeIdVec );
2286     for ( int isMax = 0; isMax < 2; ++isMax ) {
2287       {
2288         int eID = edgeIdVec[ isMax ];
2289         SMESH_Block::TEdge& tEdge = myEdge[ eID - ID_FirstE ];
2290         tEdge.Set( eID, sideFace->HorizCurve(isMax), true);
2291         SHOWYXZ(eID<<" HOR"<<isMax<<"(0)", sideFace->HorizCurve(isMax)->Value(0));
2292         SHOWYXZ(eID<<" HOR"<<isMax<<"(1)", sideFace->HorizCurve(isMax)->Value(1));
2293       }
2294       {
2295         int eID = edgeIdVec[ isMax+2 ];
2296         SMESH_Block::TEdge& tEdge = myEdge[ eID - ID_FirstE  ];
2297         tEdge.Set( eID, sideFace->VertiCurve(isMax), true);
2298         SHOWYXZ(eID<<" VER"<<isMax<<"(0)", sideFace->VertiCurve(isMax)->Value(0));
2299         SHOWYXZ(eID<<" VER"<<isMax<<"(1)", sideFace->VertiCurve(isMax)->Value(1));
2300
2301         // corner points
2302         vector< int > vertexIdVec;
2303         SMESH_Block::GetEdgeVertexIDs( eID, vertexIdVec );
2304         myPnt[ vertexIdVec[0] - ID_FirstV ] = tEdge.GetCurve()->Value(0).XYZ();
2305         myPnt[ vertexIdVec[1] - ID_FirstV ] = tEdge.GetCurve()->Value(1).XYZ();
2306       }
2307     }
2308     // pcurves on horizontal faces
2309     for ( iE = 0; iE < NB_WALL_FACES; ++iE ) {
2310       if ( edgeIdVec[ BOTTOM_EDGE ] == botEdgeIdVec[ iE ] ) {
2311         botPcurves[ iE ] = sideFace->HorizPCurve( false, thePrism.myBottom );
2312         topPcurves[ iE ] = sideFace->HorizPCurve( true,  thePrism.myTop );
2313         break;
2314       }
2315     }
2316     //sideFace->dumpNodes( 4 ); // debug
2317   }
2318   // horizontal faces geometry
2319   {
2320     SMESH_Block::TFace& tFace = myFace[ ID_BOT_FACE - ID_FirstF ];
2321     tFace.Set( ID_BOT_FACE, new BRepAdaptor_Surface( thePrism.myBottom ), botPcurves, isForward );
2322     SMESH_Block::Insert( thePrism.myBottom, ID_BOT_FACE, myShapeIDMap );
2323   }
2324   {
2325     SMESH_Block::TFace& tFace = myFace[ ID_TOP_FACE - ID_FirstF ];
2326     tFace.Set( ID_TOP_FACE, new BRepAdaptor_Surface( thePrism.myTop ), topPcurves, isForward );
2327     SMESH_Block::Insert( thePrism.myTop, ID_TOP_FACE, myShapeIDMap );
2328   }
2329
2330   // Fill map ShapeIndex to TParam2ColumnMap
2331   // ----------------------------------------
2332
2333   list< TSideFace* > fList;
2334   list< TSideFace* >::iterator fListIt;
2335   fList.push_back( mySide );
2336   for ( fListIt = fList.begin(); fListIt != fList.end(); ++fListIt)
2337   {
2338     int nb = (*fListIt)->NbComponents();
2339     for ( int i = 0; i < nb; ++i ) {
2340       if ( TSideFace* comp = (*fListIt)->GetComponent( i ))
2341         fList.push_back( comp );
2342     }
2343     if ( TParam2ColumnMap* cols = (*fListIt)->GetColumns()) {
2344       // columns for a base edge
2345       int id = MeshDS()->ShapeToIndex( (*fListIt)->BaseEdge() );
2346       bool isForward = (*fListIt)->IsForward();
2347       myShapeIndex2ColumnMap[ id ] = make_pair( cols, isForward );
2348
2349       // columns for vertices
2350       const SMDS_MeshNode* n0 = cols->begin()->second.front();
2351       id = n0->getshapeId();
2352       myShapeIndex2ColumnMap[ id ] = make_pair( cols, isForward );
2353
2354       const SMDS_MeshNode* n1 = cols->rbegin()->second.front();
2355       id = n1->getshapeId();
2356       myShapeIndex2ColumnMap[ id ] = make_pair( cols, !isForward );
2357     }
2358   }
2359
2360 //   gp_XYZ testPar(0.25, 0.25, 0), testCoord;
2361 //   if ( !FacePoint( ID_BOT_FACE, testPar, testCoord ))
2362 //     RETURN_BAD_RESULT("TEST FacePoint() FAILED");
2363 //   SHOWYXZ("IN TEST PARAM" , testPar);
2364 //   SHOWYXZ("OUT TEST CORD" , testCoord);
2365 //   if ( !ComputeParameters( testCoord, testPar , ID_BOT_FACE))
2366 //     RETURN_BAD_RESULT("TEST ComputeParameters() FAILED");
2367 //   SHOWYXZ("OUT TEST PARAM" , testPar);
2368
2369   return true;
2370 }
2371
2372 //================================================================================
2373 /*!
2374  * \brief Return pointer to column of nodes
2375  * \param node - bottom node from which the returned column goes up
2376  * \retval const TNodeColumn* - the found column
2377  */
2378 //================================================================================
2379
2380 const TNodeColumn* StdMeshers_PrismAsBlock::GetNodeColumn(const SMDS_MeshNode* node) const
2381 {
2382   int sID = node->getshapeId();
2383
2384   map<int, pair< TParam2ColumnMap*, bool > >::const_iterator col_frw =
2385     myShapeIndex2ColumnMap.find( sID );
2386   if ( col_frw != myShapeIndex2ColumnMap.end() ) {
2387     const TParam2ColumnMap* cols = col_frw->second.first;
2388     TParam2ColumnIt u_col = cols->begin();
2389     for ( ; u_col != cols->end(); ++u_col )
2390       if ( u_col->second[ 0 ] == node )
2391         return & u_col->second;
2392   }
2393   return 0;
2394 }
2395
2396 //=======================================================================
2397 //function : GetLayersTransformation
2398 //purpose  : Return transformations to get coordinates of nodes of each layer
2399 //           by nodes of the bottom. Layer is a set of nodes at a certain step
2400 //           from bottom to top.
2401 //=======================================================================
2402
2403 bool StdMeshers_PrismAsBlock::GetLayersTransformation(vector<gp_Trsf> &           trsf,
2404                                                       const Prism_3D::TPrismTopo& prism) const
2405 {
2406   const int zSize = VerticalSize();
2407   if ( zSize < 3 ) return true;
2408   trsf.resize( zSize - 2 );
2409
2410   // Select some node columns by which we will define coordinate system of layers
2411
2412   vector< const TNodeColumn* > columns;
2413   {
2414     bool isReverse;
2415     list< TopoDS_Edge >::const_iterator edgeIt = prism.myBottomEdges.begin();
2416     for ( int iE = 0; iE < prism.myNbEdgesInWires.front(); ++iE, ++edgeIt )
2417     {
2418       if ( BRep_Tool::Degenerated( *edgeIt )) continue;
2419       const TParam2ColumnMap* u2colMap =
2420         GetParam2ColumnMap( MeshDS()->ShapeToIndex( *edgeIt ), isReverse );
2421       if ( !u2colMap ) return false;
2422       double f = u2colMap->begin()->first, l = u2colMap->rbegin()->first;
2423       //isReverse = ( edgeIt->Orientation() == TopAbs_REVERSED );
2424       //if ( isReverse ) swap ( f, l ); -- u2colMap takes orientation into account
2425       const int nbCol = 5;
2426       for ( int i = 0; i < nbCol; ++i )
2427       {
2428         double u = f + i/double(nbCol) * ( l - f );
2429         const TNodeColumn* col = & getColumn( u2colMap, u )->second;
2430         if ( columns.empty() || col != columns.back() )
2431           columns.push_back( col );
2432       }
2433     }
2434   }
2435
2436   // Find tolerance to check transformations
2437
2438   double tol2;
2439   {
2440     Bnd_B3d bndBox;
2441     for ( int i = 0; i < columns.size(); ++i )
2442       bndBox.Add( gpXYZ( columns[i]->front() ));
2443     tol2 = bndBox.SquareExtent() * 1e-5;
2444   }
2445
2446   // Compute transformations
2447
2448   int xCol = -1;
2449   gp_Trsf fromCsZ, toCs0;
2450   gp_Ax3 cs0 = getLayerCoordSys(0, columns, xCol );
2451   //double dist0 = cs0.Location().Distance( gpXYZ( (*columns[0])[0]));
2452   toCs0.SetTransformation( cs0 );
2453   for ( int z = 1; z < zSize-1; ++z )
2454   {
2455     gp_Ax3 csZ = getLayerCoordSys(z, columns, xCol );
2456     //double distZ = csZ.Location().Distance( gpXYZ( (*columns[0])[z]));
2457     fromCsZ.SetTransformation( csZ );
2458     fromCsZ.Invert();
2459     gp_Trsf& t = trsf[ z-1 ];
2460     t = fromCsZ * toCs0;
2461     //t.SetScaleFactor( distZ/dist0 ); - it does not work properly, wrong base point
2462
2463     // check a transformation
2464     for ( int i = 0; i < columns.size(); ++i )
2465     {
2466       gp_Pnt p0 = gpXYZ( (*columns[i])[0] );
2467       gp_Pnt pz = gpXYZ( (*columns[i])[z] );
2468       t.Transforms( p0.ChangeCoord() );
2469       if ( p0.SquareDistance( pz ) > tol2 )
2470         return false;
2471     }
2472   }
2473   return true;
2474 }
2475
2476 //================================================================================
2477 /*!
2478  * \brief Check curve orientation of a bootom edge
2479   * \param meshDS - mesh DS
2480   * \param columnsMap - node columns map of side face
2481   * \param bottomEdge - the bootom edge
2482   * \param sideFaceID - side face in-block ID
2483   * \retval bool - true if orientation coinside with in-block forward orientation
2484  */
2485 //================================================================================
2486
2487 bool StdMeshers_PrismAsBlock::IsForwardEdge(SMESHDS_Mesh*           meshDS,
2488                                             const TParam2ColumnMap& columnsMap,
2489                                             const TopoDS_Edge &     bottomEdge,
2490                                             const int               sideFaceID)
2491 {
2492   bool isForward = false;
2493   if ( SMESH_MesherHelper::IsClosedEdge( bottomEdge ))
2494   {
2495     isForward = ( bottomEdge.Orientation() == TopAbs_FORWARD );
2496   }
2497   else
2498   {
2499     const TNodeColumn&     firstCol = columnsMap.begin()->second;
2500     const SMDS_MeshNode* bottomNode = firstCol[0];
2501     TopoDS_Shape firstVertex = SMESH_MesherHelper::GetSubShapeByNode( bottomNode, meshDS );
2502     isForward = ( firstVertex.IsSame( TopExp::FirstVertex( bottomEdge, true )));
2503   }
2504   // on 2 of 4 sides first vertex is end
2505   if ( sideFaceID == ID_Fx1z || sideFaceID == ID_F0yz )
2506     isForward = !isForward;
2507   return isForward;
2508 }
2509
2510 //================================================================================
2511 /*!
2512  * \brief Constructor
2513   * \param faceID - in-block ID
2514   * \param face - geom FACE
2515   * \param baseEdge - EDGE proreply oriented in the bottom EDGE !!!
2516   * \param columnsMap - map of node columns
2517   * \param first - first normalized param
2518   * \param last - last normalized param
2519  */
2520 //================================================================================
2521
2522 StdMeshers_PrismAsBlock::TSideFace::TSideFace(SMESH_MesherHelper*        helper,
2523                                               const int                  faceID,
2524                                               const Prism_3D::TQuadList& quadList,
2525                                               const TopoDS_Edge&         baseEdge,
2526                                               TParam2ColumnMap*          columnsMap,
2527                                               const double               first,
2528                                               const double               last):
2529   myID( faceID ),
2530   myParamToColumnMap( columnsMap ),
2531   myHelper( helper )
2532 {
2533   myParams.resize( 1 );
2534   myParams[ 0 ] = make_pair( first, last );
2535   mySurface     = PSurface( new BRepAdaptor_Surface( quadList.front()->face ));
2536   myBaseEdge    = baseEdge;
2537   myIsForward   = StdMeshers_PrismAsBlock::IsForwardEdge( myHelper->GetMeshDS(),
2538                                                           *myParamToColumnMap,
2539                                                           myBaseEdge, myID );
2540   if ( quadList.size() > 1 ) // side is vertically composite
2541   {
2542     // fill myShapeID2Surf map to enable finding a right surface by any sub-shape ID
2543
2544     SMESHDS_Mesh* meshDS = myHelper->GetMeshDS();
2545
2546     TopTools_IndexedDataMapOfShapeListOfShape subToFaces;
2547     Prism_3D::TQuadList::const_iterator quad = quadList.begin();
2548     for ( ; quad != quadList.end(); ++quad )
2549     {
2550       const TopoDS_Face& face = (*quad)->face;
2551       TopExp::MapShapesAndAncestors( face, TopAbs_VERTEX, TopAbs_FACE, subToFaces );
2552       TopExp::MapShapesAndAncestors( face, TopAbs_EDGE,   TopAbs_FACE, subToFaces );
2553       myShapeID2Surf.insert( make_pair( meshDS->ShapeToIndex( face ),
2554                                         PSurface( new BRepAdaptor_Surface( face ))));
2555     }
2556     for ( int i = 1; i <= subToFaces.Extent(); ++i )
2557     {
2558       const TopoDS_Shape&     sub = subToFaces.FindKey( i );
2559       TopTools_ListOfShape& faces = subToFaces( i );
2560       int subID  = meshDS->ShapeToIndex( sub );
2561       int faceID = meshDS->ShapeToIndex( faces.First() );
2562       myShapeID2Surf.insert ( make_pair( subID, myShapeID2Surf[ faceID ]));
2563     }
2564   }
2565 }
2566
2567 //================================================================================
2568 /*!
2569  * \brief Constructor of complex side face
2570  */
2571 //================================================================================
2572
2573 StdMeshers_PrismAsBlock::TSideFace::
2574 TSideFace(const vector< TSideFace* >&             components,
2575           const vector< pair< double, double> > & params)
2576   :myID( components[0] ? components[0]->myID : 0 ),
2577    myParamToColumnMap( 0 ),
2578    myParams( params ),
2579    myIsForward( true ),
2580    myComponents( components ),
2581    myHelper( components[0] ? components[0]->myHelper : 0 )
2582 {}
2583 //================================================================================
2584 /*!
2585  * \brief Copy constructor
2586   * \param other - other side
2587  */
2588 //================================================================================
2589
2590 StdMeshers_PrismAsBlock::TSideFace::TSideFace( const TSideFace& other )
2591 {
2592   myID               = other.myID;
2593   mySurface          = other.mySurface;
2594   myBaseEdge         = other.myBaseEdge;
2595   myParams           = other.myParams;
2596   myIsForward        = other.myIsForward;
2597   myHelper           = other.myHelper;
2598   myParamToColumnMap = other.myParamToColumnMap;
2599
2600   myComponents.resize( other.myComponents.size());
2601   for (int i = 0 ; i < myComponents.size(); ++i )
2602     myComponents[ i ] = new TSideFace( *other.myComponents[ i ]);
2603 }
2604
2605 //================================================================================
2606 /*!
2607  * \brief Deletes myComponents
2608  */
2609 //================================================================================
2610
2611 StdMeshers_PrismAsBlock::TSideFace::~TSideFace()
2612 {
2613   for (int i = 0 ; i < myComponents.size(); ++i )
2614     if ( myComponents[ i ] )
2615       delete myComponents[ i ];
2616 }
2617
2618 //================================================================================
2619 /*!
2620  * \brief Return geometry of the vertical curve
2621   * \param isMax - true means curve located closer to (1,1,1) block point
2622   * \retval Adaptor3d_Curve* - curve adaptor
2623  */
2624 //================================================================================
2625
2626 Adaptor3d_Curve* StdMeshers_PrismAsBlock::TSideFace::VertiCurve(const bool isMax) const
2627 {
2628   if ( !myComponents.empty() ) {
2629     if ( isMax )
2630       return myComponents.back()->VertiCurve(isMax);
2631     else
2632       return myComponents.front()->VertiCurve(isMax);
2633   }
2634   double f = myParams[0].first, l = myParams[0].second;
2635   if ( !myIsForward ) std::swap( f, l );
2636   return new TVerticalEdgeAdaptor( myParamToColumnMap, isMax ? l : f );
2637 }
2638
2639 //================================================================================
2640 /*!
2641  * \brief Return geometry of the top or bottom curve
2642   * \param isTop - 
2643   * \retval Adaptor3d_Curve* - 
2644  */
2645 //================================================================================
2646
2647 Adaptor3d_Curve* StdMeshers_PrismAsBlock::TSideFace::HorizCurve(const bool isTop) const
2648 {
2649   return new THorizontalEdgeAdaptor( this, isTop );
2650 }
2651
2652 //================================================================================
2653 /*!
2654  * \brief Return pcurves
2655   * \param pcurv - array of 4 pcurves
2656   * \retval bool - is a success
2657  */
2658 //================================================================================
2659
2660 bool StdMeshers_PrismAsBlock::TSideFace::GetPCurves(Adaptor2d_Curve2d* pcurv[4]) const
2661 {
2662   int iEdge[ 4 ] = { BOTTOM_EDGE, TOP_EDGE, V0_EDGE, V1_EDGE };
2663
2664   for ( int i = 0 ; i < 4 ; ++i ) {
2665     Handle(Geom2d_Line) line;
2666     switch ( iEdge[ i ] ) {
2667     case TOP_EDGE:
2668       line = new Geom2d_Line( gp_Pnt2d( 0, 1 ), gp::DX2d() ); break;
2669     case BOTTOM_EDGE:
2670       line = new Geom2d_Line( gp::Origin2d(), gp::DX2d() ); break;
2671     case V0_EDGE:
2672       line = new Geom2d_Line( gp::Origin2d(), gp::DY2d() ); break;
2673     case V1_EDGE:
2674       line = new Geom2d_Line( gp_Pnt2d( 1, 0 ), gp::DY2d() ); break;
2675     }
2676     pcurv[ i ] = new Geom2dAdaptor_Curve( line, 0, 1 );
2677   }
2678   return true;
2679 }
2680
2681 //================================================================================
2682 /*!
2683  * \brief Returns geometry of pcurve on a horizontal face
2684   * \param isTop - is top or bottom face
2685   * \param horFace - a horizontal face
2686   * \retval Adaptor2d_Curve2d* - curve adaptor
2687  */
2688 //================================================================================
2689
2690 Adaptor2d_Curve2d*
2691 StdMeshers_PrismAsBlock::TSideFace::HorizPCurve(const bool         isTop,
2692                                                 const TopoDS_Face& horFace) const
2693 {
2694   return new TPCurveOnHorFaceAdaptor( this, isTop, horFace );
2695 }
2696
2697 //================================================================================
2698 /*!
2699  * \brief Return a component corresponding to parameter
2700   * \param U - parameter along a horizontal size
2701   * \param localU - parameter along a horizontal size of a component
2702   * \retval TSideFace* - found component
2703  */
2704 //================================================================================
2705
2706 StdMeshers_PrismAsBlock::TSideFace*
2707 StdMeshers_PrismAsBlock::TSideFace::GetComponent(const double U,double & localU) const
2708 {
2709   localU = U;
2710   if ( myComponents.empty() )
2711     return const_cast<TSideFace*>( this );
2712
2713   int i;
2714   for ( i = 0; i < myComponents.size(); ++i )
2715     if ( U < myParams[ i ].second )
2716       break;
2717   if ( i >= myComponents.size() )
2718     i = myComponents.size() - 1;
2719
2720   double f = myParams[ i ].first, l = myParams[ i ].second;
2721   localU = ( U - f ) / ( l - f );
2722   return myComponents[ i ];
2723 }
2724
2725 //================================================================================
2726 /*!
2727  * \brief Find node columns for a parameter
2728   * \param U - parameter along a horizontal edge
2729   * \param col1 - the 1st found column
2730   * \param col2 - the 2nd found column
2731   * \retval r - normalized position of U between the found columns
2732  */
2733 //================================================================================
2734
2735 double StdMeshers_PrismAsBlock::TSideFace::GetColumns(const double      U,
2736                                                       TParam2ColumnIt & col1,
2737                                                       TParam2ColumnIt & col2) const
2738 {
2739   double u = U, r = 0;
2740   if ( !myComponents.empty() ) {
2741     TSideFace * comp = GetComponent(U,u);
2742     return comp->GetColumns( u, col1, col2 );
2743   }
2744
2745   if ( !myIsForward )
2746     u = 1 - u;
2747   double f = myParams[0].first, l = myParams[0].second;
2748   u = f + u * ( l - f );
2749
2750   col1 = col2 = getColumn( myParamToColumnMap, u );
2751   if ( ++col2 == myParamToColumnMap->end() ) {
2752     --col2;
2753     r = 0.5;
2754   }
2755   else {
2756     double uf = col1->first;
2757     double ul = col2->first;
2758     r = ( u - uf ) / ( ul - uf );
2759   }
2760   return r;
2761 }
2762
2763 //================================================================================
2764 /*!
2765  * \brief Return coordinates by normalized params
2766   * \param U - horizontal param
2767   * \param V - vertical param
2768   * \retval gp_Pnt - result point
2769  */
2770 //================================================================================
2771
2772 gp_Pnt StdMeshers_PrismAsBlock::TSideFace::Value(const Standard_Real U,
2773                                                  const Standard_Real V) const
2774 {
2775   if ( !myComponents.empty() ) {
2776     double u;
2777     TSideFace * comp = GetComponent(U,u);
2778     return comp->Value( u, V );
2779   }
2780
2781   TParam2ColumnIt u_col1, u_col2;
2782   double vR, hR = GetColumns( U, u_col1, u_col2 );
2783
2784   const SMDS_MeshNode* nn[4];
2785
2786   // BEGIN issue 0020680: Bad cell created by Radial prism in center of torus
2787   // Workaround for a wrongly located point returned by mySurface.Value() for
2788   // UV located near boundary of BSpline surface.
2789   // To bypass the problem, we take point from 3D curve of EDGE.
2790   // It solves pb of the bloc_fiss_new.py
2791   const double tol = 1e-3;
2792   if ( V < tol || V+tol >= 1. )
2793   {
2794     nn[0] = V < tol ? u_col1->second.front() : u_col1->second.back();
2795     nn[2] = V < tol ? u_col2->second.front() : u_col2->second.back();
2796     TopoDS_Edge edge;
2797     if ( V < tol )
2798     {
2799       edge = myBaseEdge;
2800     }
2801     else
2802     {
2803       TopoDS_Shape s = myHelper->GetSubShapeByNode( nn[0], myHelper->GetMeshDS() );
2804       if ( s.ShapeType() != TopAbs_EDGE )
2805         s = myHelper->GetSubShapeByNode( nn[2], myHelper->GetMeshDS() );
2806       if ( s.ShapeType() == TopAbs_EDGE )
2807         edge = TopoDS::Edge( s );
2808     }
2809     if ( !edge.IsNull() )
2810     {
2811       double u1 = myHelper->GetNodeU( edge, nn[0] );
2812       double u3 = myHelper->GetNodeU( edge, nn[2] );
2813       double u = u1 * ( 1 - hR ) + u3 * hR;
2814       TopLoc_Location loc; double f,l;
2815       Handle(Geom_Curve) curve = BRep_Tool::Curve( edge,loc,f,l );
2816       return curve->Value( u ).Transformed( loc );
2817     }
2818   }
2819   // END issue 0020680: Bad cell created by Radial prism in center of torus
2820
2821   vR = getRAndNodes( & u_col1->second, V, nn[0], nn[1] );
2822   vR = getRAndNodes( & u_col2->second, V, nn[2], nn[3] );
2823
2824   if ( !myShapeID2Surf.empty() ) // side is vertically composite
2825   {
2826     // find a FACE on which the 4 nodes lie
2827     TSideFace* me = (TSideFace*) this;
2828     int notFaceID1 = 0, notFaceID2 = 0;
2829     for ( int i = 0; i < 4; ++i )
2830       if ( nn[i]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) // node on FACE
2831       {
2832         me->mySurface = me->myShapeID2Surf[ nn[i]->getshapeId() ];
2833         notFaceID2 = 0;
2834         break;
2835       }
2836       else if ( notFaceID1 == 0 ) // node on EDGE or VERTEX
2837       {
2838         me->mySurface  = me->myShapeID2Surf[ nn[i]->getshapeId() ];
2839         notFaceID1 = nn[i]->getshapeId();
2840       }
2841       else if ( notFaceID1 != nn[i]->getshapeId() ) // node on other EDGE or VERTEX
2842       {
2843         if ( mySurface != me->myShapeID2Surf[ nn[i]->getshapeId() ])
2844           notFaceID2 = nn[i]->getshapeId();
2845       }
2846     if ( notFaceID2 ) // no nodes of FACE and nodes are on different FACEs
2847     {
2848       SMESHDS_Mesh* meshDS = myHelper->GetMeshDS();
2849       TopoDS_Shape face = myHelper->GetCommonAncestor( meshDS->IndexToShape( notFaceID1 ),
2850                                                        meshDS->IndexToShape( notFaceID2 ),
2851                                                        *myHelper->GetMesh(),
2852                                                        TopAbs_FACE );
2853       if ( face.IsNull() ) 
2854         throw SALOME_Exception("StdMeshers_PrismAsBlock::TSideFace::Value() face.IsNull()");
2855       int faceID = meshDS->ShapeToIndex( face );
2856       me->mySurface = me->myShapeID2Surf[ faceID ];
2857       if ( !mySurface )
2858         throw SALOME_Exception("StdMeshers_PrismAsBlock::TSideFace::Value() !mySurface");
2859     }
2860   }
2861   
2862   gp_XY uv1 = myHelper->GetNodeUV( mySurface->Face(), nn[0], nn[2]);
2863   gp_XY uv2 = myHelper->GetNodeUV( mySurface->Face(), nn[1], nn[3]);
2864   gp_XY uv12 = uv1 * ( 1 - vR ) + uv2 * vR;
2865
2866   gp_XY uv3 = myHelper->GetNodeUV( mySurface->Face(), nn[2], nn[0]);
2867   gp_XY uv4 = myHelper->GetNodeUV( mySurface->Face(), nn[3], nn[1]);
2868   gp_XY uv34 = uv3 * ( 1 - vR ) + uv4 * vR;
2869
2870   gp_XY uv = uv12 * ( 1 - hR ) + uv34 * hR;
2871
2872   gp_Pnt p = mySurface->Value( uv.X(), uv.Y() );
2873   return p;
2874 }
2875
2876
2877 //================================================================================
2878 /*!
2879  * \brief Return boundary edge
2880   * \param edge - edge index
2881   * \retval TopoDS_Edge - found edge
2882  */
2883 //================================================================================
2884
2885 TopoDS_Edge StdMeshers_PrismAsBlock::TSideFace::GetEdge(const int iEdge) const
2886 {
2887   if ( !myComponents.empty() ) {
2888     switch ( iEdge ) {
2889     case V0_EDGE : return myComponents.front()->GetEdge( iEdge );
2890     case V1_EDGE : return myComponents.back() ->GetEdge( iEdge );
2891     default: return TopoDS_Edge();
2892     }
2893   }
2894   TopoDS_Shape edge;
2895   const SMDS_MeshNode* node = 0;
2896   SMESHDS_Mesh * meshDS = myHelper->GetMesh()->GetMeshDS();
2897   TNodeColumn* column;
2898
2899   switch ( iEdge ) {
2900   case TOP_EDGE:
2901   case BOTTOM_EDGE:
2902     column = & (( ++myParamToColumnMap->begin())->second );
2903     node = ( iEdge == TOP_EDGE ) ? column->back() : column->front();
2904     edge = myHelper->GetSubShapeByNode ( node, meshDS );
2905     if ( edge.ShapeType() == TopAbs_VERTEX ) {
2906       column = & ( myParamToColumnMap->begin()->second );
2907       node = ( iEdge == TOP_EDGE ) ? column->back() : column->front();
2908     }
2909     break;
2910   case V0_EDGE:
2911   case V1_EDGE: {
2912     bool back = ( iEdge == V1_EDGE );
2913     if ( !myIsForward ) back = !back;
2914     if ( back )
2915       column = & ( myParamToColumnMap->rbegin()->second );
2916     else
2917       column = & ( myParamToColumnMap->begin()->second );
2918     if ( column->size() > 0 )
2919       edge = myHelper->GetSubShapeByNode( (*column)[ 1 ], meshDS );
2920     if ( edge.IsNull() || edge.ShapeType() == TopAbs_VERTEX )
2921       node = column->front();
2922     break;
2923   }
2924   default:;
2925   }
2926   if ( !edge.IsNull() && edge.ShapeType() == TopAbs_EDGE )
2927     return TopoDS::Edge( edge );
2928
2929   // find edge by 2 vertices
2930   TopoDS_Shape V1 = edge;
2931   TopoDS_Shape V2 = myHelper->GetSubShapeByNode( node, meshDS );
2932   if ( !V2.IsNull() && V2.ShapeType() == TopAbs_VERTEX && !V2.IsSame( V1 ))
2933   {
2934     TopoDS_Shape ancestor = myHelper->GetCommonAncestor( V1, V2, *myHelper->GetMesh(), TopAbs_EDGE);
2935     if ( !ancestor.IsNull() )
2936       return TopoDS::Edge( ancestor );
2937   }
2938   return TopoDS_Edge();
2939 }
2940
2941 //================================================================================
2942 /*!
2943  * \brief Fill block sub-shapes
2944   * \param shapeMap - map to fill in
2945   * \retval int - nb inserted sub-shapes
2946  */
2947 //================================================================================
2948
2949 int StdMeshers_PrismAsBlock::TSideFace::InsertSubShapes(TBlockShapes& shapeMap) const
2950 {
2951   int nbInserted = 0;
2952
2953   // Insert edges
2954   vector< int > edgeIdVec;
2955   SMESH_Block::GetFaceEdgesIDs( myID, edgeIdVec );
2956
2957   for ( int i = BOTTOM_EDGE; i <=V1_EDGE ; ++i ) {
2958     TopoDS_Edge e = GetEdge( i );
2959     if ( !e.IsNull() ) {
2960       nbInserted += SMESH_Block::Insert( e, edgeIdVec[ i ], shapeMap);
2961     }
2962   }
2963
2964   // Insert corner vertices
2965
2966   TParam2ColumnIt col1, col2 ;
2967   vector< int > vertIdVec;
2968
2969   // from V0 column
2970   SMESH_Block::GetEdgeVertexIDs( edgeIdVec[ V0_EDGE ], vertIdVec);
2971   GetColumns(0, col1, col2 );
2972   const SMDS_MeshNode* node0 = col1->second.front();
2973   const SMDS_MeshNode* node1 = col1->second.back();
2974   TopoDS_Shape v0 = myHelper->GetSubShapeByNode( node0, myHelper->GetMeshDS());
2975   TopoDS_Shape v1 = myHelper->GetSubShapeByNode( node1, myHelper->GetMeshDS());
2976   if ( v0.ShapeType() == TopAbs_VERTEX ) {
2977     nbInserted += SMESH_Block::Insert( v0, vertIdVec[ 0 ], shapeMap);
2978   }
2979   if ( v1.ShapeType() == TopAbs_VERTEX ) {
2980     nbInserted += SMESH_Block::Insert( v1, vertIdVec[ 1 ], shapeMap);
2981   }
2982   
2983   // from V1 column
2984   SMESH_Block::GetEdgeVertexIDs( edgeIdVec[ V1_EDGE ], vertIdVec);
2985   GetColumns(1, col1, col2 );
2986   node0 = col2->second.front();
2987   node1 = col2->second.back();
2988   v0 = myHelper->GetSubShapeByNode( node0, myHelper->GetMeshDS());
2989   v1 = myHelper->GetSubShapeByNode( node1, myHelper->GetMeshDS());
2990   if ( v0.ShapeType() == TopAbs_VERTEX ) {
2991     nbInserted += SMESH_Block::Insert( v0, vertIdVec[ 0 ], shapeMap);
2992   }
2993   if ( v1.ShapeType() == TopAbs_VERTEX ) {
2994     nbInserted += SMESH_Block::Insert( v1, vertIdVec[ 1 ], shapeMap);
2995   }
2996
2997 //   TopoDS_Vertex V0, V1, Vcom;
2998 //   TopExp::Vertices( myBaseEdge, V0, V1, true );
2999 //   if ( !myIsForward ) std::swap( V0, V1 );
3000
3001 //   // bottom vertex IDs
3002 //   SMESH_Block::GetEdgeVertexIDs( edgeIdVec[ _u0 ], vertIdVec);
3003 //   SMESH_Block::Insert( V0, vertIdVec[ 0 ], shapeMap);
3004 //   SMESH_Block::Insert( V1, vertIdVec[ 1 ], shapeMap);
3005
3006 //   TopoDS_Edge sideEdge = GetEdge( V0_EDGE );
3007 //   if ( sideEdge.IsNull() || !TopExp::CommonVertex( botEdge, sideEdge, Vcom ))
3008 //     return false;
3009
3010 //   // insert one side edge
3011 //   int edgeID;
3012 //   if ( Vcom.IsSame( V0 )) edgeID = edgeIdVec[ _v0 ];
3013 //   else                    edgeID = edgeIdVec[ _v1 ];
3014 //   SMESH_Block::Insert( sideEdge, edgeID, shapeMap);
3015
3016 //   // top vertex of the side edge
3017 //   SMESH_Block::GetEdgeVertexIDs( edgeID, vertIdVec);
3018 //   TopoDS_Vertex Vtop = TopExp::FirstVertex( sideEdge );
3019 //   if ( Vcom.IsSame( Vtop ))
3020 //     Vtop = TopExp::LastVertex( sideEdge );
3021 //   SMESH_Block::Insert( Vtop, vertIdVec[ 1 ], shapeMap);
3022
3023 //   // other side edge
3024 //   sideEdge = GetEdge( V1_EDGE );
3025 //   if ( sideEdge.IsNull() )
3026 //     return false;
3027 //   if ( edgeID = edgeIdVec[ _v1 ]) edgeID = edgeIdVec[ _v0 ];
3028 //   else                            edgeID = edgeIdVec[ _v1 ];
3029 //   SMESH_Block::Insert( sideEdge, edgeID, shapeMap);
3030   
3031 //   // top edge
3032 //   TopoDS_Edge topEdge = GetEdge( TOP_EDGE );
3033 //   SMESH_Block::Insert( topEdge, edgeIdVec[ _u1 ], shapeMap);
3034
3035 //   // top vertex of the other side edge
3036 //   if ( !TopExp::CommonVertex( topEdge, sideEdge, Vcom ))
3037 //     return false;
3038 //   SMESH_Block::GetEdgeVertexIDs( edgeID, vertIdVec );
3039 //   SMESH_Block::Insert( Vcom, vertIdVec[ 1 ], shapeMap);
3040
3041   return nbInserted;
3042 }
3043
3044 //================================================================================
3045 /*!
3046  * \brief Dump ids of nodes of sides
3047  */
3048 //================================================================================
3049
3050 void StdMeshers_PrismAsBlock::TSideFace::dumpNodes(int nbNodes) const
3051 {
3052 #ifdef _DEBUG_
3053   cout << endl << "NODES OF FACE "; SMESH_Block::DumpShapeID( myID, cout ) << endl;
3054   THorizontalEdgeAdaptor* hSize0 = (THorizontalEdgeAdaptor*) HorizCurve(0);
3055   cout << "Horiz side 0: "; hSize0->dumpNodes(nbNodes); cout << endl;
3056   THorizontalEdgeAdaptor* hSize1 = (THorizontalEdgeAdaptor*) HorizCurve(1);
3057   cout << "Horiz side 1: "; hSize1->dumpNodes(nbNodes); cout << endl;
3058   TVerticalEdgeAdaptor* vSide0 = (TVerticalEdgeAdaptor*) VertiCurve(0);
3059   cout << "Verti side 0: "; vSide0->dumpNodes(nbNodes); cout << endl;
3060   TVerticalEdgeAdaptor* vSide1 = (TVerticalEdgeAdaptor*) VertiCurve(1);
3061   cout << "Verti side 1: "; vSide1->dumpNodes(nbNodes); cout << endl;
3062   delete hSize0; delete hSize1; delete vSide0; delete vSide1;
3063 #endif
3064 }
3065
3066 //================================================================================
3067 /*!
3068  * \brief Creates TVerticalEdgeAdaptor 
3069   * \param columnsMap - node column map
3070   * \param parameter - normalized parameter
3071  */
3072 //================================================================================
3073
3074 StdMeshers_PrismAsBlock::TVerticalEdgeAdaptor::
3075 TVerticalEdgeAdaptor( const TParam2ColumnMap* columnsMap, const double parameter)
3076 {
3077   myNodeColumn = & getColumn( columnsMap, parameter )->second;
3078 }
3079
3080 //================================================================================
3081 /*!
3082  * \brief Return coordinates for the given normalized parameter
3083   * \param U - normalized parameter
3084   * \retval gp_Pnt - coordinates
3085  */
3086 //================================================================================
3087
3088 gp_Pnt StdMeshers_PrismAsBlock::TVerticalEdgeAdaptor::Value(const Standard_Real U) const
3089 {
3090   const SMDS_MeshNode* n1;
3091   const SMDS_MeshNode* n2;
3092   double r = getRAndNodes( myNodeColumn, U, n1, n2 );
3093   return gpXYZ(n1) * ( 1 - r ) + gpXYZ(n2) * r;
3094 }
3095
3096 //================================================================================
3097 /*!
3098  * \brief Dump ids of nodes
3099  */
3100 //================================================================================
3101
3102 void StdMeshers_PrismAsBlock::TVerticalEdgeAdaptor::dumpNodes(int nbNodes) const
3103 {
3104 #ifdef _DEBUG_
3105   for ( int i = 0; i < nbNodes && i < myNodeColumn->size(); ++i )
3106     cout << (*myNodeColumn)[i]->GetID() << " ";
3107   if ( nbNodes < myNodeColumn->size() )
3108     cout << myNodeColumn->back()->GetID();
3109 #endif
3110 }
3111
3112 //================================================================================
3113 /*!
3114  * \brief Return coordinates for the given normalized parameter
3115   * \param U - normalized parameter
3116   * \retval gp_Pnt - coordinates
3117  */
3118 //================================================================================
3119
3120 gp_Pnt StdMeshers_PrismAsBlock::THorizontalEdgeAdaptor::Value(const Standard_Real U) const
3121 {
3122   return mySide->TSideFace::Value( U, myV );
3123 }
3124
3125 //================================================================================
3126 /*!
3127  * \brief Dump ids of <nbNodes> first nodes and the last one
3128  */
3129 //================================================================================
3130
3131 void StdMeshers_PrismAsBlock::THorizontalEdgeAdaptor::dumpNodes(int nbNodes) const
3132 {
3133 #ifdef _DEBUG_
3134   // Not bedugged code. Last node is sometimes incorrect
3135   const TSideFace* side = mySide;
3136   double u = 0;
3137   if ( mySide->IsComplex() )
3138     side = mySide->GetComponent(0,u);
3139
3140   TParam2ColumnIt col, col2;
3141   TParam2ColumnMap* u2cols = side->GetColumns();
3142   side->GetColumns( u , col, col2 );
3143   
3144   int j, i = myV ? mySide->ColumnHeight()-1 : 0;
3145
3146   const SMDS_MeshNode* n = 0;
3147   const SMDS_MeshNode* lastN
3148     = side->IsForward() ? u2cols->rbegin()->second[ i ] : u2cols->begin()->second[ i ];
3149   for ( j = 0; j < nbNodes && n != lastN; ++j )
3150   {
3151     n = col->second[ i ];
3152     cout << n->GetID() << " ";
3153     if ( side->IsForward() )
3154       ++col;
3155     else
3156       --col;
3157   }
3158
3159   // last node
3160   u = 1;
3161   if ( mySide->IsComplex() )
3162     side = mySide->GetComponent(1,u);
3163
3164   side->GetColumns( u , col, col2 );
3165   if ( n != col->second[ i ] )
3166     cout << col->second[ i ]->GetID();
3167 #endif
3168 }
3169 //================================================================================
3170 /*!
3171  * \brief Return UV on pcurve for the given normalized parameter
3172   * \param U - normalized parameter
3173   * \retval gp_Pnt - coordinates
3174  */
3175 //================================================================================
3176
3177 gp_Pnt2d StdMeshers_PrismAsBlock::TPCurveOnHorFaceAdaptor::Value(const Standard_Real U) const
3178 {
3179   TParam2ColumnIt u_col1, u_col2;
3180   double r = mySide->GetColumns( U, u_col1, u_col2 );
3181   gp_XY uv1 = mySide->GetNodeUV( myFace, u_col1->second[ myZ ]);
3182   gp_XY uv2 = mySide->GetNodeUV( myFace, u_col2->second[ myZ ]);
3183   return uv1 * ( 1 - r ) + uv2 * r;
3184 }