Salome HOME
e40390c6e7596e5b8d8b383853bdb07825eb616e
[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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
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 using namespace std;
31 #include "StdMeshers_Quadrangle_2D.hxx"
32 #include "SMESH_Gen.hxx"
33 #include "SMESH_Mesh.hxx"
34 #include "SMESH_subMesh.hxx"
35
36 #include "SMDS_MeshElement.hxx"
37 #include "SMDS_MeshNode.hxx"
38 #include "SMDS_EdgePosition.hxx"
39 #include "SMDS_FacePosition.hxx"
40
41 #include <BRep_Tool.hxx>
42 #include <BRepTools.hxx>
43 #include <BRepTools_WireExplorer.hxx>
44
45 #include <Geom_Surface.hxx>
46 #include <Geom_Curve.hxx>
47 #include <Geom2d_Curve.hxx>
48 #include <GeomAdaptor_Curve.hxx>
49 #include <GCPnts_UniformAbscissa.hxx>
50
51 #include <Precision.hxx>
52 #include <gp_Pnt2d.hxx>
53 #include <TColStd_ListIteratorOfListOfInteger.hxx>
54
55 #include "utilities.h"
56 #include "Utils_ExceptHandlers.hxx"
57
58
59 //=============================================================================
60 /*!
61  *  
62  */
63 //=============================================================================
64
65 StdMeshers_Quadrangle_2D::StdMeshers_Quadrangle_2D (int hypId, int studyId, SMESH_Gen* gen)
66      : SMESH_2D_Algo(hypId, studyId, gen)
67 {
68   MESSAGE("StdMeshers_Quadrangle_2D::StdMeshers_Quadrangle_2D");
69   _name = "Quadrangle_2D";
70   _shapeType = (1 << TopAbs_FACE);
71   _compatibleHypothesis.push_back("QuadranglePreference");
72 }
73
74 //=============================================================================
75 /*!
76  *  
77  */
78 //=============================================================================
79
80 StdMeshers_Quadrangle_2D::~StdMeshers_Quadrangle_2D()
81 {
82   MESSAGE("StdMeshers_Quadrangle_2D::~StdMeshers_Quadrangle_2D");
83 }
84
85 //=============================================================================
86 /*!
87  *  
88  */
89 //=============================================================================
90
91 bool StdMeshers_Quadrangle_2D::CheckHypothesis
92                          (SMESH_Mesh&                          aMesh,
93                           const TopoDS_Shape&                  aShape,
94                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
95 {
96   bool isOk = true;
97   aStatus = SMESH_Hypothesis::HYP_OK;
98
99   // there is only one compatible Hypothesis so far
100   const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape);
101   myQuadranglePreference = hyps.size() > 0;
102
103   return isOk;
104 }
105
106 //=============================================================================
107 /*!
108  *  
109  */
110 //=============================================================================
111
112 bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
113                                         const TopoDS_Shape& aShape) throw (SALOME_Exception)
114 {
115   Unexpect aCatch(SalomeException);
116   //MESSAGE("StdMeshers_Quadrangle_2D::Compute");
117   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
118   aMesh.GetSubMesh(aShape);
119
120   FaceQuadStruct *quad = CheckAnd2Dcompute(aMesh, aShape);
121   if (!quad)
122     return false;
123
124   // --- compute 3D values on points, store points & quadrangles
125
126   int nbdown  = quad->nbPts[0];
127   int nbup    = quad->nbPts[2];
128
129   int nbright = quad->nbPts[1];
130   int nbleft  = quad->nbPts[3];
131
132   int nbhoriz  = Min(nbdown, nbup);
133   int nbvertic = Min(nbright, nbleft);
134
135   const TopoDS_Face& F = TopoDS::Face(aShape);
136   Handle(Geom_Surface) S = BRep_Tool::Surface(F);
137
138   // internal mesh nodes
139   int i, j, geomFaceID = meshDS->ShapeToIndex( F );
140   for (i = 1; i < nbhoriz - 1; i++) {
141     for (j = 1; j < nbvertic - 1; j++) {
142       int ij = j * nbhoriz + i;
143       double u = quad->uv_grid[ij].u;
144       double v = quad->uv_grid[ij].v;
145       gp_Pnt P = S->Value(u, v);
146       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
147       meshDS->SetNodeOnFace(node, geomFaceID, u, v);
148       quad->uv_grid[ij].node = node;
149     }
150   }
151
152   // mesh faces
153
154   //             [2]
155   //      --.--.--.--.--.--  nbvertic
156   //     |                 | ^
157   //     |                 | ^
158   // [3] |                 | ^ j  [1]
159   //     |                 | ^
160   //     |                 | ^
161   //      ---.----.----.---  0
162   //     0 > > > > > > > > nbhoriz
163   //              i
164   //             [0]
165
166   i = 0;
167   int ilow = 0;
168   int iup = nbhoriz - 1;
169   if (quad->isEdgeOut[3]) { ilow++; } else { if (quad->isEdgeOut[1]) iup--; }
170
171   int jlow = 0;
172   int jup = nbvertic - 1;
173   if (quad->isEdgeOut[0]) { jlow++; } else { if (quad->isEdgeOut[2]) jup--; }
174
175   // regular quadrangles
176   for (i = ilow; i < iup; i++) {
177     for (j = jlow; j < jup; j++) {
178       const SMDS_MeshNode *a, *b, *c, *d;
179       a = quad->uv_grid[j * nbhoriz + i].node;
180       b = quad->uv_grid[j * nbhoriz + i + 1].node;
181       c = quad->uv_grid[(j + 1) * nbhoriz + i + 1].node;
182       d = quad->uv_grid[(j + 1) * nbhoriz + i].node;
183       SMDS_MeshFace * face = meshDS->AddFace(a, b, c, d);
184       meshDS->SetMeshElementOnShape(face, geomFaceID);
185     }
186   }
187
188   UVPtStruct *uv_e0 = quad->uv_edges[0];
189   UVPtStruct *uv_e1 = quad->uv_edges[1];
190   UVPtStruct *uv_e2 = quad->uv_edges[2];
191   UVPtStruct *uv_e3 = quad->uv_edges[3];
192
193   double eps = Precision::Confusion();
194
195   // Boundary quadrangles
196
197   if (quad->isEdgeOut[0]) {
198     // Down edge is out
199     // 
200     // |___|___|___|___|___|___|
201     // |   |   |   |   |   |   |
202     // |___|___|___|___|___|___|
203     // |   |   |   |   |   |   |
204     // |___|___|___|___|___|___| __ first row of the regular grid
205     // .  .  .  .  .  .  .  .  . __ down edge nodes
206     // 
207     // >->->->->->->->->->->->-> -- direction of processing
208
209     int g = 0; // number of last processed node in the regular grid
210
211     // number of last node of the down edge to be processed
212     int stop = nbdown - 1;
213     // if right edge is out, we will stop at a node, previous to the last one
214     if (quad->isEdgeOut[1]) stop--;
215
216     // for each node of the down edge find nearest node
217     // in the first row of the regular grid and link them
218     for (i = 0; i < stop; i++) {
219       const SMDS_MeshNode *a, *b, *c, *d;
220       a = uv_e0[i].node;
221       b = uv_e0[i + 1].node;
222       gp_Pnt pb (b->X(), b->Y(), b->Z());
223
224       // find node c in the regular grid, which will be linked with node b
225       int near = g;
226       if (i == stop - 1) {
227         // right bound reached, link with the rightmost node
228         near = iup;
229         c = quad->uv_grid[nbhoriz + iup].node;
230       } else {
231         // find in the grid node c, nearest to the b
232         double mind = RealLast();
233         for (int k = g; k <= iup; k++) {
234
235           const SMDS_MeshNode *nk;
236           if (k < ilow) // this can be, if left edge is out
237             nk = uv_e3[1].node; // get node from the left edge
238           else
239             nk = quad->uv_grid[nbhoriz + k].node; // get one of middle nodes
240
241           gp_Pnt pnk (nk->X(), nk->Y(), nk->Z());
242           double dist = pb.Distance(pnk);
243           if (dist < mind - eps) {
244             c = nk;
245             near = k;
246             mind = dist;
247           } else {
248             break;
249           }
250         }
251       }
252
253       if (near == g) { // make triangle
254         SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
255         meshDS->SetMeshElementOnShape(face, geomFaceID);
256       } else { // make quadrangle
257         if (near - 1 < ilow)
258           d = uv_e3[1].node;
259         else
260           d = quad->uv_grid[nbhoriz + near - 1].node;
261         SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
262         meshDS->SetMeshElementOnShape(face, geomFaceID);
263
264         // if node d is not at position g - make additional triangles
265         if (near - 1 > g) {
266           for (int k = near - 1; k > g; k--) {
267             c = quad->uv_grid[nbhoriz + k].node;
268             if (k - 1 < ilow)
269               d = uv_e3[1].node;
270             else
271               d = quad->uv_grid[nbhoriz + k - 1].node;
272             SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
273             meshDS->SetMeshElementOnShape(face, geomFaceID);
274           }
275         }
276         g = near;
277       }
278     }
279   } else {
280     if (quad->isEdgeOut[2]) {
281       // Up edge is out
282       // 
283       // <-<-<-<-<-<-<-<-<-<-<-<-< -- direction of processing
284       // 
285       // .  .  .  .  .  .  .  .  . __ up edge nodes
286       //  ___ ___ ___ ___ ___ ___  __ first row of the regular grid
287       // |   |   |   |   |   |   |
288       // |___|___|___|___|___|___|
289       // |   |   |   |   |   |   |
290       // |___|___|___|___|___|___|
291       // |   |   |   |   |   |   |
292
293       int g = nbhoriz - 1; // last processed node in the regular grid
294
295       int stop = 0;
296       // if left edge is out, we will stop at a second node
297       if (quad->isEdgeOut[3]) stop++;
298
299       // for each node of the up edge find nearest node
300       // in the first row of the regular grid and link them
301       for (i = nbup - 1; i > stop; i--) {
302         const SMDS_MeshNode *a, *b, *c, *d;
303         a = uv_e2[i].node;
304         b = uv_e2[i - 1].node;
305         gp_Pnt pb (b->X(), b->Y(), b->Z());
306
307         // find node c in the grid, which will be linked with node b
308         int near = g;
309         if (i == stop + 1) { // left bound reached, link with the leftmost node
310           c = quad->uv_grid[nbhoriz*(nbvertic - 2) + ilow].node;
311           near = ilow;
312         } else {
313           // find node c in the grid, nearest to the b
314           double mind = RealLast();
315           for (int k = g; k >= ilow; k--) {
316             const SMDS_MeshNode *nk;
317             if (k > iup)
318               nk = uv_e1[nbright - 2].node;
319             else
320               nk = quad->uv_grid[nbhoriz*(nbvertic - 2) + k].node;
321             gp_Pnt pnk (nk->X(), nk->Y(), nk->Z());
322             double dist = pb.Distance(pnk);
323             if (dist < mind - eps) {
324               c = nk;
325               near = k;
326               mind = dist;
327             } else {
328               break;
329             }
330           }
331         }
332
333         if (near == g) { // make triangle
334           SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
335           meshDS->SetMeshElementOnShape(face, geomFaceID);
336         } else { // make quadrangle
337           if (near + 1 > iup)
338             d = uv_e1[nbright - 2].node;
339           else
340             d = quad->uv_grid[nbhoriz*(nbvertic - 2) + near + 1].node;
341           SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
342           meshDS->SetMeshElementOnShape(face, geomFaceID);
343
344           if (near + 1 < g) { // if d not is at g - make additional triangles
345             for (int k = near + 1; k < g; k++) {
346               c = quad->uv_grid[nbhoriz*(nbvertic - 2) + k].node;
347               if (k + 1 > iup)
348                 d = uv_e1[nbright - 2].node;
349               else
350                 d = quad->uv_grid[nbhoriz*(nbvertic - 2) + k + 1].node;
351               SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
352               meshDS->SetMeshElementOnShape(face, geomFaceID);
353             }
354           }
355           g = near;
356         }
357       }
358     }
359   }
360
361   // right or left boundary quadrangles
362   if (quad->isEdgeOut[1]) {
363 //    MESSAGE("right edge is out");
364     int g = 0; // last processed node in the grid
365     int stop = nbright - 1;
366     if (quad->isEdgeOut[2]) stop--;
367     for (i = 0; i < stop; i++) {
368       const SMDS_MeshNode *a, *b, *c, *d;
369       a = uv_e1[i].node;
370       b = uv_e1[i + 1].node;
371       gp_Pnt pb (b->X(), b->Y(), b->Z());
372
373       // find node c in the grid, nearest to the b
374       int near = g;
375       if (i == stop - 1) { // up bondary reached
376         c = quad->uv_grid[nbhoriz*(jup + 1) - 2].node;
377         near = jup;
378       } else {
379         double mind = RealLast();
380         for (int k = g; k <= jup; k++) {
381           const SMDS_MeshNode *nk;
382           if (k < jlow)
383             nk = uv_e0[nbdown - 2].node;
384           else
385             nk = quad->uv_grid[nbhoriz*(k + 1) - 2].node;
386           gp_Pnt pnk (nk->X(), nk->Y(), nk->Z());
387           double dist = pb.Distance(pnk);
388           if (dist < mind - eps) {
389             c = nk;
390             near = k;
391             mind = dist;
392           } else {
393             break;
394           }
395         }
396       }
397
398       if (near == g) { // make triangle
399         SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
400         meshDS->SetMeshElementOnShape(face, geomFaceID);
401       } else { // make quadrangle
402         if (near - 1 < jlow)
403           d = uv_e0[nbdown - 2].node;
404         else
405           d = quad->uv_grid[nbhoriz*near - 2].node;
406         SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
407         meshDS->SetMeshElementOnShape(face, geomFaceID);
408
409         if (near - 1 > g) { // if d not is at g - make additional triangles
410           for (int k = near - 1; k > g; k--) {
411             c = quad->uv_grid[nbhoriz*(k + 1) - 2].node;
412             if (k - 1 < jlow)
413               d = uv_e0[nbdown - 2].node;
414             else
415               d = quad->uv_grid[nbhoriz*k - 2].node;
416             SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
417             meshDS->SetMeshElementOnShape(face, geomFaceID);
418           }
419         }
420         g = near;
421       }
422     }
423   } else {
424     if (quad->isEdgeOut[3]) {
425 //      MESSAGE("left edge is out");
426       int g = nbvertic - 1; // last processed node in the grid
427       int stop = 0;
428       if (quad->isEdgeOut[0]) stop++;
429       for (i = nbleft - 1; i > stop; i--) {
430         const SMDS_MeshNode *a, *b, *c, *d;
431         a = uv_e3[i].node;
432         b = uv_e3[i - 1].node;
433         gp_Pnt pb (b->X(), b->Y(), b->Z());
434
435         // find node c in the grid, nearest to the b
436         int near = g;
437         if (i == stop + 1) { // down bondary reached
438           c = quad->uv_grid[nbhoriz*jlow + 1].node;
439           near = jlow;
440         } else {
441           double mind = RealLast();
442           for (int k = g; k >= jlow; k--) {
443             const SMDS_MeshNode *nk;
444             if (k > jup)
445               nk = uv_e2[1].node;
446             else
447               nk = quad->uv_grid[nbhoriz*k + 1].node;
448             gp_Pnt pnk (nk->X(), nk->Y(), nk->Z());
449             double dist = pb.Distance(pnk);
450             if (dist < mind - eps) {
451               c = nk;
452               near = k;
453               mind = dist;
454             } else {
455               break;
456             }
457           }
458         }
459
460         if (near == g) { // make triangle
461           SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
462           meshDS->SetMeshElementOnShape(face, geomFaceID);
463         } else { // make quadrangle
464           if (near + 1 > jup)
465             d = uv_e2[1].node;
466           else
467             d = quad->uv_grid[nbhoriz*(near + 1) + 1].node;
468           SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
469           meshDS->SetMeshElementOnShape(face, geomFaceID);
470
471           if (near + 1 < g) { // if d not is at g - make additional triangles
472             for (int k = near + 1; k < g; k++) {
473               c = quad->uv_grid[nbhoriz*k + 1].node;
474               if (k + 1 > jup)
475                 d = uv_e2[1].node;
476               else
477                 d = quad->uv_grid[nbhoriz*(k + 1) + 1].node;
478               SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
479               meshDS->SetMeshElementOnShape(face, geomFaceID);
480             }
481           }
482           g = near;
483         }
484       }
485     }
486   }
487
488   QuadDelete(quad);
489   bool isOk = true;
490   return isOk;
491 }
492
493 //=============================================================================
494 /*!
495  *  
496  */
497 //=============================================================================
498
499 FaceQuadStruct *StdMeshers_Quadrangle_2D::CheckAnd2Dcompute
500   (SMESH_Mesh & aMesh, const TopoDS_Shape & aShape) throw(SALOME_Exception)
501 {
502   Unexpect aCatch(SalomeException);
503
504   const TopoDS_Face & F = TopoDS::Face(aShape);
505
506   // verify 1 wire only, with 4 edges
507
508   if (NumberOfWires(F) != 1)
509   {
510     INFOS("only 1 wire by face (quadrangles)");
511     return 0;
512   }
513   const TopoDS_Wire& W = BRepTools::OuterWire(F);
514   BRepTools_WireExplorer wexp (W, F);
515
516   FaceQuadStruct *quad = new FaceQuadStruct;
517   for (int i = 0; i < 4; i++)
518     quad->uv_edges[i] = 0;
519   quad->uv_grid = 0;
520
521   int nbEdges = 0;
522   for (wexp.Init(W, F); wexp.More(); wexp.Next())
523   {
524     const TopoDS_Edge& E = wexp.Current();
525     int nb = aMesh.GetSubMesh(E)->GetSubMeshDS()->NbNodes();
526     if (nbEdges < 4)
527     {
528       quad->edge[nbEdges] = E;
529       quad->nbPts[nbEdges] = nb + 2; // internal points + 2 extrema
530     }
531     nbEdges++;
532   }
533
534   if (nbEdges != 4)
535   {
536     INFOS("face must have 4 edges /quadrangles");
537     QuadDelete(quad);
538     return 0;
539   }
540
541   // set normalized grid on unit square in parametric domain
542
543   SetNormalizedGrid(aMesh, F, quad);
544
545   return quad;
546 }
547
548 //=============================================================================
549 /*!
550  *  
551  */
552 //=============================================================================
553
554 void StdMeshers_Quadrangle_2D::QuadDelete (FaceQuadStruct * quad)
555 {
556   //MESSAGE("StdMeshers_Quadrangle_2D::QuadDelete");
557   if (quad)
558   {
559     for (int i = 0; i < 4; i++)
560     {
561       if (quad->uv_edges[i])
562         delete [] quad->uv_edges[i];
563       quad->edge[i].Nullify();
564     }
565     if (quad->uv_grid)
566       delete [] quad->uv_grid;
567     delete quad;
568   }
569 }
570
571 //=============================================================================
572 /*!
573  *  
574  */
575 //=============================================================================
576
577 void StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh,
578                                                   const TopoDS_Shape& aShape,
579                                                   FaceQuadStruct* quad) throw (SALOME_Exception)
580 {
581   Unexpect aCatch(SalomeException);
582   // Algorithme décrit dans "Génération automatique de maillages"
583   // P.L. GEORGE, MASSON, Â§ 6.4.1 p. 84-85
584   // traitement dans le domaine paramétrique 2d u,v
585   // transport - projection sur le carré unité
586
587 //  MESSAGE("StdMeshers_Quadrangle_2D::SetNormalizedGrid");
588   const TopoDS_Face& F = TopoDS::Face(aShape);
589
590   // 1 --- find orientation of the 4 edges, by test on extrema
591
592   //      max             min                    0     x1     1
593   //     |<----north-2-------^                a3 -------------> a2
594   //     |                   |                   ^1          1^
595   //    west-3            east-1 =right          |            |
596   //     |                   |         ==>       |            |
597   //  y0 |                   | y1                |            |
598   //     |                   |                   |0          0|
599   //     v----south-0-------->                a0 -------------> a1
600   //      min             max                    0     x0     1
601   //             =down
602   //
603
604   Handle(Geom2d_Curve) c2d[4];
605   gp_Pnt2d pf[4];
606   gp_Pnt2d pl[4];
607   for (int i = 0; i < 4; i++)
608   {
609     c2d[i] = BRep_Tool::CurveOnSurface(quad->edge[i], F,
610                                        quad->first[i], quad->last[i]);
611     pf[i] = c2d[i]->Value(quad->first[i]);
612     pl[i] = c2d[i]->Value(quad->last[i]);
613     quad->isEdgeForward[i] = false;
614   }
615
616   double l0f1 = pl[0].SquareDistance(pf[1]);
617   double l0l1 = pl[0].SquareDistance(pl[1]);
618   double f0f1 = pf[0].SquareDistance(pf[1]);
619   double f0l1 = pf[0].SquareDistance(pl[1]);
620   if ( Min( l0f1, l0l1 ) < Min ( f0f1, f0l1 ))
621   {
622     quad->isEdgeForward[0] = true;
623   } else {
624     double tmp = quad->first[0];
625     quad->first[0] = quad->last[0];
626     quad->last[0] = tmp;
627     pf[0] = c2d[0]->Value(quad->first[0]);
628     pl[0] = c2d[0]->Value(quad->last[0]);
629   }
630   for (int i = 1; i < 4; i++)
631   {
632     l0l1 = pl[i - 1].SquareDistance(pl[i]);
633     l0f1 = pl[i - 1].SquareDistance(pf[i]);
634     quad->isEdgeForward[i] = ( l0f1 < l0l1 );
635     if (!quad->isEdgeForward[i])
636     {
637       double tmp = quad->first[i];
638       quad->first[i] = quad->last[i];
639       quad->last[i] = tmp;
640       pf[i] = c2d[i]->Value(quad->first[i]);
641       pl[i] = c2d[i]->Value(quad->last[i]);
642     }
643   }
644
645   // 2 --- load 2d edge points (u,v) with orientation and value on unit square
646
647   bool loadOk = true;
648   for (int i = 0; i < 2; i++)
649   {
650     quad->uv_edges[i] = LoadEdgePoints(aMesh, F, quad->edge[i],
651                                        quad->first[i], quad->last[i]);
652     if (!quad->uv_edges[i]) loadOk = false;
653   }
654
655   for (int i = 2; i < 4; i++)
656   {
657     quad->uv_edges[i] = LoadEdgePoints(aMesh, F, quad->edge[i],
658                                        quad->last[i], quad->first[i]);
659     if (!quad->uv_edges[i]) loadOk = false;
660   }
661
662   if (!loadOk)
663   {
664     INFOS("StdMeshers_Quadrangle_2D::SetNormalizedGrid - LoadEdgePoints failed");
665     QuadDelete( quad );
666     quad = 0;
667     return;
668   }
669   // 3 --- 2D normalized values on unit square [0..1][0..1]
670
671   int nbhoriz  = Min(quad->nbPts[0], quad->nbPts[2]);
672   int nbvertic = Min(quad->nbPts[1], quad->nbPts[3]);
673
674   quad->isEdgeOut[0] = (quad->nbPts[0] > quad->nbPts[2]);
675   quad->isEdgeOut[1] = (quad->nbPts[1] > quad->nbPts[3]);
676   quad->isEdgeOut[2] = (quad->nbPts[2] > quad->nbPts[0]);
677   quad->isEdgeOut[3] = (quad->nbPts[3] > quad->nbPts[1]);
678
679   quad->uv_grid = new UVPtStruct[nbvertic * nbhoriz];
680
681   UVPtStruct *uv_grid = quad->uv_grid;
682   UVPtStruct *uv_e0 = quad->uv_edges[0];
683   UVPtStruct *uv_e1 = quad->uv_edges[1];
684   UVPtStruct *uv_e2 = quad->uv_edges[2];
685   UVPtStruct *uv_e3 = quad->uv_edges[3];
686
687   // nodes Id on "in" edges
688   if (! quad->isEdgeOut[0]) {
689     int j = 0;
690     for (int i = 0; i < nbhoriz; i++) { // down
691       int ij = j * nbhoriz + i;
692       uv_grid[ij].node = uv_e0[i].node;
693     }
694   }
695   if (! quad->isEdgeOut[1]) {
696     int i = nbhoriz - 1;
697     for (int j = 0; j < nbvertic; j++) { // right
698       int ij = j * nbhoriz + i;
699       uv_grid[ij].node = uv_e1[j].node;
700     }
701   }
702   if (! quad->isEdgeOut[2]) {
703     int j = nbvertic - 1;
704     for (int i = 0; i < nbhoriz; i++) { // up
705       int ij = j * nbhoriz + i;
706       uv_grid[ij].node = uv_e2[i].node;
707     }
708   }
709   if (! quad->isEdgeOut[3]) {
710     int i = 0;
711     for (int j = 0; j < nbvertic; j++) { // left
712       int ij = j * nbhoriz + i;
713       uv_grid[ij].node = uv_e3[j].node;
714     }
715   }
716
717   // falsificate "out" edges
718   if (quad->isEdgeOut[0]) // down
719     uv_e0 = MakeEdgePoints
720       (aMesh, F, quad->edge[0], quad->first[0], quad->last[0], nbhoriz - 1);
721   else if (quad->isEdgeOut[2]) // up
722     uv_e2 = MakeEdgePoints
723       (aMesh, F, quad->edge[2], quad->last[2], quad->first[2], nbhoriz - 1);
724
725   if (quad->isEdgeOut[1]) // right
726     uv_e1 = MakeEdgePoints
727       (aMesh, F, quad->edge[1], quad->first[1], quad->last[1], nbvertic - 1);
728   else if (quad->isEdgeOut[3]) // left
729     uv_e3 = MakeEdgePoints
730       (aMesh, F, quad->edge[3], quad->last[3], quad->first[3], nbvertic - 1);
731
732   // normalized 2d values on grid
733   for (int i = 0; i < nbhoriz; i++)
734   {
735     for (int j = 0; j < nbvertic; j++)
736     {
737       int ij = j * nbhoriz + i;
738       // --- droite i cste : x = x0 + y(x1-x0)
739       double x0 = uv_e0[i].normParam;   // bas - sud
740       double x1 = uv_e2[i].normParam;   // haut - nord
741       // --- droite j cste : y = y0 + x(y1-y0)
742       double y0 = uv_e3[j].normParam;   // gauche-ouest
743       double y1 = uv_e1[j].normParam;   // droite - est
744       // --- intersection : x=x0+(y0+x(y1-y0))(x1-x0)
745       double x = (x0 + y0 * (x1 - x0)) / (1 - (y1 - y0) * (x1 - x0));
746       double y = y0 + x * (y1 - y0);
747       uv_grid[ij].x = x;
748       uv_grid[ij].y = y;
749       //MESSAGE("-xy-01 "<<x0<<" "<<x1<<" "<<y0<<" "<<y1);
750       //MESSAGE("-xy-norm "<<i<<" "<<j<<" "<<x<<" "<<y);
751     }
752   }
753
754   // 4 --- projection on 2d domain (u,v)
755   gp_Pnt2d a0 = pf[0];
756   gp_Pnt2d a1 = pf[1];
757   gp_Pnt2d a2 = pf[2];
758   gp_Pnt2d a3 = pf[3];
759
760   for (int i = 0; i < nbhoriz; i++)
761   {
762     for (int j = 0; j < nbvertic; j++)
763     {
764       int ij = j * nbhoriz + i;
765       double x = uv_grid[ij].x;
766       double y = uv_grid[ij].y;
767       double param_0 = uv_e0[0].param + x * (uv_e0[nbhoriz - 1].param - uv_e0[0].param); // sud
768       double param_2 = uv_e2[0].param + x * (uv_e2[nbhoriz - 1].param - uv_e2[0].param); // nord
769       double param_1 = uv_e1[0].param + y * (uv_e1[nbvertic - 1].param - uv_e1[0].param); // est
770       double param_3 = uv_e3[0].param + y * (uv_e3[nbvertic - 1].param - uv_e3[0].param); // ouest
771
772       //MESSAGE("params "<<param_0<<" "<<param_1<<" "<<param_2<<" "<<param_3);
773       gp_Pnt2d p0 = c2d[0]->Value(param_0);
774       gp_Pnt2d p1 = c2d[1]->Value(param_1);
775       gp_Pnt2d p2 = c2d[2]->Value(param_2);
776       gp_Pnt2d p3 = c2d[3]->Value(param_3);
777
778       double u = (1 - y) * p0.X() + x * p1.X() + y * p2.X() + (1 - x) * p3.X();
779       double v = (1 - y) * p0.Y() + x * p1.Y() + y * p2.Y() + (1 - x) * p3.Y();
780
781       u -= (1 - x) * (1 - y) * a0.X() + x * (1 - y) * a1.X() +
782         x * y * a2.X() + (1 - x) * y * a3.X();
783       v -= (1 - x) * (1 - y) * a0.Y() + x * (1 - y) * a1.Y() +
784         x * y * a2.Y() + (1 - x) * y * a3.Y();
785
786       uv_grid[ij].u = u;
787       uv_grid[ij].v = v;
788     }
789   }
790 }
791
792 //=============================================================================
793 /*!
794  *  LoadEdgePoints
795  */
796 //=============================================================================
797 UVPtStruct* StdMeshers_Quadrangle_2D::LoadEdgePoints (SMESH_Mesh & aMesh,
798                                                       const TopoDS_Face& F,
799                                                       const TopoDS_Edge& E,
800                                                       double first, double last)
801 //                        bool isForward)
802 {
803   //MESSAGE("StdMeshers_Quadrangle_2D::LoadEdgePoints");
804
805   // --- IDNodes of first and last Vertex
806
807   TopoDS_Vertex VFirst, VLast;
808   TopExp::Vertices(E, VFirst, VLast); // corresponds to f and l
809
810   ASSERT(!VFirst.IsNull());
811   SMDS_NodeIteratorPtr lid = aMesh.GetSubMesh(VFirst)->GetSubMeshDS()->GetNodes();
812   if (!lid->more())
813   {
814     MESSAGE ( "NO NODE BUILT ON VERTEX" );
815     return 0;
816   }
817   const SMDS_MeshNode* idFirst = lid->next();
818
819   ASSERT(!VLast.IsNull());
820   lid = aMesh.GetSubMesh(VLast)->GetSubMeshDS()->GetNodes();
821   if (!lid->more())
822   {
823     MESSAGE ( "NO NODE BUILT ON VERTEX" );
824     return 0;
825   }
826   const SMDS_MeshNode* idLast = lid->next();
827
828   // --- edge internal IDNodes (relies on good order storage, not checked)
829
830   map<double, const SMDS_MeshNode *> params;
831   SMDS_NodeIteratorPtr ite = aMesh.GetSubMesh(E)->GetSubMeshDS()->GetNodes();
832
833   while(ite->more())
834   {
835     const SMDS_MeshNode* node = ite->next();
836     const SMDS_EdgePosition* epos =
837       static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
838     double param = epos->GetUParameter();
839     params[param] = node;
840   }
841
842   int nbPoints = aMesh.GetSubMesh(E)->GetSubMeshDS()->NbNodes();
843   if (nbPoints != params.size())
844   {
845     MESSAGE( "BAD NODE ON EDGE POSITIONS" );
846     return 0;
847   }
848   UVPtStruct* uvslf = new UVPtStruct[nbPoints + 2];
849
850   double f, l;
851   Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, F, f, l);
852
853   bool isForward = (((l - f) * (last - first)) > 0);
854   double paramin = 0;
855   double paramax = 0;
856   if (isForward)
857   {
858     paramin = f;
859     paramax = l;
860     gp_Pnt2d p = C2d->Value(f); // first point = Vertex Forward
861     uvslf[0].x = p.X();
862     uvslf[0].y = p.Y();
863     uvslf[0].param = f;
864     uvslf[0].node = idFirst;
865     //MESSAGE("__ f "<<f<<" "<<uvslf[0].x <<" "<<uvslf[0].y);
866     map < double, const SMDS_MeshNode* >::iterator itp = params.begin();
867     for (int i = 1; i <= nbPoints; i++) // nbPoints internal
868     {
869       double param = (*itp).first;
870       gp_Pnt2d p = C2d->Value(param);
871       uvslf[i].x = p.X();
872       uvslf[i].y = p.Y();
873       uvslf[i].param = param;
874       uvslf[i].node = (*itp).second;
875       //MESSAGE("__ "<<i<<" "<<param<<" "<<uvslf[i].x <<" "<<uvslf[i].y);
876       itp++;
877     }
878     p = C2d->Value(l);          // last point = Vertex Reversed
879     uvslf[nbPoints + 1].x = p.X();
880     uvslf[nbPoints + 1].y = p.Y();
881     uvslf[nbPoints + 1].param = l;
882     uvslf[nbPoints + 1].node = idLast;
883     //MESSAGE("__ l "<<l<<" "<<uvslf[nbPoints+1].x <<" "<<uvslf[nbPoints+1].y);
884   } else
885   {
886     paramin = l;
887     paramax = f;
888     gp_Pnt2d p = C2d->Value(l); // first point = Vertex Reversed
889     uvslf[0].x = p.X();
890     uvslf[0].y = p.Y();
891     uvslf[0].param = l;
892     uvslf[0].node = idLast;
893     //MESSAGE("__ l "<<l<<" "<<uvslf[0].x <<" "<<uvslf[0].y);
894     map < double, const SMDS_MeshNode* >::reverse_iterator itp = params.rbegin();
895
896     for (int j = nbPoints; j >= 1; j--) // nbPoints internal
897     {
898       double param = (*itp).first;
899       int i = nbPoints + 1 - j;
900       gp_Pnt2d p = C2d->Value(param);
901       uvslf[i].x = p.X();
902       uvslf[i].y = p.Y();
903       uvslf[i].param = param;
904       uvslf[i].node = (*itp).second;
905       //MESSAGE("__ "<<i<<" "<<param<<" "<<uvslf[i].x <<" "<<uvslf[i].y);
906       itp++;
907     }
908     p = C2d->Value(f);          // last point = Vertex Forward
909     uvslf[nbPoints + 1].x = p.X();
910     uvslf[nbPoints + 1].y = p.Y();
911     uvslf[nbPoints + 1].param = f;
912     uvslf[nbPoints + 1].node = idFirst;
913     //MESSAGE("__ f "<<f<<" "<<uvslf[nbPoints+1].x <<" "<<uvslf[nbPoints+1].y);
914   }
915
916   ASSERT(paramin != paramax);
917   for (int i = 0; i < nbPoints + 2; i++)
918   {
919     uvslf[i].normParam = (uvslf[i].param - paramin) / (paramax - paramin);
920   }
921
922   return uvslf;
923 }
924
925 //=============================================================================
926 /*!
927  *  MakeEdgePoints
928  */
929 //=============================================================================
930 UVPtStruct* StdMeshers_Quadrangle_2D::MakeEdgePoints (SMESH_Mesh & aMesh,
931                                                       const TopoDS_Face& F,
932                                                       const TopoDS_Edge& E,
933                                                       double first, double last,
934                                                       int nb_segm)
935 {
936 //  MESSAGE("StdMeshers_Quadrangle_2D::MakeEdgePoints");
937
938   UVPtStruct* uvslf = new UVPtStruct[nb_segm + 1];
939   list<double> params;
940
941   // --- edge internal points
942   double fi, li;
943   Handle(Geom_Curve) Curve = BRep_Tool::Curve(E, fi, li);
944   if (!Curve.IsNull()) {
945     try {
946       GeomAdaptor_Curve C3d (Curve);
947       double length = EdgeLength(E);
948       double eltSize = length / nb_segm;
949       GCPnts_UniformAbscissa Discret (C3d, eltSize, fi, li);
950       if (!Discret.IsDone()) return false;
951       int NbPoints = Discret.NbPoints();
952       for (int i = 1; i <= NbPoints; i++) {
953         double param = Discret.Parameter(i);
954         params.push_back(param);
955       }
956     }
957     catch (Standard_Failure) {
958       return 0;
959     }
960   }
961   else
962   {
963     // Edge is a degenerated Edge
964     BRep_Tool::Range(E, fi, li);
965     double du = (li - fi) / nb_segm;
966     for (int i = 1; i <= nb_segm + 1; i++)
967     {
968       double param = fi + (i - 1) * du;
969       params.push_back(param);
970     }
971   }
972
973   double f, l;
974   Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, F, f, l);
975   ASSERT(f != l);
976
977   bool isForward = (((l - f) * (last - first)) > 0);
978   if (isForward) {
979     list<double>::iterator itU = params.begin();
980     for (int i = 0; i <= nb_segm; i++) // nbPoints internal
981     {
982       double param = *itU;
983       gp_Pnt2d p = C2d->Value(param);
984       uvslf[i].x = p.X();
985       uvslf[i].y = p.Y();
986       uvslf[i].param = param;
987       uvslf[i].normParam = (param - f) / (l - f);
988       itU++;
989     }
990   } else {
991     list<double>::reverse_iterator itU = params.rbegin();
992     for (int j = nb_segm; j >= 0; j--) // nbPoints internal
993     {
994       double param = *itU;
995       int i = nb_segm - j;
996       gp_Pnt2d p = C2d->Value(param);
997       uvslf[i].x = p.X();
998       uvslf[i].y = p.Y();
999       uvslf[i].param = param;
1000       uvslf[i].normParam = (param - l) / (f - l);
1001       itU++;
1002     }
1003   }
1004
1005   return uvslf;
1006 }
1007
1008
1009 //=============================================================================
1010 /*!
1011  *  
1012  */
1013 //=============================================================================
1014
1015 ostream & StdMeshers_Quadrangle_2D::SaveTo(ostream & save)
1016 {
1017   return save;
1018 }
1019
1020 //=============================================================================
1021 /*!
1022  *  
1023  */
1024 //=============================================================================
1025
1026 istream & StdMeshers_Quadrangle_2D::LoadFrom(istream & load)
1027 {
1028   return load;
1029 }
1030
1031 //=============================================================================
1032 /*!
1033  *  
1034  */
1035 //=============================================================================
1036
1037 ostream & operator <<(ostream & save, StdMeshers_Quadrangle_2D & hyp)
1038 {
1039   return hyp.SaveTo( save );
1040 }
1041
1042 //=============================================================================
1043 /*!
1044  *  
1045  */
1046 //=============================================================================
1047
1048 istream & operator >>(istream & load, StdMeshers_Quadrangle_2D & hyp)
1049 {
1050   return hyp.LoadFrom( load );
1051 }