Salome HOME
dfa510427326a8b15da1fd62f62f9fc7758a85d4
[modules/smesh.git] / src / StdMeshers / StdMeshers_Quadrangle_2D.cxx
1 //  SMESH SMESH : implementaion of SMESH idl descriptions
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
5 // 
6 //  This library is free software; you can redistribute it and/or 
7 //  modify it under the terms of the GNU Lesser General Public 
8 //  License as published by the Free Software Foundation; either 
9 //  version 2.1 of the License. 
10 // 
11 //  This library is distributed in the hope that it will be useful, 
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
14 //  Lesser General Public License for more details. 
15 // 
16 //  You should have received a copy of the GNU Lesser General Public 
17 //  License along with this library; if not, write to the Free Software 
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
19 // 
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //
23 //
24 //  File   : StdMeshers_Quadrangle_2D.cxx
25 //           Moved here from SMESH_Quadrangle_2D.cxx
26 //  Author : Paul RASCLE, EDF
27 //  Module : SMESH
28 //  $Header$
29
30 #include "StdMeshers_Quadrangle_2D.hxx"
31
32 #include "StdMeshers_FaceSide.hxx"
33
34 #include "SMESH_Gen.hxx"
35 #include "SMESH_Mesh.hxx"
36 #include "SMESH_subMesh.hxx"
37 #include "SMESH_MesherHelper.hxx"
38 #include "SMESH_Block.hxx"
39 #include "SMESH_Comment.hxx"
40
41 #include "SMDS_MeshElement.hxx"
42 #include "SMDS_MeshNode.hxx"
43 #include "SMDS_EdgePosition.hxx"
44 #include "SMDS_FacePosition.hxx"
45
46 #include <BRepTools.hxx>
47 #include <BRepTools_WireExplorer.hxx>
48 #include <BRep_Tool.hxx>
49 #include <Geom_Surface.hxx>
50 #include <NCollection_DefineArray2.hxx>
51 #include <Precision.hxx>
52 #include <TColStd_SequenceOfReal.hxx>
53 #include <TColgp_SequenceOfXY.hxx>
54 #include <TopExp.hxx>
55 #include <TopoDS.hxx>
56
57 #include "utilities.h"
58 #include "Utils_ExceptHandlers.hxx"
59
60 #ifndef StdMeshers_Array2OfNode_HeaderFile
61 #define StdMeshers_Array2OfNode_HeaderFile
62 typedef const SMDS_MeshNode* SMDS_MeshNodePtr;
63 DEFINE_BASECOLLECTION (StdMeshers_BaseCollectionNodePtr, SMDS_MeshNodePtr)
64 DEFINE_ARRAY2(StdMeshers_Array2OfNode,
65               StdMeshers_BaseCollectionNodePtr, SMDS_MeshNodePtr)
66 #endif
67
68 using namespace std;
69
70 typedef gp_XY gp_UV;
71 typedef SMESH_Comment TComm;
72
73 //=============================================================================
74 /*!
75  *  
76  */
77 //=============================================================================
78
79 StdMeshers_Quadrangle_2D::StdMeshers_Quadrangle_2D (int hypId, int studyId, SMESH_Gen* gen)
80      : SMESH_2D_Algo(hypId, studyId, gen)
81 {
82   MESSAGE("StdMeshers_Quadrangle_2D::StdMeshers_Quadrangle_2D");
83   _name = "Quadrangle_2D";
84   _shapeType = (1 << TopAbs_FACE);
85   _compatibleHypothesis.push_back("QuadranglePreference");
86   _compatibleHypothesis.push_back("TrianglePreference");
87   myTool = 0;
88 }
89
90 //=============================================================================
91 /*!
92  *  
93  */
94 //=============================================================================
95
96 StdMeshers_Quadrangle_2D::~StdMeshers_Quadrangle_2D()
97 {
98   MESSAGE("StdMeshers_Quadrangle_2D::~StdMeshers_Quadrangle_2D");
99 }
100
101 //=============================================================================
102 /*!
103  *  
104  */
105 //=============================================================================
106
107 bool StdMeshers_Quadrangle_2D::CheckHypothesis
108                          (SMESH_Mesh&                          aMesh,
109                           const TopoDS_Shape&                  aShape,
110                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
111 {
112   bool isOk = true;
113   aStatus = SMESH_Hypothesis::HYP_OK;
114
115
116   const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape, false);
117   const SMESHDS_Hypothesis *theHyp = 0;
118   
119   if(hyps.size() > 0){
120     theHyp = *hyps.begin();
121     if(strcmp("QuadranglePreference", theHyp->GetName()) == 0) {
122       myQuadranglePreference= true;
123       myTrianglePreference= false; 
124     }
125     else if(strcmp("TrianglePreference", theHyp->GetName()) == 0){
126       myQuadranglePreference= false;
127       myTrianglePreference= true; 
128     }
129   }
130   else {
131     myQuadranglePreference = false;
132     myTrianglePreference = false;
133   }
134   return isOk;
135 }
136
137 //=============================================================================
138 /*!
139  *  
140  */
141 //=============================================================================
142
143 bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
144                                         const TopoDS_Shape& aShape)// throw (SALOME_Exception)
145 {
146   // PAL14921. Enable catching std::bad_alloc and Standard_OutOfMemory outside
147   //Unexpect aCatchSalomeException);
148
149   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
150   aMesh.GetSubMesh(aShape);
151
152   SMESH_MesherHelper helper(aMesh);
153   myTool = &helper;
154
155   _quadraticMesh = myTool->IsQuadraticSubMesh(aShape);
156
157   FaceQuadStruct *quad = CheckNbEdges( aMesh, aShape );
158   std::auto_ptr<FaceQuadStruct> quadDeleter( quad ); // to delete quad at exit from Compute()
159   if (!quad)
160     return false;
161
162   if(myQuadranglePreference) {
163     int n1 = quad->side[0]->NbPoints();
164     int n2 = quad->side[1]->NbPoints();
165     int n3 = quad->side[2]->NbPoints();
166     int n4 = quad->side[3]->NbPoints();
167     int nfull = n1+n2+n3+n4;
168     int ntmp = nfull/2;
169     ntmp = ntmp*2;
170     if( nfull==ntmp && ( (n1!=n3) || (n2!=n4) ) ) {
171       // special path for using only quandrangle faces
172       bool ok = ComputeQuadPref(aMesh, aShape, quad);
173       return ok;
174     }
175   }
176
177   // set normalized grid on unit square in parametric domain
178   
179   if (!SetNormalizedGrid(aMesh, aShape, quad))
180     return false;
181
182   // --- compute 3D values on points, store points & quadrangles
183
184   int nbdown  = quad->side[0]->NbPoints();
185   int nbup    = quad->side[2]->NbPoints();
186
187   int nbright = quad->side[1]->NbPoints();
188   int nbleft  = quad->side[3]->NbPoints();
189
190   int nbhoriz  = Min(nbdown, nbup);
191   int nbvertic = Min(nbright, nbleft);
192
193   const TopoDS_Face& F = TopoDS::Face(aShape);
194   Handle(Geom_Surface) S = BRep_Tool::Surface(F);
195
196   // internal mesh nodes
197   int i, j, geomFaceID = meshDS->ShapeToIndex( F );
198   for (i = 1; i < nbhoriz - 1; i++) {
199     for (j = 1; j < nbvertic - 1; j++) {
200       int ij = j * nbhoriz + i;
201       double u = quad->uv_grid[ij].u;
202       double v = quad->uv_grid[ij].v;
203       gp_Pnt P = S->Value(u, v);
204       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
205       meshDS->SetNodeOnFace(node, geomFaceID, u, v);
206       quad->uv_grid[ij].node = node;
207     }
208   }
209   
210   // mesh faces
211
212   //             [2]
213   //      --.--.--.--.--.--  nbvertic
214   //     |                 | ^
215   //     |                 | ^
216   // [3] |                 | ^ j  [1]
217   //     |                 | ^
218   //     |                 | ^
219   //      ---.----.----.---  0
220   //     0 > > > > > > > > nbhoriz
221   //              i
222   //             [0]
223   
224   i = 0;
225   int ilow = 0;
226   int iup = nbhoriz - 1;
227   if (quad->isEdgeOut[3]) { ilow++; } else { if (quad->isEdgeOut[1]) iup--; }
228   
229   int jlow = 0;
230   int jup = nbvertic - 1;
231   if (quad->isEdgeOut[0]) { jlow++; } else { if (quad->isEdgeOut[2]) jup--; }
232   
233   // regular quadrangles
234   for (i = ilow; i < iup; i++) {
235     for (j = jlow; j < jup; j++) {
236       const SMDS_MeshNode *a, *b, *c, *d;
237       a = quad->uv_grid[j * nbhoriz + i].node;
238       b = quad->uv_grid[j * nbhoriz + i + 1].node;
239       c = quad->uv_grid[(j + 1) * nbhoriz + i + 1].node;
240       d = quad->uv_grid[(j + 1) * nbhoriz + i].node;
241       SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
242       meshDS->SetMeshElementOnShape(face, geomFaceID);
243     }
244   }
245
246   const vector<UVPtStruct>& uv_e0 = quad->side[0]->GetUVPtStruct(true,0 );
247   const vector<UVPtStruct>& uv_e1 = quad->side[1]->GetUVPtStruct(false,1);
248   const vector<UVPtStruct>& uv_e2 = quad->side[2]->GetUVPtStruct(true,1 );
249   const vector<UVPtStruct>& uv_e3 = quad->side[3]->GetUVPtStruct(false,0);
250
251   if ( uv_e0.empty() || uv_e1.empty() || uv_e2.empty() || uv_e3.empty() )
252     return error( COMPERR_BAD_INPUT_MESH );
253
254   double eps = Precision::Confusion();
255
256   // Boundary quadrangles
257   
258   if (quad->isEdgeOut[0]) {
259     // Down edge is out
260     // 
261     // |___|___|___|___|___|___|
262     // |   |   |   |   |   |   |
263     // |___|___|___|___|___|___|
264     // |   |   |   |   |   |   |
265     // |___|___|___|___|___|___| __ first row of the regular grid
266     // .  .  .  .  .  .  .  .  . __ down edge nodes
267     // 
268     // >->->->->->->->->->->->-> -- direction of processing
269       
270     int g = 0; // number of last processed node in the regular grid
271     
272     // number of last node of the down edge to be processed
273     int stop = nbdown - 1;
274     // if right edge is out, we will stop at a node, previous to the last one
275     if (quad->isEdgeOut[1]) stop--;
276     
277     // for each node of the down edge find nearest node
278     // in the first row of the regular grid and link them
279     for (i = 0; i < stop; i++) {
280       const SMDS_MeshNode *a, *b, *c, *d;
281       a = uv_e0[i].node;
282       b = uv_e0[i + 1].node;
283       gp_Pnt pb (b->X(), b->Y(), b->Z());
284       
285       // find node c in the regular grid, which will be linked with node b
286       int near = g;
287       if (i == stop - 1) {
288         // right bound reached, link with the rightmost node
289         near = iup;
290         c = quad->uv_grid[nbhoriz + iup].node;
291       }
292       else {
293         // find in the grid node c, nearest to the b
294         double mind = RealLast();
295         for (int k = g; k <= iup; k++) {
296           
297           const SMDS_MeshNode *nk;
298           if (k < ilow) // this can be, if left edge is out
299             nk = uv_e3[1].node; // get node from the left edge
300           else
301             nk = quad->uv_grid[nbhoriz + k].node; // get one of middle nodes
302
303           gp_Pnt pnk (nk->X(), nk->Y(), nk->Z());
304           double dist = pb.Distance(pnk);
305           if (dist < mind - eps) {
306             c = nk;
307             near = k;
308             mind = dist;
309           } else {
310             break;
311           }
312         }
313       }
314
315       if (near == g) { // make triangle
316         //SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
317         SMDS_MeshFace* face = myTool->AddFace(a, b, c);
318         meshDS->SetMeshElementOnShape(face, geomFaceID);
319       }
320       else { // make quadrangle
321         if (near - 1 < ilow)
322           d = uv_e3[1].node;
323         else
324           d = quad->uv_grid[nbhoriz + near - 1].node;
325         //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
326         
327         if(!myTrianglePreference){
328           SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
329           meshDS->SetMeshElementOnShape(face, geomFaceID);
330         }
331         else {
332           SMDS_MeshFace* face = myTool->AddFace(a, b, c);
333           meshDS->SetMeshElementOnShape(face, geomFaceID);
334           face = myTool->AddFace(a, c, d);
335           meshDS->SetMeshElementOnShape(face, geomFaceID);
336         }
337
338         // if node d is not at position g - make additional triangles
339         if (near - 1 > g) {
340           for (int k = near - 1; k > g; k--) {
341             c = quad->uv_grid[nbhoriz + k].node;
342             if (k - 1 < ilow)
343               d = uv_e3[1].node;
344             else
345               d = quad->uv_grid[nbhoriz + k - 1].node;
346             //SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
347             SMDS_MeshFace* face = myTool->AddFace(a, c, d);
348             meshDS->SetMeshElementOnShape(face, geomFaceID);
349           }
350         }
351         g = near;
352       }
353     }
354   } else {
355     if (quad->isEdgeOut[2]) {
356       // Up edge is out
357       // 
358       // <-<-<-<-<-<-<-<-<-<-<-<-< -- direction of processing
359       // 
360       // .  .  .  .  .  .  .  .  . __ up edge nodes
361       //  ___ ___ ___ ___ ___ ___  __ first row of the regular grid
362       // |   |   |   |   |   |   |
363       // |___|___|___|___|___|___|
364       // |   |   |   |   |   |   |
365       // |___|___|___|___|___|___|
366       // |   |   |   |   |   |   |
367
368       int g = nbhoriz - 1; // last processed node in the regular grid
369
370       int stop = 0;
371       // if left edge is out, we will stop at a second node
372       if (quad->isEdgeOut[3]) stop++;
373
374       // for each node of the up edge find nearest node
375       // in the first row of the regular grid and link them
376       for (i = nbup - 1; i > stop; i--) {
377         const SMDS_MeshNode *a, *b, *c, *d;
378         a = uv_e2[i].node;
379         b = uv_e2[i - 1].node;
380         gp_Pnt pb (b->X(), b->Y(), b->Z());
381
382         // find node c in the grid, which will be linked with node b
383         int near = g;
384         if (i == stop + 1) { // left bound reached, link with the leftmost node
385           c = quad->uv_grid[nbhoriz*(nbvertic - 2) + ilow].node;
386           near = ilow;
387         } else {
388           // find node c in the grid, nearest to the b
389           double mind = RealLast();
390           for (int k = g; k >= ilow; k--) {
391             const SMDS_MeshNode *nk;
392             if (k > iup)
393               nk = uv_e1[nbright - 2].node;
394             else
395               nk = quad->uv_grid[nbhoriz*(nbvertic - 2) + k].node;
396             gp_Pnt pnk (nk->X(), nk->Y(), nk->Z());
397             double dist = pb.Distance(pnk);
398             if (dist < mind - eps) {
399               c = nk;
400               near = k;
401               mind = dist;
402             } else {
403               break;
404             }
405           }
406         }
407
408         if (near == g) { // make triangle
409           //SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
410           SMDS_MeshFace* face = myTool->AddFace(a, b, c);
411           meshDS->SetMeshElementOnShape(face, geomFaceID);
412         }
413         else { // make quadrangle
414           if (near + 1 > iup)
415             d = uv_e1[nbright - 2].node;
416           else
417             d = quad->uv_grid[nbhoriz*(nbvertic - 2) + near + 1].node;
418           //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
419           if(!myTrianglePreference){
420             SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
421             meshDS->SetMeshElementOnShape(face, geomFaceID);
422           }
423           else {
424             SMDS_MeshFace* face = myTool->AddFace(a, b, c);
425             meshDS->SetMeshElementOnShape(face, geomFaceID);
426             face = myTool->AddFace(a, c, d);
427             meshDS->SetMeshElementOnShape(face, geomFaceID);
428           }
429
430           if (near + 1 < g) { // if d not is at g - make additional triangles
431             for (int k = near + 1; k < g; k++) {
432               c = quad->uv_grid[nbhoriz*(nbvertic - 2) + k].node;
433               if (k + 1 > iup)
434                 d = uv_e1[nbright - 2].node;
435               else
436                 d = quad->uv_grid[nbhoriz*(nbvertic - 2) + k + 1].node;
437               //SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
438               SMDS_MeshFace* face = myTool->AddFace(a, c, d);
439               meshDS->SetMeshElementOnShape(face, geomFaceID);
440             }
441           }
442           g = near;
443         }
444       }
445     }
446   }
447
448   // right or left boundary quadrangles
449   if (quad->isEdgeOut[1]) {
450 //    MESSAGE("right edge is out");
451     int g = 0; // last processed node in the grid
452     int stop = nbright - 1;
453     if (quad->isEdgeOut[2]) stop--;
454     for (i = 0; i < stop; i++) {
455       const SMDS_MeshNode *a, *b, *c, *d;
456       a = uv_e1[i].node;
457       b = uv_e1[i + 1].node;
458       gp_Pnt pb (b->X(), b->Y(), b->Z());
459
460       // find node c in the grid, nearest to the b
461       int near = g;
462       if (i == stop - 1) { // up bondary reached
463         c = quad->uv_grid[nbhoriz*(jup + 1) - 2].node;
464         near = jup;
465       } else {
466         double mind = RealLast();
467         for (int k = g; k <= jup; k++) {
468           const SMDS_MeshNode *nk;
469           if (k < jlow)
470             nk = uv_e0[nbdown - 2].node;
471           else
472             nk = quad->uv_grid[nbhoriz*(k + 1) - 2].node;
473           gp_Pnt pnk (nk->X(), nk->Y(), nk->Z());
474           double dist = pb.Distance(pnk);
475           if (dist < mind - eps) {
476             c = nk;
477             near = k;
478             mind = dist;
479           } else {
480             break;
481           }
482         }
483       }
484
485       if (near == g) { // make triangle
486         //SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
487         SMDS_MeshFace* face = myTool->AddFace(a, b, c);
488         meshDS->SetMeshElementOnShape(face, geomFaceID);
489       }
490       else { // make quadrangle
491         if (near - 1 < jlow)
492           d = uv_e0[nbdown - 2].node;
493         else
494           d = quad->uv_grid[nbhoriz*near - 2].node;
495         //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
496
497         if(!myTrianglePreference){
498           SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
499           meshDS->SetMeshElementOnShape(face, geomFaceID);
500         }
501         else {
502           SMDS_MeshFace* face = myTool->AddFace(a, b, c);
503           meshDS->SetMeshElementOnShape(face, geomFaceID);
504           face = myTool->AddFace(a, c, d);
505           meshDS->SetMeshElementOnShape(face, geomFaceID);
506         }
507
508         if (near - 1 > g) { // if d not is at g - make additional triangles
509           for (int k = near - 1; k > g; k--) {
510             c = quad->uv_grid[nbhoriz*(k + 1) - 2].node;
511             if (k - 1 < jlow)
512               d = uv_e0[nbdown - 2].node;
513             else
514               d = quad->uv_grid[nbhoriz*k - 2].node;
515             //SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
516             SMDS_MeshFace* face = myTool->AddFace(a, c, d);
517             meshDS->SetMeshElementOnShape(face, geomFaceID);
518           }
519         }
520         g = near;
521       }
522     }
523   } else {
524     if (quad->isEdgeOut[3]) {
525 //      MESSAGE("left edge is out");
526       int g = nbvertic - 1; // last processed node in the grid
527       int stop = 0;
528       if (quad->isEdgeOut[0]) stop++;
529       for (i = nbleft - 1; i > stop; i--) {
530         const SMDS_MeshNode *a, *b, *c, *d;
531         a = uv_e3[i].node;
532         b = uv_e3[i - 1].node;
533         gp_Pnt pb (b->X(), b->Y(), b->Z());
534
535         // find node c in the grid, nearest to the b
536         int near = g;
537         if (i == stop + 1) { // down bondary reached
538           c = quad->uv_grid[nbhoriz*jlow + 1].node;
539           near = jlow;
540         } else {
541           double mind = RealLast();
542           for (int k = g; k >= jlow; k--) {
543             const SMDS_MeshNode *nk;
544             if (k > jup)
545               nk = uv_e2[1].node;
546             else
547               nk = quad->uv_grid[nbhoriz*k + 1].node;
548             gp_Pnt pnk (nk->X(), nk->Y(), nk->Z());
549             double dist = pb.Distance(pnk);
550             if (dist < mind - eps) {
551               c = nk;
552               near = k;
553               mind = dist;
554             } else {
555               break;
556             }
557           }
558         }
559
560         if (near == g) { // make triangle
561           //SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
562           SMDS_MeshFace* face = myTool->AddFace(a, b, c);
563           meshDS->SetMeshElementOnShape(face, geomFaceID);
564         }
565         else { // make quadrangle
566           if (near + 1 > jup)
567             d = uv_e2[1].node;
568           else
569             d = quad->uv_grid[nbhoriz*(near + 1) + 1].node;
570           //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
571           if(!myTrianglePreference){
572             SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
573             meshDS->SetMeshElementOnShape(face, geomFaceID);
574           }
575           else {
576             SMDS_MeshFace* face = myTool->AddFace(a, b, c);
577             meshDS->SetMeshElementOnShape(face, geomFaceID);
578             face = myTool->AddFace(a, c, d);
579             meshDS->SetMeshElementOnShape(face, geomFaceID);
580           }
581
582           if (near + 1 < g) { // if d not is at g - make additional triangles
583             for (int k = near + 1; k < g; k++) {
584               c = quad->uv_grid[nbhoriz*k + 1].node;
585               if (k + 1 > jup)
586                 d = uv_e2[1].node;
587               else
588                 d = quad->uv_grid[nbhoriz*(k + 1) + 1].node;
589               //SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
590               SMDS_MeshFace* face = myTool->AddFace(a, c, d);
591               meshDS->SetMeshElementOnShape(face, geomFaceID);
592             }
593           }
594           g = near;
595         }
596       }
597     }
598   }
599
600   bool isOk = true;
601   return isOk;
602 }
603
604 //=============================================================================
605 /*!
606  *  
607  */
608 //=============================================================================
609
610 FaceQuadStruct* StdMeshers_Quadrangle_2D::CheckNbEdges(SMESH_Mesh &         aMesh,
611                                                        const TopoDS_Shape & aShape)
612   //throw(SALOME_Exception)
613 {
614   const TopoDS_Face & F = TopoDS::Face(aShape);
615   const bool ignoreMediumNodes = _quadraticMesh;
616
617   // verify 1 wire only, with 4 edges
618   TopoDS_Vertex V;
619   list< TopoDS_Edge > edges;
620   list< int > nbEdgesInWire;
621   int nbWire = SMESH_Block::GetOrderedEdges (F, V, edges, nbEdgesInWire);
622   if (nbWire != 1) {
623     error(COMPERR_BAD_SHAPE, TComm("Wrong number of wires: ") << nbWire);
624     return 0;
625   }
626   FaceQuadStruct* quad = new FaceQuadStruct;
627   quad->uv_grid = 0;
628   quad->side.reserve(nbEdgesInWire.front());
629
630   int nbSides = 0;
631   list< TopoDS_Edge >::iterator edgeIt = edges.begin();
632   if ( nbEdgesInWire.front() == 4 ) { // exactly 4 edges
633     for ( ; edgeIt != edges.end(); ++edgeIt, nbSides++ )
634       quad->side.push_back( new StdMeshers_FaceSide(F, *edgeIt, &aMesh,
635                                                     nbSides<TOP_SIDE, ignoreMediumNodes));
636   }
637   else if ( nbEdgesInWire.front() > 4 ) { // more than 4 edges - try to unite some
638     list< TopoDS_Edge > sideEdges;
639     while ( !edges.empty()) {
640       sideEdges.clear();
641       sideEdges.splice( sideEdges.end(), edges, edges.begin()); // edges.front() -> sideEdges.end()
642       bool sameSide = true;
643       while ( !edges.empty() && sameSide ) {
644         sameSide = SMESH_Algo::IsContinuous( sideEdges.back(), edges.front() );
645         if ( sameSide )
646           sideEdges.splice( sideEdges.end(), edges, edges.begin());
647       }
648       if ( nbSides == 0 ) { // go backward from the first edge
649         sameSide = true;
650         while ( !edges.empty() && sameSide ) {
651           sameSide = SMESH_Algo::IsContinuous( sideEdges.front(), edges.back() );
652           if ( sameSide )
653             sideEdges.splice( sideEdges.begin(), edges, --edges.end());
654         }
655       }
656       quad->side.push_back( new StdMeshers_FaceSide(F, sideEdges, &aMesh,
657                                                     nbSides<TOP_SIDE, ignoreMediumNodes));
658       ++nbSides;
659     }
660   }
661   if (nbSides != 4) {
662 #ifdef _DEBUG_
663     MESSAGE ( "StdMeshers_Quadrangle_2D. Edge IDs of " << nbSides << " sides:\n" );
664     for ( int i = 0; i < nbSides; ++i ) {
665       MESSAGE ( " ( " );
666       for ( int e = 0; e < quad->side[i]->NbEdges(); ++e )
667         MESSAGE ( myTool->GetMeshDS()->ShapeToIndex( quad->side[i]->Edge( e )) << " " );
668       MESSAGE ( ")\n" );
669     }
670     //cout << endl;
671 #endif
672     if ( !nbSides )
673       nbSides = nbEdgesInWire.front();
674     error(COMPERR_BAD_SHAPE, TComm("Face must have 4 sides but not ") << nbSides);
675     delete quad;
676     quad = 0;
677   }
678
679   return quad;
680 }
681
682 //=============================================================================
683 /*!
684  *  CheckAnd2Dcompute
685  */
686 //=============================================================================
687
688 FaceQuadStruct *StdMeshers_Quadrangle_2D::CheckAnd2Dcompute
689                            (SMESH_Mesh &         aMesh,
690                             const TopoDS_Shape & aShape,
691                             const bool           CreateQuadratic) //throw(SALOME_Exception)
692 {
693   _quadraticMesh = CreateQuadratic;
694
695   FaceQuadStruct *quad = CheckNbEdges(aMesh, aShape);
696
697   if(!quad) return 0;
698
699   // set normalized grid on unit square in parametric domain
700   bool stat = SetNormalizedGrid(aMesh, aShape, quad);
701   if(!stat) {
702     if(!quad)
703       delete quad;
704     quad = 0;
705   }
706
707   return quad;
708 }
709
710 //=============================================================================
711 /*!
712  *  
713  */
714 //=============================================================================
715
716 faceQuadStruct::~faceQuadStruct()
717 {
718   for (int i = 0; i < side.size(); i++) {
719     if (side[i])     delete side[i];
720   }
721   if (uv_grid)       delete [] uv_grid;
722 }
723
724 namespace {
725   inline const vector<UVPtStruct>& GetUVPtStructIn(FaceQuadStruct* quad, int i, int nbSeg)
726   {
727     bool   isXConst   = ( i == BOTTOM_SIDE || i == TOP_SIDE );
728     double constValue = ( i == BOTTOM_SIDE || i == LEFT_SIDE ) ? 0 : 1;
729     return
730       quad->isEdgeOut[i] ?
731       quad->side[i]->SimulateUVPtStruct(nbSeg,isXConst,constValue) :
732       quad->side[i]->GetUVPtStruct(isXConst,constValue);
733   }
734 }
735
736 //=============================================================================
737 /*!
738  *  
739  */
740 //=============================================================================
741
742 bool StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh,
743                                                   const TopoDS_Shape& aShape,
744                                                   FaceQuadStruct* & quad) //throw (SALOME_Exception)
745 {
746   // Algorithme décrit dans "Génération automatique de maillages"
747   // P.L. GEORGE, MASSON, Â§ 6.4.1 p. 84-85
748   // traitement dans le domaine paramétrique 2d u,v
749   // transport - projection sur le carré unité
750
751 //  MESSAGE("StdMeshers_Quadrangle_2D::SetNormalizedGrid");
752 //  const TopoDS_Face& F = TopoDS::Face(aShape);
753
754   // 1 --- find orientation of the 4 edges, by test on extrema
755
756   //      max             min                    0     x1     1
757   //     |<----north-2-------^                a3 -------------> a2
758   //     |                   |                   ^1          1^
759   //    west-3            east-1 =right          |            |
760   //     |                   |         ==>       |            |
761   //  y0 |                   | y1                |            |
762   //     |                   |                   |0          0|
763   //     v----south-0-------->                a0 -------------> a1
764   //      min             max                    0     x0     1
765   //             =down
766   //
767
768   // 3 --- 2D normalized values on unit square [0..1][0..1]
769
770   int nbhoriz  = Min(quad->side[0]->NbPoints(), quad->side[2]->NbPoints());
771   int nbvertic = Min(quad->side[1]->NbPoints(), quad->side[3]->NbPoints());
772
773   quad->isEdgeOut[0] = (quad->side[0]->NbPoints() > quad->side[2]->NbPoints());
774   quad->isEdgeOut[1] = (quad->side[1]->NbPoints() > quad->side[3]->NbPoints());
775   quad->isEdgeOut[2] = (quad->side[2]->NbPoints() > quad->side[0]->NbPoints());
776   quad->isEdgeOut[3] = (quad->side[3]->NbPoints() > quad->side[1]->NbPoints());
777
778   UVPtStruct *uv_grid = quad->uv_grid = new UVPtStruct[nbvertic * nbhoriz];
779
780   const vector<UVPtStruct>& uv_e0 = GetUVPtStructIn( quad, 0, nbhoriz - 1 );
781   const vector<UVPtStruct>& uv_e1 = GetUVPtStructIn( quad, 1, nbvertic - 1 );
782   const vector<UVPtStruct>& uv_e2 = GetUVPtStructIn( quad, 2, nbhoriz - 1 );
783   const vector<UVPtStruct>& uv_e3 = GetUVPtStructIn( quad, 3, nbvertic - 1 );
784
785   if ( uv_e0.empty() || uv_e1.empty() || uv_e2.empty() || uv_e3.empty() )
786     //return error( "Can't find nodes on sides");
787     return error( COMPERR_BAD_INPUT_MESH );
788
789   // nodes Id on "in" edges
790   if (! quad->isEdgeOut[0]) {
791     int j = 0;
792     for (int i = 0; i < nbhoriz; i++) { // down
793       int ij = j * nbhoriz + i;
794       uv_grid[ij].node = uv_e0[i].node;
795     }
796   }
797   if (! quad->isEdgeOut[1]) {
798     int i = nbhoriz - 1;
799     for (int j = 0; j < nbvertic; j++) { // right
800       int ij = j * nbhoriz + i;
801       uv_grid[ij].node = uv_e1[j].node;
802     }
803   }
804   if (! quad->isEdgeOut[2]) {
805     int j = nbvertic - 1;
806     for (int i = 0; i < nbhoriz; i++) { // up
807       int ij = j * nbhoriz + i;
808       uv_grid[ij].node = uv_e2[i].node;
809     }
810   }
811   if (! quad->isEdgeOut[3]) {
812     int i = 0;
813     for (int j = 0; j < nbvertic; j++) { // left
814       int ij = j * nbhoriz + i;
815       uv_grid[ij].node = uv_e3[j].node;
816     }
817   }
818
819   // normalized 2d values on grid
820   for (int i = 0; i < nbhoriz; i++)
821   {
822     for (int j = 0; j < nbvertic; j++)
823     {
824       int ij = j * nbhoriz + i;
825       // --- droite i cste : x = x0 + y(x1-x0)
826       double x0 = uv_e0[i].normParam;   // bas - sud
827       double x1 = uv_e2[i].normParam;   // haut - nord
828       // --- droite j cste : y = y0 + x(y1-y0)
829       double y0 = uv_e3[j].normParam;   // gauche-ouest
830       double y1 = uv_e1[j].normParam;   // droite - est
831       // --- intersection : x=x0+(y0+x(y1-y0))(x1-x0)
832       double x = (x0 + y0 * (x1 - x0)) / (1 - (y1 - y0) * (x1 - x0));
833       double y = y0 + x * (y1 - y0);
834       uv_grid[ij].x = x;
835       uv_grid[ij].y = y;
836       //MESSAGE("-xy-01 "<<x0<<" "<<x1<<" "<<y0<<" "<<y1);
837       //MESSAGE("-xy-norm "<<i<<" "<<j<<" "<<x<<" "<<y);
838     }
839   }
840
841   // 4 --- projection on 2d domain (u,v)
842   gp_UV a0( uv_e0.front().u, uv_e0.front().v );
843   gp_UV a1( uv_e0.back().u,  uv_e0.back().v );
844   gp_UV a2( uv_e2.back().u,  uv_e2.back().v );
845   gp_UV a3( uv_e2.front().u, uv_e2.front().v );
846
847   for (int i = 0; i < nbhoriz; i++)
848   {
849     for (int j = 0; j < nbvertic; j++)
850     {
851       int ij = j * nbhoriz + i;
852       double x = uv_grid[ij].x;
853       double y = uv_grid[ij].y;
854       double param_0 = uv_e0[0].normParam + x * (uv_e0.back().normParam - uv_e0[0].normParam); // sud
855       double param_2 = uv_e2[0].normParam + x * (uv_e2.back().normParam - uv_e2[0].normParam); // nord
856       double param_1 = uv_e1[0].normParam + y * (uv_e1.back().normParam - uv_e1[0].normParam); // est
857       double param_3 = uv_e3[0].normParam + y * (uv_e3.back().normParam - uv_e3[0].normParam); // ouest
858
859       //MESSAGE("params "<<param_0<<" "<<param_1<<" "<<param_2<<" "<<param_3);
860       gp_UV p0 = quad->side[0]->Value2d(param_0).XY();
861       gp_UV p1 = quad->side[1]->Value2d(param_1).XY();
862       gp_UV p2 = quad->side[2]->Value2d(param_2).XY();
863       gp_UV p3 = quad->side[3]->Value2d(param_3).XY();
864
865       gp_UV uv = (1 - y) * p0 + x * p1 + y * p2 + (1 - x) * p3;
866       uv -= (1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3;
867
868       uv_grid[ij].u = uv.X();
869       uv_grid[ij].v = uv.Y();
870     }
871   }
872   return true;
873 }
874
875 //=======================================================================
876 //function : ShiftQuad
877 //purpose  : auxilary function for ComputeQuadPref
878 //=======================================================================
879
880 static void ShiftQuad(FaceQuadStruct* quad, const int num, bool)
881 {
882   StdMeshers_FaceSide* side[4] = { quad->side[0], quad->side[1], quad->side[2], quad->side[3] };
883   for (int i = BOTTOM_SIDE; i < NB_SIDES; ++i ) {
884     int id = ( i + num ) % NB_SIDES;
885     bool wasForward = ( i < TOP_SIDE );
886     bool newForward = ( id < TOP_SIDE );
887     if ( wasForward != newForward )
888       side[ i ]->Reverse();
889     quad->side[ id ] = side[ i ];
890   }
891 }
892
893 //=======================================================================
894 //function : CalcUV
895 //purpose  : auxilary function for ComputeQuadPref
896 //=======================================================================
897
898 static gp_UV CalcUV(double x0, double x1, double y0, double y1,
899                     FaceQuadStruct* quad,
900                     const gp_UV& a0, const gp_UV& a1,
901                     const gp_UV& a2, const gp_UV& a3)
902 {
903   const vector<UVPtStruct>& uv_eb = quad->side[0]->GetUVPtStruct(true,0 );
904   const vector<UVPtStruct>& uv_er = quad->side[1]->GetUVPtStruct(false,1);
905   const vector<UVPtStruct>& uv_et = quad->side[2]->GetUVPtStruct(true,1 );
906   const vector<UVPtStruct>& uv_el = quad->side[3]->GetUVPtStruct(false,0);
907
908   double x = (x0 + y0 * (x1 - x0)) / (1 - (y1 - y0) * (x1 - x0));
909   double y = y0 + x * (y1 - y0);
910
911   double param_b = uv_eb[0].normParam + x * (uv_eb.back().normParam - uv_eb[0].normParam);
912   double param_t = uv_et[0].normParam + x * (uv_et.back().normParam - uv_et[0].normParam);
913   double param_r = uv_er[0].normParam + y * (uv_er.back().normParam - uv_er[0].normParam);
914   double param_l = uv_el[0].normParam + y * (uv_el.back().normParam - uv_el[0].normParam);
915
916   gp_UV p0 = quad->side[BOTTOM_SIDE]->Value2d(param_b).XY();
917   gp_UV p1 = quad->side[RIGHT_SIDE ]->Value2d(param_r).XY();
918   gp_UV p2 = quad->side[TOP_SIDE   ]->Value2d(param_t).XY();
919   gp_UV p3 = quad->side[LEFT_SIDE  ]->Value2d(param_l).XY();
920
921   gp_UV uv = p0 * (1 - y) + p1 * x + p2 * y + p3 * (1 - x);
922
923   uv -= (1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3;
924
925   return uv;
926 }
927
928 //=======================================================================
929 /*!
930  * Create only quandrangle faces
931  */
932 //=======================================================================
933
934 bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh &        aMesh,
935                                                 const TopoDS_Shape& aShape,
936                                                 FaceQuadStruct*     quad)
937 {
938   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
939   const TopoDS_Face& F = TopoDS::Face(aShape);
940   Handle(Geom_Surface) S = BRep_Tool::Surface(F);
941 //  const TopoDS_Wire& W = BRepTools::OuterWire(F);
942   bool WisF = true;
943 //   if(W.Orientation()==TopAbs_FORWARD) 
944 //     WisF = true;
945   //if(WisF) cout<<"W is FORWARD"<<endl;
946   //else cout<<"W is REVERSED"<<endl;
947 //   bool FisF = (F.Orientation()==TopAbs_FORWARD);
948 //   if(!FisF) WisF = !WisF;
949 //  WisF = FisF;
950   int i,j,geomFaceID = meshDS->ShapeToIndex( F );
951
952   int nb = quad->side[0]->NbPoints();
953   int nr = quad->side[1]->NbPoints();
954   int nt = quad->side[2]->NbPoints();
955   int nl = quad->side[3]->NbPoints();
956   int dh = abs(nb-nt);
957   int dv = abs(nr-nl);
958
959   if( dh>=dv ) {
960     if( nt>nb ) {
961       // it is a base case => not shift quad but me be replacement is need
962       ShiftQuad(quad,0,WisF);
963     }
964     else {
965       // we have to shift quad on 2
966       ShiftQuad(quad,2,WisF);
967     }
968   }
969   else {
970     if( nr>nl ) {
971       // we have to shift quad on 1
972       ShiftQuad(quad,1,WisF);
973     }
974     else {
975       // we have to shift quad on 3
976       ShiftQuad(quad,3,WisF);
977     }
978   }
979
980   nb = quad->side[0]->NbPoints();
981   nr = quad->side[1]->NbPoints();
982   nt = quad->side[2]->NbPoints();
983   nl = quad->side[3]->NbPoints();
984   dh = abs(nb-nt);
985   dv = abs(nr-nl);
986   int nbh  = Max(nb,nt);
987   int nbv = Max(nr,nl);
988   int addh = 0;
989   int addv = 0;
990
991   // orientation of face and 3 main domain for future faces
992   //       0   top    1
993   //      1------------1
994   //       |   |  |   |
995   //       |   |  |   |
996   //       | L |  | R |
997   //  left |   |  |   | rigth
998   //       |  /    \  |
999   //       | /  C   \ |
1000   //       |/        \|
1001   //      0------------0
1002   //       0  bottom  1
1003
1004   if(dh>dv) {
1005     addv = (dh-dv)/2;
1006     nbv = nbv + addv;
1007   }
1008   else { // dv>=dh
1009     addh = (dv-dh)/2;
1010     nbh = nbh + addh;
1011   }
1012
1013   const vector<UVPtStruct>& uv_eb = quad->side[0]->GetUVPtStruct(true,0 );
1014   const vector<UVPtStruct>& uv_er = quad->side[1]->GetUVPtStruct(false,1);
1015   const vector<UVPtStruct>& uv_et = quad->side[2]->GetUVPtStruct(true,1 );
1016   const vector<UVPtStruct>& uv_el = quad->side[3]->GetUVPtStruct(false,0);
1017
1018   // arrays for normalized params
1019   //cout<<"Dump B:"<<endl;
1020   TColStd_SequenceOfReal npb, npr, npt, npl;
1021   for(i=0; i<nb; i++) {
1022     npb.Append(uv_eb[i].normParam);
1023     //cout<<"i="<<i<<" par="<<uv_eb[i].normParam<<" npar="<<uv_eb[i].normParam;
1024     //const SMDS_MeshNode* N = uv_eb[i].node;
1025     //cout<<" node("<<N->X()<<","<<N->Y()<<","<<N->Z()<<")"<<endl;
1026   }
1027   for(i=0; i<nr; i++) {
1028     npr.Append(uv_er[i].normParam);
1029   }
1030   for(i=0; i<nt; i++) {
1031     npt.Append(uv_et[i].normParam);
1032   }
1033   for(i=0; i<nl; i++) {
1034     npl.Append(uv_el[i].normParam);
1035   }
1036
1037   // add some params to right and left after the first param
1038   // insert to right
1039   int dr = nbv - nr;
1040   double dpr = (npr.Value(2) - npr.Value(1))/(dr+1);
1041   for(i=1; i<=dr; i++) {
1042     npr.InsertAfter(1,npr.Value(2)-dpr);
1043   }
1044   // insert to left
1045   int dl = nbv - nl;
1046   dpr = (npl.Value(2) - npl.Value(1))/(dl+1);
1047   for(i=1; i<=dl; i++) {
1048     npl.InsertAfter(1,npl.Value(2)-dpr);
1049   }
1050   //cout<<"npb:";
1051   //for(i=1; i<=npb.Length(); i++) {
1052   //  cout<<" "<<npb.Value(i);
1053   //}
1054   //cout<<endl;
1055   
1056   gp_XY a0( uv_eb.front().u, uv_eb.front().v );
1057   gp_XY a1( uv_eb.back().u,  uv_eb.back().v );
1058   gp_XY a2( uv_et.back().u,  uv_et.back().v );
1059   gp_XY a3( uv_et.front().u, uv_et.front().v );
1060   //cout<<" a0("<<a0.X()<<","<<a0.Y()<<")"<<" a1("<<a1.X()<<","<<a1.Y()<<")"
1061   //    <<" a2("<<a2.X()<<","<<a2.Y()<<")"<<" a3("<<a3.X()<<","<<a3.Y()<<")"<<endl;
1062
1063   int nnn = Min(nr,nl);
1064   // auxilary sequence of XY for creation nodes
1065   // in the bottom part of central domain
1066   // it's length must be == nbv-nnn-1
1067   TColgp_SequenceOfXY UVL;
1068   TColgp_SequenceOfXY UVR;
1069
1070   // step1: create faces for left domain
1071   StdMeshers_Array2OfNode NodesL(1,dl+1,1,nl);
1072   // add left nodes
1073   for(j=1; j<=nl; j++)
1074     NodesL.SetValue(1,j,uv_el[j-1].node);
1075   if(dl>0) {
1076     // add top nodes
1077     for(i=1; i<=dl; i++) 
1078       NodesL.SetValue(i+1,nl,uv_et[i].node);
1079     // create and add needed nodes
1080     TColgp_SequenceOfXY UVtmp;
1081     for(i=1; i<=dl; i++) {
1082       double x0 = npt.Value(i+1);
1083       double x1 = x0;
1084       // diagonal node
1085       double y0 = npl.Value(i+1);
1086       double y1 = npr.Value(i+1);
1087       gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
1088       gp_Pnt P = S->Value(UV.X(),UV.Y());
1089       SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1090       meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
1091       NodesL.SetValue(i+1,1,N);
1092       if(UVL.Length()<nbv-nnn-1) UVL.Append(UV);
1093       // internal nodes
1094       for(j=2; j<nl; j++) {
1095         double y0 = npl.Value(dl+j);
1096         double y1 = npr.Value(dl+j);
1097         gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
1098         gp_Pnt P = S->Value(UV.X(),UV.Y());
1099         SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1100         meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
1101         NodesL.SetValue(i+1,j,N);
1102         if( i==dl ) UVtmp.Append(UV);
1103       }
1104     }
1105     for(i=1; i<=UVtmp.Length() && UVL.Length()<nbv-nnn-1; i++) {
1106       UVL.Append(UVtmp.Value(i));
1107     }
1108     //cout<<"Dump NodesL:"<<endl;
1109     //for(i=1; i<=dl+1; i++) {
1110     //  cout<<"i="<<i;
1111     //  for(j=1; j<=nl; j++) {
1112     //    cout<<" ("<<NodesL.Value(i,j)->X()<<","<<NodesL.Value(i,j)->Y()<<","<<NodesL.Value(i,j)->Z()<<")";
1113     //  }
1114     //  cout<<endl;
1115     //}
1116     // create faces
1117     for(i=1; i<=dl; i++) {
1118       for(j=1; j<nl; j++) {
1119         if(WisF) {
1120           SMDS_MeshFace* F =
1121             myTool->AddFace(NodesL.Value(i,j), NodesL.Value(i+1,j),
1122                             NodesL.Value(i+1,j+1), NodesL.Value(i,j+1));
1123           meshDS->SetMeshElementOnShape(F, geomFaceID);
1124         }
1125         else {
1126           SMDS_MeshFace* F =
1127             myTool->AddFace(NodesL.Value(i,j), NodesL.Value(i,j+1),
1128                             NodesL.Value(i+1,j+1), NodesL.Value(i+1,j));
1129           meshDS->SetMeshElementOnShape(F, geomFaceID);
1130         }
1131       }
1132     }
1133   }
1134   else {
1135     // fill UVL using c2d
1136     for(i=1; i<npl.Length() && UVL.Length()<nbv-nnn-1; i++) {
1137       UVL.Append( gp_UV ( uv_el[i].u, uv_el[i].v ));
1138     }
1139   }
1140
1141   // step2: create faces for right domain
1142   StdMeshers_Array2OfNode NodesR(1,dr+1,1,nr);
1143   // add right nodes
1144   for(j=1; j<=nr; j++) 
1145     NodesR.SetValue(1,j,uv_er[nr-j].node);
1146   if(dr>0) {
1147     // add top nodes
1148     for(i=1; i<=dr; i++) 
1149       NodesR.SetValue(i+1,1,uv_et[nt-1-i].node);
1150     // create and add needed nodes
1151     TColgp_SequenceOfXY UVtmp;
1152     for(i=1; i<=dr; i++) {
1153       double x0 = npt.Value(nt-i);
1154       double x1 = x0;
1155       // diagonal node
1156       double y0 = npl.Value(i+1);
1157       double y1 = npr.Value(i+1);
1158       gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
1159       gp_Pnt P = S->Value(UV.X(),UV.Y());
1160       SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1161       meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
1162       NodesR.SetValue(i+1,nr,N);
1163       if(UVR.Length()<nbv-nnn-1) UVR.Append(UV);
1164       // internal nodes
1165       for(j=2; j<nr; j++) {
1166         double y0 = npl.Value(nbv-j+1);
1167         double y1 = npr.Value(nbv-j+1);
1168         gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
1169         gp_Pnt P = S->Value(UV.X(),UV.Y());
1170         SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1171         meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
1172         NodesR.SetValue(i+1,j,N);
1173         if( i==dr ) UVtmp.Prepend(UV);
1174       }
1175     }
1176     for(i=1; i<=UVtmp.Length() && UVR.Length()<nbv-nnn-1; i++) {
1177       UVR.Append(UVtmp.Value(i));
1178     }
1179     // create faces
1180     for(i=1; i<=dr; i++) {
1181       for(j=1; j<nr; j++) {
1182         if(WisF) {
1183           SMDS_MeshFace* F =
1184             myTool->AddFace(NodesR.Value(i,j), NodesR.Value(i+1,j),
1185                             NodesR.Value(i+1,j+1), NodesR.Value(i,j+1));
1186           meshDS->SetMeshElementOnShape(F, geomFaceID);
1187         }
1188         else {
1189           SMDS_MeshFace* F =
1190             myTool->AddFace(NodesR.Value(i,j), NodesR.Value(i,j+1),
1191                             NodesR.Value(i+1,j+1), NodesR.Value(i+1,j));
1192           meshDS->SetMeshElementOnShape(F, geomFaceID);
1193         }
1194       }
1195     }
1196   }
1197   else {
1198     // fill UVR using c2d
1199     for(i=1; i<npr.Length() && UVR.Length()<nbv-nnn-1; i++) {
1200       UVR.Append( gp_UV( uv_er[i].u, uv_er[i].v ));
1201     }
1202   }
1203
1204   // step3: create faces for central domain
1205   StdMeshers_Array2OfNode NodesC(1,nb,1,nbv);
1206   // add first string using NodesL
1207   for(i=1; i<=dl+1; i++)
1208     NodesC.SetValue(1,i,NodesL(i,1));
1209   for(i=2; i<=nl; i++)
1210     NodesC.SetValue(1,dl+i,NodesL(dl+1,i));
1211   // add last string using NodesR
1212   for(i=1; i<=dr+1; i++)
1213     NodesC.SetValue(nb,i,NodesR(i,nr));
1214   for(i=1; i<nr; i++)
1215     NodesC.SetValue(nb,dr+i+1,NodesR(dr+1,nr-i));
1216   // add top nodes (last columns)
1217   for(i=dl+2; i<nbh-dr; i++) 
1218     NodesC.SetValue(i-dl,nbv,uv_et[i-1].node);
1219   // add bottom nodes (first columns)
1220   for(i=2; i<nb; i++)
1221     NodesC.SetValue(i,1,uv_eb[i-1].node);
1222
1223   // create and add needed nodes
1224   // add linear layers
1225   for(i=2; i<nb; i++) {
1226     double x0 = npt.Value(dl+i);
1227     double x1 = x0;
1228     for(j=1; j<nnn; j++) {
1229       double y0 = npl.Value(nbv-nnn+j);
1230       double y1 = npr.Value(nbv-nnn+j);
1231       gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
1232       gp_Pnt P = S->Value(UV.X(),UV.Y());
1233       SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1234       meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
1235       NodesC.SetValue(i,nbv-nnn+j,N);
1236     }
1237   }
1238   // add diagonal layers
1239   //cout<<"UVL.Length()="<<UVL.Length()<<" UVR.Length()="<<UVR.Length()<<endl;
1240   //cout<<"Dump UVL:"<<endl;
1241   //for(i=1; i<=UVL.Length(); i++) {
1242   //  cout<<" ("<<UVL.Value(i).X()<<","<<UVL.Value(i).Y()<<")";
1243   //}
1244   //cout<<endl;
1245   for(i=1; i<nbv-nnn; i++) {
1246     double du = UVR.Value(i).X() - UVL.Value(i).X();
1247     double dv = UVR.Value(i).Y() - UVL.Value(i).Y();
1248     for(j=2; j<nb; j++) {
1249       double u = UVL.Value(i).X() + du*npb.Value(j);
1250       double v = UVL.Value(i).Y() + dv*npb.Value(j);
1251       gp_Pnt P = S->Value(u,v);
1252       SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1253       meshDS->SetNodeOnFace(N, geomFaceID, u, v);
1254       NodesC.SetValue(j,i+1,N);
1255     }
1256   }
1257   // create faces
1258   for(i=1; i<nb; i++) {
1259     for(j=1; j<nbv; j++) {
1260       if(WisF) {
1261         SMDS_MeshFace* F =
1262           myTool->AddFace(NodesC.Value(i,j), NodesC.Value(i+1,j),
1263                           NodesC.Value(i+1,j+1), NodesC.Value(i,j+1));
1264         meshDS->SetMeshElementOnShape(F, geomFaceID);
1265       }
1266       else {
1267         SMDS_MeshFace* F =
1268           myTool->AddFace(NodesC.Value(i,j), NodesC.Value(i,j+1),
1269                           NodesC.Value(i+1,j+1), NodesC.Value(i+1,j));
1270         meshDS->SetMeshElementOnShape(F, geomFaceID);
1271       }
1272     }
1273   }
1274
1275   bool isOk = true;
1276   return isOk;
1277 }
1278