Salome HOME
Implementation on the issue 16186: EDF PAL 459: Mapping: when refining, to separate...
[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 //function : CalcUV2
931 //purpose  : auxilary function for ComputeQuadPref
932 //=======================================================================
933
934 static gp_UV CalcUV2(double x, double y,
935                      FaceQuadStruct* quad,
936                      const gp_UV& a0, const gp_UV& a1,
937                      const gp_UV& a2, const gp_UV& a3)
938 {
939   const vector<UVPtStruct>& uv_eb = quad->side[0]->GetUVPtStruct(true,0 );
940   const vector<UVPtStruct>& uv_er = quad->side[1]->GetUVPtStruct(false,1);
941   const vector<UVPtStruct>& uv_et = quad->side[2]->GetUVPtStruct(true,1 );
942   const vector<UVPtStruct>& uv_el = quad->side[3]->GetUVPtStruct(false,0);
943
944   //double x = (x0 + y0 * (x1 - x0)) / (1 - (y1 - y0) * (x1 - x0));
945   //double y = y0 + x * (y1 - y0);
946
947   double param_b = uv_eb[0].normParam + x * (uv_eb.back().normParam - uv_eb[0].normParam);
948   double param_t = uv_et[0].normParam + x * (uv_et.back().normParam - uv_et[0].normParam);
949   double param_r = uv_er[0].normParam + y * (uv_er.back().normParam - uv_er[0].normParam);
950   double param_l = uv_el[0].normParam + y * (uv_el.back().normParam - uv_el[0].normParam);
951
952   gp_UV p0 = quad->side[BOTTOM_SIDE]->Value2d(param_b).XY();
953   gp_UV p1 = quad->side[RIGHT_SIDE ]->Value2d(param_r).XY();
954   gp_UV p2 = quad->side[TOP_SIDE   ]->Value2d(param_t).XY();
955   gp_UV p3 = quad->side[LEFT_SIDE  ]->Value2d(param_l).XY();
956
957   gp_UV uv = p0 * (1 - y) + p1 * x + p2 * y + p3 * (1 - x);
958
959   uv -= (1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3;
960
961   return uv;
962 }
963
964 //=======================================================================
965 /*!
966  * Create only quandrangle faces
967  */
968 //=======================================================================
969
970 bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh &        aMesh,
971                                                 const TopoDS_Shape& aShape,
972                                                 FaceQuadStruct*     quad)
973 {
974   // Auxilary key in order to keep old variant
975   // of meshing after implementation new variant
976   // for bug 0016220 from Mantis.
977   bool OldVersion = false;
978
979   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
980   const TopoDS_Face& F = TopoDS::Face(aShape);
981   Handle(Geom_Surface) S = BRep_Tool::Surface(F);
982 //  const TopoDS_Wire& W = BRepTools::OuterWire(F);
983   bool WisF = true;
984 //   if(W.Orientation()==TopAbs_FORWARD) 
985 //     WisF = true;
986   //if(WisF) cout<<"W is FORWARD"<<endl;
987   //else cout<<"W is REVERSED"<<endl;
988 //   bool FisF = (F.Orientation()==TopAbs_FORWARD);
989 //   if(!FisF) WisF = !WisF;
990 //  WisF = FisF;
991   int i,j,geomFaceID = meshDS->ShapeToIndex( F );
992
993   int nb = quad->side[0]->NbPoints();
994   int nr = quad->side[1]->NbPoints();
995   int nt = quad->side[2]->NbPoints();
996   int nl = quad->side[3]->NbPoints();
997   int dh = abs(nb-nt);
998   int dv = abs(nr-nl);
999
1000   if( dh>=dv ) {
1001     if( nt>nb ) {
1002       // it is a base case => not shift quad but me be replacement is need
1003       ShiftQuad(quad,0,WisF);
1004     }
1005     else {
1006       // we have to shift quad on 2
1007       ShiftQuad(quad,2,WisF);
1008     }
1009   }
1010   else {
1011     if( nr>nl ) {
1012       // we have to shift quad on 1
1013       ShiftQuad(quad,1,WisF);
1014     }
1015     else {
1016       // we have to shift quad on 3
1017       ShiftQuad(quad,3,WisF);
1018     }
1019   }
1020
1021   nb = quad->side[0]->NbPoints();
1022   nr = quad->side[1]->NbPoints();
1023   nt = quad->side[2]->NbPoints();
1024   nl = quad->side[3]->NbPoints();
1025   dh = abs(nb-nt);
1026   dv = abs(nr-nl);
1027   int nbh  = Max(nb,nt);
1028   int nbv = Max(nr,nl);
1029   int addh = 0;
1030   int addv = 0;
1031
1032   // ----------- Old version ---------------
1033   // orientation of face and 3 main domain for future faces
1034   //       0   top    1
1035   //      1------------1
1036   //       |   |  |   |
1037   //       |   |  |   |
1038   //       | L |  | R |
1039   //  left |   |  |   | rigth
1040   //       |  /    \  |
1041   //       | /  C   \ |
1042   //       |/        \|
1043   //      0------------0
1044   //       0  bottom  1
1045
1046   // ----------- New version ---------------
1047   // orientation of face and 3 main domain for future faces
1048   //       0   top    1
1049   //      1------------1
1050   //       |  |____|  |
1051   //       |L /    \ R|
1052   //       | /  C   \ |
1053   //  left |/________\| rigth
1054   //       |          |
1055   //       |          |
1056   //       |          |
1057   //      0------------0
1058   //       0  bottom  1
1059
1060   if(dh>dv) {
1061     addv = (dh-dv)/2;
1062     nbv = nbv + addv;
1063   }
1064   else { // dv>=dh
1065     addh = (dv-dh)/2;
1066     nbh = nbh + addh;
1067   }
1068
1069   const vector<UVPtStruct>& uv_eb = quad->side[0]->GetUVPtStruct(true,0 );
1070   const vector<UVPtStruct>& uv_er = quad->side[1]->GetUVPtStruct(false,1);
1071   const vector<UVPtStruct>& uv_et = quad->side[2]->GetUVPtStruct(true,1 );
1072   const vector<UVPtStruct>& uv_el = quad->side[3]->GetUVPtStruct(false,0);
1073
1074   // arrays for normalized params
1075   //cout<<"Dump B:"<<endl;
1076   TColStd_SequenceOfReal npb, npr, npt, npl;
1077   for(i=0; i<nb; i++) {
1078     npb.Append(uv_eb[i].normParam);
1079     //cout<<"i="<<i<<" par="<<uv_eb[i].normParam<<" npar="<<uv_eb[i].normParam;
1080     //const SMDS_MeshNode* N = uv_eb[i].node;
1081     //cout<<" node("<<N->X()<<","<<N->Y()<<","<<N->Z()<<")"<<endl;
1082   }
1083   for(i=0; i<nr; i++) {
1084     npr.Append(uv_er[i].normParam);
1085   }
1086   for(i=0; i<nt; i++) {
1087     npt.Append(uv_et[i].normParam);
1088   }
1089   for(i=0; i<nl; i++) {
1090     npl.Append(uv_el[i].normParam);
1091   }
1092
1093   int dl,dr;
1094   if(OldVersion) {
1095     // add some params to right and left after the first param
1096     // insert to right
1097     dr = nbv - nr;
1098     double dpr = (npr.Value(2) - npr.Value(1))/(dr+1);
1099     for(i=1; i<=dr; i++) {
1100       npr.InsertAfter(1,npr.Value(2)-dpr);
1101     }
1102     // insert to left
1103     dl = nbv - nl;
1104     dpr = (npl.Value(2) - npl.Value(1))/(dl+1);
1105     for(i=1; i<=dl; i++) {
1106       npl.InsertAfter(1,npl.Value(2)-dpr);
1107     }
1108   }
1109   //cout<<"npb:";
1110   //for(i=1; i<=npb.Length(); i++) {
1111   //  cout<<" "<<npb.Value(i);
1112   //}
1113   //cout<<endl;
1114   
1115   gp_XY a0( uv_eb.front().u, uv_eb.front().v );
1116   gp_XY a1( uv_eb.back().u,  uv_eb.back().v );
1117   gp_XY a2( uv_et.back().u,  uv_et.back().v );
1118   gp_XY a3( uv_et.front().u, uv_et.front().v );
1119   //cout<<" a0("<<a0.X()<<","<<a0.Y()<<")"<<" a1("<<a1.X()<<","<<a1.Y()<<")"
1120   //    <<" a2("<<a2.X()<<","<<a2.Y()<<")"<<" a3("<<a3.X()<<","<<a3.Y()<<")"<<endl;
1121
1122   int nnn = Min(nr,nl);
1123   // auxilary sequence of XY for creation nodes
1124   // in the bottom part of central domain
1125   // it's length must be == nbv-nnn-1
1126   TColgp_SequenceOfXY UVL;
1127   TColgp_SequenceOfXY UVR;
1128
1129   if(OldVersion) {
1130     // step1: create faces for left domain
1131     StdMeshers_Array2OfNode NodesL(1,dl+1,1,nl);
1132     // add left nodes
1133     for(j=1; j<=nl; j++)
1134       NodesL.SetValue(1,j,uv_el[j-1].node);
1135     if(dl>0) {
1136       // add top nodes
1137       for(i=1; i<=dl; i++) 
1138         NodesL.SetValue(i+1,nl,uv_et[i].node);
1139       // create and add needed nodes
1140       TColgp_SequenceOfXY UVtmp;
1141       for(i=1; i<=dl; i++) {
1142         double x0 = npt.Value(i+1);
1143         double x1 = x0;
1144         // diagonal node
1145         double y0 = npl.Value(i+1);
1146         double y1 = npr.Value(i+1);
1147         gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
1148         gp_Pnt P = S->Value(UV.X(),UV.Y());
1149         SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1150         meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
1151         NodesL.SetValue(i+1,1,N);
1152         if(UVL.Length()<nbv-nnn-1) UVL.Append(UV);
1153         // internal nodes
1154         for(j=2; j<nl; j++) {
1155           double y0 = npl.Value(dl+j);
1156           double y1 = npr.Value(dl+j);
1157           gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
1158           gp_Pnt P = S->Value(UV.X(),UV.Y());
1159           SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1160           meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
1161           NodesL.SetValue(i+1,j,N);
1162           if( i==dl ) UVtmp.Append(UV);
1163         }
1164       }
1165       for(i=1; i<=UVtmp.Length() && UVL.Length()<nbv-nnn-1; i++) {
1166         UVL.Append(UVtmp.Value(i));
1167       }
1168       //cout<<"Dump NodesL:"<<endl;
1169       //for(i=1; i<=dl+1; i++) {
1170       //  cout<<"i="<<i;
1171       //  for(j=1; j<=nl; j++) {
1172       //    cout<<" ("<<NodesL.Value(i,j)->X()<<","<<NodesL.Value(i,j)->Y()<<","<<NodesL.Value(i,j)->Z()<<")";
1173       //  }
1174       //  cout<<endl;
1175       //}
1176       // create faces
1177       for(i=1; i<=dl; i++) {
1178         for(j=1; j<nl; j++) {
1179           if(WisF) {
1180             SMDS_MeshFace* F =
1181               myTool->AddFace(NodesL.Value(i,j), NodesL.Value(i+1,j),
1182                               NodesL.Value(i+1,j+1), NodesL.Value(i,j+1));
1183             meshDS->SetMeshElementOnShape(F, geomFaceID);
1184           }
1185           else {
1186             SMDS_MeshFace* F =
1187               myTool->AddFace(NodesL.Value(i,j), NodesL.Value(i,j+1),
1188                               NodesL.Value(i+1,j+1), NodesL.Value(i+1,j));
1189             meshDS->SetMeshElementOnShape(F, geomFaceID);
1190           }
1191         }
1192       }
1193     }
1194     else {
1195       // fill UVL using c2d
1196       for(i=1; i<npl.Length() && UVL.Length()<nbv-nnn-1; i++) {
1197         UVL.Append( gp_UV ( uv_el[i].u, uv_el[i].v ));
1198       }
1199     }
1200     
1201     // step2: create faces for right domain
1202     StdMeshers_Array2OfNode NodesR(1,dr+1,1,nr);
1203     // add right nodes
1204     for(j=1; j<=nr; j++) 
1205       NodesR.SetValue(1,j,uv_er[nr-j].node);
1206     if(dr>0) {
1207       // add top nodes
1208       for(i=1; i<=dr; i++) 
1209         NodesR.SetValue(i+1,1,uv_et[nt-1-i].node);
1210       // create and add needed nodes
1211       TColgp_SequenceOfXY UVtmp;
1212       for(i=1; i<=dr; i++) {
1213         double x0 = npt.Value(nt-i);
1214         double x1 = x0;
1215         // diagonal node
1216         double y0 = npl.Value(i+1);
1217         double y1 = npr.Value(i+1);
1218         gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
1219         gp_Pnt P = S->Value(UV.X(),UV.Y());
1220         SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1221         meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
1222         NodesR.SetValue(i+1,nr,N);
1223         if(UVR.Length()<nbv-nnn-1) UVR.Append(UV);
1224         // internal nodes
1225         for(j=2; j<nr; j++) {
1226           double y0 = npl.Value(nbv-j+1);
1227           double y1 = npr.Value(nbv-j+1);
1228           gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
1229           gp_Pnt P = S->Value(UV.X(),UV.Y());
1230           SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1231           meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
1232           NodesR.SetValue(i+1,j,N);
1233           if( i==dr ) UVtmp.Prepend(UV);
1234         }
1235       }
1236       for(i=1; i<=UVtmp.Length() && UVR.Length()<nbv-nnn-1; i++) {
1237         UVR.Append(UVtmp.Value(i));
1238       }
1239       // create faces
1240       for(i=1; i<=dr; i++) {
1241         for(j=1; j<nr; j++) {
1242           if(WisF) {
1243             SMDS_MeshFace* F =
1244               myTool->AddFace(NodesR.Value(i,j), NodesR.Value(i+1,j),
1245                               NodesR.Value(i+1,j+1), NodesR.Value(i,j+1));
1246             meshDS->SetMeshElementOnShape(F, geomFaceID);
1247           }
1248           else {
1249             SMDS_MeshFace* F =
1250               myTool->AddFace(NodesR.Value(i,j), NodesR.Value(i,j+1),
1251                               NodesR.Value(i+1,j+1), NodesR.Value(i+1,j));
1252             meshDS->SetMeshElementOnShape(F, geomFaceID);
1253           }
1254         }
1255       }
1256     }
1257     else {
1258       // fill UVR using c2d
1259       for(i=1; i<npr.Length() && UVR.Length()<nbv-nnn-1; i++) {
1260         UVR.Append( gp_UV( uv_er[i].u, uv_er[i].v ));
1261       }
1262     }
1263     
1264     // step3: create faces for central domain
1265     StdMeshers_Array2OfNode NodesC(1,nb,1,nbv);
1266     // add first string using NodesL
1267     for(i=1; i<=dl+1; i++)
1268       NodesC.SetValue(1,i,NodesL(i,1));
1269     for(i=2; i<=nl; i++)
1270       NodesC.SetValue(1,dl+i,NodesL(dl+1,i));
1271     // add last string using NodesR
1272     for(i=1; i<=dr+1; i++)
1273       NodesC.SetValue(nb,i,NodesR(i,nr));
1274     for(i=1; i<nr; i++)
1275       NodesC.SetValue(nb,dr+i+1,NodesR(dr+1,nr-i));
1276     // add top nodes (last columns)
1277     for(i=dl+2; i<nbh-dr; i++) 
1278       NodesC.SetValue(i-dl,nbv,uv_et[i-1].node);
1279     // add bottom nodes (first columns)
1280     for(i=2; i<nb; i++)
1281       NodesC.SetValue(i,1,uv_eb[i-1].node);
1282     
1283     // create and add needed nodes
1284     // add linear layers
1285     for(i=2; i<nb; i++) {
1286       double x0 = npt.Value(dl+i);
1287       double x1 = x0;
1288       for(j=1; j<nnn; j++) {
1289         double y0 = npl.Value(nbv-nnn+j);
1290         double y1 = npr.Value(nbv-nnn+j);
1291         gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
1292         gp_Pnt P = S->Value(UV.X(),UV.Y());
1293         SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1294         meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
1295         NodesC.SetValue(i,nbv-nnn+j,N);
1296       }
1297     }
1298     // add diagonal layers
1299     //cout<<"UVL.Length()="<<UVL.Length()<<" UVR.Length()="<<UVR.Length()<<endl;
1300     //cout<<"Dump UVL:"<<endl;
1301     //for(i=1; i<=UVL.Length(); i++) {
1302     //  cout<<" ("<<UVL.Value(i).X()<<","<<UVL.Value(i).Y()<<")";
1303     //}
1304     //cout<<endl;
1305     for(i=1; i<nbv-nnn; i++) {
1306       double du = UVR.Value(i).X() - UVL.Value(i).X();
1307       double dv = UVR.Value(i).Y() - UVL.Value(i).Y();
1308       for(j=2; j<nb; j++) {
1309         double u = UVL.Value(i).X() + du*npb.Value(j);
1310         double v = UVL.Value(i).Y() + dv*npb.Value(j);
1311         gp_Pnt P = S->Value(u,v);
1312         SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1313         meshDS->SetNodeOnFace(N, geomFaceID, u, v);
1314         NodesC.SetValue(j,i+1,N);
1315       }
1316     }
1317     // create faces
1318     for(i=1; i<nb; i++) {
1319       for(j=1; j<nbv; j++) {
1320         if(WisF) {
1321           SMDS_MeshFace* F =
1322             myTool->AddFace(NodesC.Value(i,j), NodesC.Value(i+1,j),
1323                             NodesC.Value(i+1,j+1), NodesC.Value(i,j+1));
1324           meshDS->SetMeshElementOnShape(F, geomFaceID);
1325         }
1326         else {
1327           SMDS_MeshFace* F =
1328             myTool->AddFace(NodesC.Value(i,j), NodesC.Value(i,j+1),
1329                             NodesC.Value(i+1,j+1), NodesC.Value(i+1,j));
1330           meshDS->SetMeshElementOnShape(F, geomFaceID);
1331         }
1332       }
1333     }
1334   }
1335
1336   else { // New version (!OldVersion)
1337     // step1: create faces for bottom rectangle domain
1338     StdMeshers_Array2OfNode NodesBRD(1,nb,1,nnn-1);
1339     // fill UVL and UVR using c2d
1340     for(j=0; j<nb; j++) {
1341       NodesBRD.SetValue(j+1,1,uv_eb[j].node);
1342     }
1343     for(i=1; i<nnn-1; i++) {
1344       NodesBRD.SetValue(1,i+1,uv_el[i].node);
1345       NodesBRD.SetValue(nb,i+1,uv_er[i].node);
1346       double du = uv_er[i].u - uv_el[i].u;
1347       double dv = uv_er[i].v - uv_el[i].v;
1348       for(j=2; j<nb; j++) {
1349         double u = uv_el[i].u + du*npb.Value(j);
1350         double v = uv_el[i].v + dv*npb.Value(j);
1351         gp_Pnt P = S->Value(u,v);
1352         SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1353         meshDS->SetNodeOnFace(N, geomFaceID, u, v);
1354         NodesBRD.SetValue(j,i+1,N);
1355
1356       }
1357     }
1358     for(j=1; j<nnn-1; j++) {
1359       for(i=1; i<nb; i++) {
1360         if(WisF) {
1361           SMDS_MeshFace* F =
1362             myTool->AddFace(NodesBRD.Value(i,j), NodesBRD.Value(i+1,j),
1363                             NodesBRD.Value(i+1,j+1), NodesBRD.Value(i,j+1));
1364           meshDS->SetMeshElementOnShape(F, geomFaceID);
1365         }
1366         else {
1367           SMDS_MeshFace* F =
1368             myTool->AddFace(NodesBRD.Value(i,j), NodesBRD.Value(i,j+1),
1369                             NodesBRD.Value(i+1,j+1), NodesBRD.Value(i+1,j));
1370           meshDS->SetMeshElementOnShape(F, geomFaceID);
1371         }
1372       }
1373     }
1374
1375     int drl = abs(nr-nl);
1376     // create faces for region C
1377     StdMeshers_Array2OfNode NodesC(1,nb,1,drl+1+addv);
1378     // add nodes from previous region
1379     for(j=1; j<=nb; j++) {
1380       NodesC.SetValue(j,1,NodesBRD.Value(j,nnn-1));
1381     }
1382     if( (drl+addv) > 0 ) {
1383       int n1,n2;
1384       if(nr>nl) {
1385         n1 = 1;
1386         n2 = drl + 1;
1387         TColgp_SequenceOfXY UVtmp;
1388         double drparam = npr.Value(nr) - npr.Value(nnn-1);
1389         double dlparam = npl.Value(nnn) - npl.Value(nnn-1);
1390         double y0,y1;
1391         for(i=1; i<=drl; i++) {
1392           // add existed nodes from right edge
1393           NodesC.SetValue(nb,i+1,uv_er[nnn+i-2].node);
1394           //double dtparam = npt.Value(i+1);
1395           y1 = npr.Value(nnn+i-1); // param on right edge
1396           double dpar = (y1 - npr.Value(nnn-1))/drparam;
1397           y0 = npl.Value(nnn-1) + dpar*dlparam; // param on left edge
1398           double dy = y1 - y0;
1399           for(j=1; j<nb; j++) {
1400             double x = npt.Value(i+1) + npb.Value(j)*(1-npt.Value(i+1));
1401             double y = y0 + dy*x;
1402             gp_UV UV = CalcUV2(x, y, quad, a0, a1, a2, a3);
1403             gp_Pnt P = S->Value(UV.X(),UV.Y());
1404             SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1405             meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
1406             NodesC.SetValue(j,i+1,N);
1407           }
1408         }
1409         double dy0 = (1-y0)/(addv+1);
1410         double dy1 = (1-y1)/(addv+1);
1411         for(i=1; i<=addv; i++) {
1412           double yy0 = y0 + dy0*i;
1413           double yy1 = y1 + dy1*i;
1414           double dyy = yy1 - yy0;
1415           for(j=1; j<=nb; j++) {
1416             double x = npt.Value(i+1+drl) + 
1417               npb.Value(j) * ( npt.Value(nt-i) - npt.Value(i+1+drl) );
1418             double y = yy0 + dyy*x;
1419             gp_UV UV = CalcUV2(x, y, quad, a0, a1, a2, a3);
1420             gp_Pnt P = S->Value(UV.X(),UV.Y());
1421             SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1422             meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
1423             NodesC.SetValue(j,i+drl+1,N);
1424           }
1425         }
1426       }
1427       else { // nr<nl
1428         n2 = 1;
1429         n1 = drl + 1;
1430         TColgp_SequenceOfXY UVtmp;
1431         double dlparam = npl.Value(nl) - npl.Value(nnn-1);
1432         double drparam = npr.Value(nnn) - npr.Value(nnn-1);
1433         double y0 = npl.Value(nnn-1);
1434         double y1 = npr.Value(nnn-1);
1435         for(i=1; i<=drl; i++) {
1436           // add existed nodes from right edge
1437           NodesC.SetValue(1,i+1,uv_el[nnn+i-2].node);
1438           y0 = npl.Value(nnn+i-1); // param on left edge
1439           double dpar = (y0 - npl.Value(nnn-1))/dlparam;
1440           y1 = npr.Value(nnn-1) + dpar*drparam; // param on right edge
1441           double dy = y1 - y0;
1442           for(j=2; j<=nb; j++) {
1443             double x = npb.Value(j)*npt.Value(nt-i);
1444             double y = y0 + dy*x;
1445             gp_UV UV = CalcUV2(x, y, quad, a0, a1, a2, a3);
1446             gp_Pnt P = S->Value(UV.X(),UV.Y());
1447             SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1448             meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
1449             NodesC.SetValue(j,i+1,N);
1450           }
1451         }
1452         double dy0 = (1-y0)/(addv+1);
1453         double dy1 = (1-y1)/(addv+1);
1454         for(i=1; i<=addv; i++) {
1455           double yy0 = y0 + dy0*i;
1456           double yy1 = y1 + dy1*i;
1457           double dyy = yy1 - yy0;
1458           for(j=1; j<=nb; j++) {
1459             double x = npt.Value(i+1) + 
1460               npb.Value(j) * ( npt.Value(nt-i-drl) - npt.Value(i+1) );
1461             double y = yy0 + dyy*x;
1462             gp_UV UV = CalcUV2(x, y, quad, a0, a1, a2, a3);
1463             gp_Pnt P = S->Value(UV.X(),UV.Y());
1464             SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
1465             meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
1466             NodesC.SetValue(j,i+drl+1,N);
1467           }
1468         }
1469       }
1470       // create faces
1471       for(j=1; j<=drl+addv; j++) {
1472         for(i=1; i<nb; i++) {
1473           if(WisF) {
1474             SMDS_MeshFace* F =
1475               myTool->AddFace(NodesC.Value(i,j), NodesC.Value(i+1,j),
1476                               NodesC.Value(i+1,j+1), NodesC.Value(i,j+1));
1477             meshDS->SetMeshElementOnShape(F, geomFaceID);
1478           }
1479           else {
1480             SMDS_MeshFace* F =
1481               myTool->AddFace(NodesC.Value(i,j), NodesC.Value(i,j+1),
1482                               NodesC.Value(i+1,j+1), NodesC.Value(i+1,j));
1483             meshDS->SetMeshElementOnShape(F, geomFaceID);
1484           }
1485         }
1486       } // end nr<nl
1487
1488       StdMeshers_Array2OfNode NodesLast(1,nt,1,2);
1489       for(i=1; i<=nt; i++) {
1490         NodesLast.SetValue(i,2,uv_et[i-1].node);
1491       }
1492       int nnn=0;
1493       for(i=n1; i<drl+addv+1; i++) {
1494         nnn++;
1495         NodesLast.SetValue(nnn,1,NodesC.Value(1,i));
1496       }
1497       for(i=1; i<=nb; i++) {
1498         nnn++;
1499         NodesLast.SetValue(nnn,1,NodesC.Value(i,drl+addv+1));
1500       }
1501       for(i=drl+addv; i>=n2; i--) {
1502         nnn++;
1503         NodesLast.SetValue(nnn,1,NodesC.Value(nb,i));
1504       }
1505       for(i=1; i<nt; i++) {
1506         if(WisF) {
1507           SMDS_MeshFace* F =
1508             myTool->AddFace(NodesLast.Value(i,1), NodesLast.Value(i+1,1),
1509                             NodesLast.Value(i+1,2), NodesLast.Value(i,2));
1510           meshDS->SetMeshElementOnShape(F, geomFaceID);
1511         }
1512         else {
1513           SMDS_MeshFace* F =
1514             myTool->AddFace(NodesLast.Value(i,1), NodesLast.Value(i,2),
1515                             NodesLast.Value(i+1,2), NodesLast.Value(i+1,2));
1516           meshDS->SetMeshElementOnShape(F, geomFaceID);
1517         }
1518       }
1519     } // if( (drl+addv) > 0 )
1520
1521   } // end new version implementation
1522
1523   bool isOk = true;
1524   return isOk;
1525 }
1526