Salome HOME
c97e7b3d2f1df7e90f6b7a4a9b47e5f1d5a398d0
[modules/smesh.git] / src / StdMeshers / StdMeshers_MEFISTO_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_MEFISTO_2D.cxx
25 //           Moved here from SMESH_MEFISTO_2D.cxx
26 //  Author : Paul RASCLE, EDF
27 //  Module : SMESH
28 //  $Header$
29
30 using namespace std;
31 #include "StdMeshers_MEFISTO_2D.hxx"
32 #include "SMESH_Gen.hxx"
33 #include "SMESH_Mesh.hxx"
34 #include "SMESH_subMesh.hxx"
35
36 #include "StdMeshers_MaxElementArea.hxx"
37 #include "StdMeshers_LengthFromEdges.hxx"
38
39 #include "Rn.h"
40 #include "aptrte.h"
41
42 #include "SMDS_MeshElement.hxx"
43 #include "SMDS_MeshNode.hxx"
44 #include "SMDS_EdgePosition.hxx"
45 #include "SMDS_FacePosition.hxx"
46
47 #include "utilities.h"
48
49 #include <TopoDS_Face.hxx>
50 #include <TopoDS_Edge.hxx>
51 #include <TopoDS_Shape.hxx>
52 #include <Geom_Surface.hxx>
53 #include <GeomAdaptor_Curve.hxx>
54 #include <Geom2d_Curve.hxx>
55 #include <gp_Pnt2d.hxx>
56 #include <BRep_Tool.hxx>
57 #include <BRepTools.hxx>
58 #include <BRepTools_WireExplorer.hxx>
59 #include <GCPnts_AbscissaPoint.hxx>
60 #include <GCPnts_UniformAbscissa.hxx>
61 #include <TColStd_ListIteratorOfListOfInteger.hxx>
62 #include <TopTools_ListIteratorOfListOfShape.hxx>
63 #include <TopTools_ListOfShape.hxx>
64
65 #include <string>
66 //#include <algorithm>
67
68 //=============================================================================
69 /*!
70  *  
71  */
72 //=============================================================================
73
74 StdMeshers_MEFISTO_2D::StdMeshers_MEFISTO_2D(int hypId, int studyId,
75                                              SMESH_Gen * gen):SMESH_2D_Algo(hypId, studyId, gen)
76 {
77   MESSAGE("StdMeshers_MEFISTO_2D::StdMeshers_MEFISTO_2D");
78   _name = "MEFISTO_2D";
79   _shapeType = (1 << TopAbs_FACE);
80   _compatibleHypothesis.push_back("MaxElementArea");
81   _compatibleHypothesis.push_back("LengthFromEdges");
82
83   _edgeLength = 0;
84   _maxElementArea = 0;
85   _hypMaxElementArea = NULL;
86   _hypLengthFromEdges = NULL;
87   myTool = 0;
88 }
89
90 //=============================================================================
91 /*!
92  *  
93  */
94 //=============================================================================
95
96 StdMeshers_MEFISTO_2D::~StdMeshers_MEFISTO_2D()
97 {
98   MESSAGE("StdMeshers_MEFISTO_2D::~StdMeshers_MEFISTO_2D");
99 }
100
101 //=============================================================================
102 /*!
103  *  
104  */
105 //=============================================================================
106
107 bool StdMeshers_MEFISTO_2D::CheckHypothesis
108                          (SMESH_Mesh& aMesh,
109                           const TopoDS_Shape& aShape,
110                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
111 {
112         //MESSAGE("StdMeshers_MEFISTO_2D::CheckHypothesis");
113
114         _hypMaxElementArea = NULL;
115         _hypLengthFromEdges = NULL;
116
117         list <const SMESHDS_Hypothesis * >::const_iterator itl;
118         const SMESHDS_Hypothesis *theHyp;
119
120         const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape);
121         int nbHyp = hyps.size();
122         if (!nbHyp)
123         {
124           aStatus = SMESH_Hypothesis::HYP_MISSING;
125           return false;  // can't work with no hypothesis
126         }
127
128         itl = hyps.begin();
129         theHyp = (*itl); // use only the first hypothesis
130
131         string hypName = theHyp->GetName();
132         //int hypId = theHyp->GetID();
133         //SCRUTE(hypName);
134
135         bool isOk = false;
136
137         if (hypName == "MaxElementArea")
138         {
139                 _hypMaxElementArea = static_cast<const StdMeshers_MaxElementArea *>(theHyp);
140                 ASSERT(_hypMaxElementArea);
141                 _maxElementArea = _hypMaxElementArea->GetMaxArea();
142                 _edgeLength = 0;
143                 isOk = true;
144                 aStatus = SMESH_Hypothesis::HYP_OK;
145         }
146
147         else if (hypName == "LengthFromEdges")
148         {
149                 _hypLengthFromEdges = static_cast<const StdMeshers_LengthFromEdges *>(theHyp);
150                 ASSERT(_hypLengthFromEdges);
151                 _edgeLength = 0;
152                 _maxElementArea = 0;
153                 isOk = true;
154                 aStatus = SMESH_Hypothesis::HYP_OK;
155         }
156         else
157           aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
158
159         if (isOk)
160         {
161                 isOk = false;
162                 if (_maxElementArea > 0)
163                 {
164 //                      _edgeLength = 2 * sqrt(_maxElementArea);        // triangles : minorant
165                         _edgeLength = 2 * sqrt(_maxElementArea/sqrt(3.0));
166                         isOk = true;
167                 }
168                 else
169                         isOk = (_hypLengthFromEdges != NULL);   // **** check mode
170                 if (!isOk)
171                   aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER;
172         }
173
174         //SCRUTE(_edgeLength);
175         //SCRUTE(_maxElementArea);
176         return isOk;
177 }
178
179 //=============================================================================
180 /*!
181  *  
182  */
183 //=============================================================================
184
185 bool StdMeshers_MEFISTO_2D::Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape)
186 {
187   MESSAGE("StdMeshers_MEFISTO_2D::Compute");
188
189   if (_hypLengthFromEdges)
190     _edgeLength = ComputeEdgeElementLength(aMesh, aShape);
191   
192   bool isOk = false;
193   //const SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
194   //SMESH_subMesh *theSubMesh = aMesh.GetSubMesh(aShape);
195
196   const TopoDS_Face & FF = TopoDS::Face(aShape);
197   bool faceIsForward = (FF.Orientation() == TopAbs_FORWARD);
198   TopoDS_Face F = TopoDS::Face(FF.Oriented(TopAbs_FORWARD));
199
200   Z nblf;                                               //nombre de lignes fermees (enveloppe en tete)
201   Z *nudslf = NULL;                     //numero du dernier sommet de chaque ligne fermee
202   R2 *uvslf = NULL;
203   Z nbpti = 0;                          //nombre points internes futurs sommets de la triangulation
204   R2 *uvpti = NULL;
205   
206   Z nbst;
207   R2 *uvst = NULL;
208   Z nbt;
209   Z *nust = NULL;
210   Z ierr = 0;
211
212   Z nutysu = 1;                         // 1: il existe un fonction areteideale_()
213   // Z  nutysu=0;              // 0: on utilise aretmx
214   R aretmx = _edgeLength;               // longueur max aretes future triangulation
215   
216   nblf = NumberOfWires(F);
217   
218   nudslf = new Z[1 + nblf];
219   nudslf[0] = 0;
220   int iw = 1;
221   int nbpnt = 0;
222
223   myTool = new StdMeshers_Helper(aMesh);
224   _quadraticMesh = myTool->IsQuadraticSubMesh(aShape);
225
226   myOuterWire = BRepTools::OuterWire(F);
227   nbpnt += NumberOfPoints(aMesh, myOuterWire);
228   if ( nbpnt < 3 ) { // ex: a circle with 2 segments
229     delete myTool; myTool = 0;
230     return false;
231   }
232   nudslf[iw++] = nbpnt;
233
234   for (TopExp_Explorer exp(F, TopAbs_WIRE); exp.More(); exp.Next()) {
235     const TopoDS_Wire & W = TopoDS::Wire(exp.Current());
236     if (!myOuterWire.IsSame(W)) {
237       nbpnt += NumberOfPoints(aMesh, W);
238       nudslf[iw++] = nbpnt;
239     }
240   }
241
242   // avoid passing same uv points for a vertex common to 2 wires
243   TopTools_IndexedDataMapOfShapeListOfShape VWMap;
244   if ( iw - 1 > 1 ) // nbofWires > 1
245     TopExp::MapShapesAndAncestors( F , TopAbs_VERTEX, TopAbs_WIRE, VWMap );
246
247   uvslf = new R2[nudslf[nblf]];
248   int m = 0;
249
250   double scalex, scaley;
251   ComputeScaleOnFace(aMesh, F, scalex, scaley);
252
253   map<int, const SMDS_MeshNode*> mefistoToDS;   // correspondence mefisto index--> points IDNodes
254   if ( !LoadPoints(aMesh, F, myOuterWire, uvslf, m,
255                    mefistoToDS, scalex, scaley, VWMap) ) {
256     delete myTool; myTool = 0;
257     return false;
258   }
259
260   for (TopExp_Explorer exp(F, TopAbs_WIRE); exp.More(); exp.Next())
261   {
262     const TopoDS_Wire & W = TopoDS::Wire(exp.Current());
263     if (!myOuterWire.IsSame(W))
264     {
265       if (! LoadPoints(aMesh, F, W, uvslf, m,
266                        mefistoToDS, scalex, scaley, VWMap )) {
267         delete myTool; myTool = 0;
268         return false;
269       }
270     }
271   }
272
273   uvst = NULL;
274   nust = NULL;
275   aptrte(nutysu, aretmx,
276          nblf, nudslf, uvslf, nbpti, uvpti, nbst, uvst, nbt, nust, ierr);
277
278   if (ierr == 0)
279   {
280     MESSAGE("... End Triangulation Generated Triangle Number " << nbt);
281     MESSAGE("                                    Node Number " << nbst);
282     StoreResult(aMesh, nbst, uvst, nbt, nust, F,
283                 faceIsForward, mefistoToDS, scalex, scaley);
284     isOk = true;
285   }
286   else
287   {
288     MESSAGE("Error in Triangulation");
289     isOk = false;
290   }
291   if (nudslf != NULL)
292     delete[]nudslf;
293   if (uvslf != NULL)
294     delete[]uvslf;
295   if (uvst != NULL)
296     delete[]uvst;
297   if (nust != NULL)
298     delete[]nust;
299   delete myTool; myTool = 0;
300
301   return isOk;
302 }
303
304 //=======================================================================
305 //function : fixOverlappedLinkUV
306 //purpose  : prevent failure due to overlapped adjacent links
307 //=======================================================================
308
309 static bool fixOverlappedLinkUV( R2& uv0, const R2& uv1, const R2& uv2 )
310 {
311   gp_XY v1( uv0.x - uv1.x, uv0.y - uv1.y );
312   gp_XY v2( uv2.x - uv1.x, uv2.y - uv1.y );
313
314   double tol2 = DBL_MIN * DBL_MIN;
315   double sqMod1 = v1.SquareModulus();
316   if ( sqMod1 <= tol2 ) return false;
317   double sqMod2 = v2.SquareModulus();
318   if ( sqMod2 <= tol2 ) return false;
319
320   double dot = v1*v2;
321
322   // check sinus >= 1.e-3
323   const double minSin = 1.e-3;
324   if ( dot > 0 && 1 - dot * dot / ( sqMod1 * sqMod2 ) < minSin * minSin ) {
325     MESSAGE(" ___ FIX UV ____" << uv0.x << " " << uv0.y);
326     v1.SetCoord( -v1.Y(), v1.X() );
327     double delta = sqrt( sqMod1 ) * minSin;
328     if ( v1.X() < 0 )
329       uv0.x -= delta;
330     else
331       uv0.x += delta;
332     if ( v1.Y() < 0 )
333       uv0.y -= delta;
334     else
335       uv0.y += delta;
336 //    MESSAGE(" -> " << uv0.x << " " << uv0.y << " ");
337 //     MESSAGE("v1( " << v1.X() << " " << v1.Y() << " ) " <<
338 //       "v2( " << v2.X() << " " << v2.Y() << " ) ");
339 //    MESSAGE("SIN: " << sqrt(1 - dot * dot / (sqMod1 * sqMod2)));
340 //     v1.SetCoord( uv0.x - uv1.x, uv0.y - uv1.y );
341 //     v2.SetCoord( uv2.x - uv1.x, uv2.y - uv1.y );
342 //     gp_XY v3( uv2.x - uv0.x, uv2.y - uv0.y );
343 //     sqMod1 = v1.SquareModulus();
344 //     sqMod2 = v2.SquareModulus();
345 //     dot = v1*v2;
346 //     double sin = sqrt(1 - dot * dot / (sqMod1 * sqMod2));
347 //     MESSAGE("NEW SIN: " << sin);
348     return true;
349   }
350   return false;
351 }
352
353 //=======================================================================
354 //function : fixCommonVertexUV
355 //purpose  : 
356 //=======================================================================
357
358 static bool fixCommonVertexUV (gp_Pnt2d &           theUV,
359                                const TopoDS_Vertex& theV,
360                                const TopoDS_Wire&   theW,
361                                const TopoDS_Wire&   theOW,
362                                const TopoDS_Face&   theF,
363                                const TopTools_IndexedDataMapOfShapeListOfShape & theVWMap,
364                                SMESH_Mesh &         theMesh,
365                                bool CreateQuadratic)
366 {
367   if( theW.IsSame( theOW ) ||
368       !theVWMap.Contains( theV )) return false;
369
370   // check if there is another wire sharing theV
371   const TopTools_ListOfShape& WList = theVWMap.FindFromKey( theV );
372   TopTools_ListIteratorOfListOfShape aWIt;
373   for ( aWIt.Initialize( WList ); aWIt.More(); aWIt.Next() )
374     if ( !theW.IsSame( aWIt.Value() ))
375       break;
376   if ( !aWIt.More() ) return false;
377
378   TopTools_ListOfShape EList;
379   list< double >       UList;
380
381   // find edges of theW sharing theV
382   // and find 2d normal to them at theV
383   gp_Vec2d N(0.,0.);
384   TopoDS_Iterator itE( theW );
385   for (  ; itE.More(); itE.Next() )
386   {
387     const TopoDS_Edge& E = TopoDS::Edge( itE.Value() );
388     TopoDS_Iterator itV( E );
389     for ( ; itV.More(); itV.Next() )
390     {
391       const TopoDS_Vertex & V = TopoDS::Vertex( itV.Value() );
392       if ( !V.IsSame( theV ))
393         continue;
394       EList.Append( E );
395       Standard_Real u = BRep_Tool::Parameter( V, E );
396       UList.push_back( u );
397       double f, l;
398       Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, theF, f, l);
399       gp_Vec2d d1;
400       gp_Pnt2d p;
401       C2d->D1( u, p, d1 );
402       gp_Vec2d n( d1.Y(), -d1.X() );
403       if ( E.Orientation() == TopAbs_REVERSED )
404         n.Reverse();
405       N += n.Normalized();
406     }
407   }
408
409   // define step size by which to move theUV
410
411   gp_Pnt2d nextUV; // uv of next node on edge, most distant of the four
412   double maxDist = -DBL_MAX;
413   TopTools_ListIteratorOfListOfShape aEIt (EList);
414   list< double >::iterator aUIt = UList.begin();
415   for ( ; aEIt.More(); aEIt.Next(), aUIt++ )
416   {
417     const TopoDS_Edge& E = TopoDS::Edge( aEIt.Value() );
418     double f, l;
419     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, theF, f, l);
420
421     double umin = DBL_MAX, umax = -DBL_MAX;
422     SMDS_NodeIteratorPtr nIt = theMesh.GetSubMesh(E)->GetSubMeshDS()->GetNodes();
423     if ( !nIt->more() ) // no nodes on edge, only on vertices
424     {
425       umin = l;
426       umax = f;
427     }
428     else {
429       while ( nIt->more() ) {
430         const SMDS_MeshNode* node = nIt->next();
431         // check if node is medium
432         if ( CreateQuadratic && StdMeshers_Helper::IsMedium( node, SMDSAbs_Edge ))
433           continue;
434         const SMDS_EdgePosition* epos =
435           static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
436         double u = epos->GetUParameter();
437         if ( u < umin )
438           umin = u;
439         if ( u > umax )
440           umax = u;
441       }
442     }
443     bool isFirstCommon = ( *aUIt == f );
444     gp_Pnt2d uv = C2d->Value( isFirstCommon ? umin : umax );
445     double dist = theUV.SquareDistance( uv );
446     if ( dist > maxDist ) {
447       maxDist = dist;
448       nextUV  = uv;
449     }
450   }
451   R2 uv0, uv1, uv2;
452   uv0.x = theUV.X();    uv0.y = theUV.Y(); 
453   uv1.x = nextUV.X();   uv1.y = nextUV.Y(); 
454   uv2.x = uv0.x;        uv2.y = uv0.y;
455   if ( fixOverlappedLinkUV( uv0, uv1, uv2 ))
456   {
457     double step = theUV.Distance( gp_Pnt2d( uv0.x, uv0.y ));
458
459     // move theUV along the normal by the step
460
461     N *= step;
462
463     MESSAGE("--fixCommonVertexUV move(" << theUV.X() << " " << theUV.Y()
464             << ") by (" << N.X() << " " << N.Y() << ")" 
465             << endl << "--- MAX DIST " << maxDist);
466
467     theUV.SetXY( theUV.XY() + N.XY() );
468
469     return true;
470   }
471   return false;
472 }
473
474 //=============================================================================
475 /*!
476  *  
477  */
478 //=============================================================================
479
480 bool StdMeshers_MEFISTO_2D::LoadPoints(SMESH_Mesh &        aMesh,
481                                        const TopoDS_Face & FF,
482                                        const TopoDS_Wire & WW,
483                                        R2 *                uvslf,
484                                        int &               m,
485                                        map<int, const SMDS_MeshNode*>&mefistoToDS,
486                                        double              scalex,
487                                        double              scaley,
488                                        const TopTools_IndexedDataMapOfShapeListOfShape& VWMap)
489 {
490 //  MESSAGE("StdMeshers_MEFISTO_2D::LoadPoints");
491
492   //SMDS_Mesh * meshDS = aMesh.GetMeshDS();
493
494   TopoDS_Face F = TopoDS::Face(FF.Oriented(TopAbs_FORWARD));
495
496   int mInit = m, mFirst, iEdge;
497   gp_XY scale( scalex, scaley );
498
499   TopoDS_Wire W = TopoDS::Wire(WW.Oriented(TopAbs_FORWARD));
500   BRepTools_WireExplorer wexp(W, F);
501   for (wexp.Init(W, F), iEdge = 0; wexp.More(); wexp.Next(), iEdge++) {
502     const TopoDS_Edge & E = wexp.Current();
503
504     // --- IDNodes of first and last Vertex
505
506     TopoDS_Vertex VFirst, VLast;
507     TopExp::Vertices(E, VFirst, VLast); // corresponds to f and l
508
509     ASSERT(!VFirst.IsNull());
510     SMDS_NodeIteratorPtr lid =
511       aMesh.GetSubMesh(VFirst)->GetSubMeshDS()->GetNodes();
512     if ( !lid->more() ) {
513       MESSAGE (" NO NODE BUILT ON VERTEX ");
514       return false;
515     }
516     const SMDS_MeshNode* idFirst = lid->next();
517
518     ASSERT(!VLast.IsNull());
519     lid = aMesh.GetSubMesh(VLast)->GetSubMeshDS()->GetNodes();
520     if ( !lid->more() ) {
521       MESSAGE (" NO NODE BUILT ON VERTEX ");
522       return false;
523     }
524     const SMDS_MeshNode* idLast = lid->next();
525
526     int nbPoints = aMesh.GetSubMesh(E)->GetSubMeshDS()->NbNodes();
527     if ( _quadraticMesh )
528       nbPoints /= 2;
529
530     double f, l;
531     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, F, f, l);
532
533     SMDS_NodeIteratorPtr ite= aMesh.GetSubMesh(E)->GetSubMeshDS()->GetNodes();
534
535     //bool isForward = (E.Orientation() == TopAbs_FORWARD);
536     map<double, const SMDS_MeshNode*> params;
537
538     while(ite->more()) {
539       const SMDS_MeshNode * node = ite->next();
540       if ( _quadraticMesh && StdMeshers_Helper::IsMedium( node, SMDSAbs_Edge ))
541         continue;
542       const SMDS_EdgePosition* epos =
543         static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
544       double param = epos->GetUParameter();
545       params[param] = node;
546     }
547
548     if ( nbPoints != params.size()) {
549       MESSAGE( "BAD NODE ON EDGE POSITIONS" );
550       return false;
551     }
552
553     mFirst = m;
554
555     // --- load 2D values into MEFISTO structure,
556     //     add IDNodes in mefistoToDS map
557     if (E.Orientation() == TopAbs_FORWARD) {
558       gp_Pnt2d p = C2d->Value(f).XY().Multiplied( scale );       // first point = Vertex Forward
559       if ( fixCommonVertexUV( p, VFirst, W, myOuterWire, F, VWMap, aMesh, _quadraticMesh ))
560         myNodesOnCommonV.push_back( idFirst );
561       uvslf[m].x = p.X();
562       uvslf[m].y = p.Y();
563       mefistoToDS[m + 1] = idFirst;
564 //       MESSAGE(" "<<m<<" "<<mefistoToDS[m+1]);
565 //       MESSAGE("__ f "<<f<<" "<<uvslf[m].x <<" "<<uvslf[m].y);
566       m++;
567       map<double, const SMDS_MeshNode*>::iterator itp = params.begin();
568       for (int i = 1; i <= nbPoints; i++) {  // nbPoints internal
569         double param = (*itp).first;
570         gp_Pnt2d p = C2d->Value(param).XY().Multiplied( scale );
571         uvslf[m].x = p.X();
572         uvslf[m].y = p.Y();
573         mefistoToDS[m + 1] = (*itp).second;
574 //         MESSAGE(" "<<m<<" "<<mefistoToDS[m+1]);
575 //         MESSAGE("__ "<<i<<" "<<param<<" "<<uvslf[m].x <<" "<<uvslf[m].y);
576         m++;
577         itp++;
578       }
579     }
580     else {
581       gp_Pnt2d p = C2d->Value(l).XY().Multiplied( scale );       // last point = Vertex Reversed
582       if ( fixCommonVertexUV( p, VLast, W, myOuterWire, F, VWMap, aMesh, _quadraticMesh ))
583         myNodesOnCommonV.push_back( idLast );
584       uvslf[m].x = p.X();
585       uvslf[m].y = p.Y();
586       mefistoToDS[m + 1] = idLast;
587 //       MESSAGE(" "<<m<<" "<<mefistoToDS[m+1]);
588 //       MESSAGE("__ l "<<l<<" "<<uvslf[m].x <<" "<<uvslf[m].y);
589       m++;
590       map<double, const SMDS_MeshNode*>::reverse_iterator itp = params.rbegin();
591       for (int i = nbPoints; i >= 1; i--)
592       {
593         double param = (*itp).first;
594         gp_Pnt2d p = C2d->Value(param).XY().Multiplied( scale );
595         uvslf[m].x = p.X();
596         uvslf[m].y = p.Y();
597         mefistoToDS[m + 1] = (*itp).second;
598 //         MESSAGE(" "<<m<<" "<<mefistoToDS[m+1]);
599 //         MESSAGE("__ "<<i<<" "<<param<<" "<<uvslf[m].x <<" "<<uvslf[m].y);
600         m++;
601         itp++;
602       }
603     }
604     /// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
605     /// !!!!!!!   HERE IS A BUG with fixOverlappedLinkUV  !!!!!!!!!!!
606     //  !!!!!!!   Correct version is in the CVS head       !!!!!!!!!!
607     /// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
608     // prevent failure on overlapped adjacent links
609 //     if ( iEdge > 0 )
610 //       fixOverlappedLinkUV (uvslf[ mFirst - 1],
611 //                            uvslf[ mFirst ],
612 //                            uvslf[ mFirst + 1 ]);
613     
614   } // for  wexp
615
616 //   fixOverlappedLinkUV (uvslf[ m - 1],
617 //                        uvslf[ mInit ],
618 //                        uvslf[ mInit + 1 ]);
619
620   return true;
621 }
622
623 //=============================================================================
624 /*!
625  *  
626  */
627 //=============================================================================
628
629 void StdMeshers_MEFISTO_2D::ComputeScaleOnFace(SMESH_Mesh & aMesh,
630         const TopoDS_Face & aFace, double &scalex, double &scaley)
631 {
632   //MESSAGE("StdMeshers_MEFISTO_2D::ComputeScaleOnFace");
633   TopoDS_Face F = TopoDS::Face(aFace.Oriented(TopAbs_FORWARD));
634   TopoDS_Wire W = BRepTools::OuterWire(F);
635
636   double xmin = 1.e300;         // min & max of face 2D parametric coord.
637   double xmax = -1.e300;
638   double ymin = 1.e300;
639   double ymax = -1.e300;
640   int nbp = 23;
641   scalex = 1;
642   scaley = 1;
643
644   TopExp_Explorer wexp(W, TopAbs_EDGE);
645   for ( ; wexp.More(); wexp.Next())
646   {
647     const TopoDS_Edge & E = TopoDS::Edge( wexp.Current() );
648     double f, l;
649     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, F, f, l);
650     if ( C2d.IsNull() ) continue;
651     double du = (l - f) / double (nbp);
652     for (int i = 0; i <= nbp; i++)
653     {
654       double param = f + double (i) * du;
655       gp_Pnt2d p = C2d->Value(param);
656       if (p.X() < xmin)
657         xmin = p.X();
658       if (p.X() > xmax)
659         xmax = p.X();
660       if (p.Y() < ymin)
661         ymin = p.Y();
662       if (p.Y() > ymax)
663         ymax = p.Y();
664       //    MESSAGE(" "<< f<<" "<<l<<" "<<param<<" "<<xmin<<" "<<xmax<<" "<<ymin<<" "<<ymax);
665     }
666   }
667   //   SCRUTE(xmin);
668   //   SCRUTE(xmax);
669   //   SCRUTE(ymin);
670   //   SCRUTE(ymax);
671   double xmoy = (xmax + xmin) / 2.;
672   double ymoy = (ymax + ymin) / 2.;
673   double xsize = xmax - xmin;
674   double ysize = ymax - ymin;
675
676   Handle(Geom_Surface) S = BRep_Tool::Surface(F);       // 3D surface
677
678   double length_x = 0;
679   double length_y = 0;
680   gp_Pnt PX0 = S->Value(xmin, ymoy);
681   gp_Pnt PY0 = S->Value(xmoy, ymin);
682   double dx = xsize / double (nbp);
683   double dy = ysize / double (nbp);
684   for (int i = 1; i <= nbp; i++)
685   {
686     double x = xmin + double (i) * dx;
687     gp_Pnt PX = S->Value(x, ymoy);
688     double y = ymin + double (i) * dy;
689     gp_Pnt PY = S->Value(xmoy, y);
690     length_x += PX.Distance(PX0);
691     length_y += PY.Distance(PY0);
692     PX0 = PX;
693     PY0 = PY;
694   }
695   scalex = length_x / xsize;
696   scaley = length_y / ysize;
697 //   SCRUTE(xsize);
698 //   SCRUTE(ysize);
699   double xyratio = xsize*scalex/(ysize*scaley);
700   const double maxratio = 1.e2;
701   //SCRUTE(xyratio);
702   if (xyratio > maxratio) {
703     SCRUTE( scaley );
704     scaley *= xyratio / maxratio;
705     SCRUTE( scaley );
706   }
707   else if (xyratio < 1./maxratio) {
708     SCRUTE( scalex );
709     scalex *= 1 / xyratio / maxratio;
710     SCRUTE( scalex );
711   }
712   ASSERT(scalex);
713   ASSERT(scaley);
714 }
715
716 //=============================================================================
717 /*!
718  *  
719  */
720 //=============================================================================
721
722 void StdMeshers_MEFISTO_2D::StoreResult(SMESH_Mesh & aMesh,
723                                         Z nbst, R2 * uvst, Z nbt, Z * nust,
724                                         const TopoDS_Face & F, bool faceIsForward,
725                                         map<int, const SMDS_MeshNode*>&mefistoToDS,
726                                         double scalex, double scaley)
727 {
728   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
729   int faceID = meshDS->ShapeToIndex( F );
730
731   Z n, m;
732   Handle(Geom_Surface) S = BRep_Tool::Surface(F);
733
734   for (n = 0; n < nbst; n++)
735   {
736     if (mefistoToDS.find(n + 1) == mefistoToDS.end())
737     {
738       double u = uvst[n][0] / scalex;
739       double v = uvst[n][1] / scaley;
740       gp_Pnt P = S->Value(u, v);
741
742       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
743       meshDS->SetNodeOnFace(node, faceID, u, v);
744
745       //MESSAGE(P.X()<<" "<<P.Y()<<" "<<P.Z());
746       mefistoToDS[n + 1] = node;
747       //MESSAGE("NEW: "<<n<<" "<<mefistoToDS[n+1]);
748     }
749   }
750
751   m = 0;
752   //int mt = 0;
753
754   //SCRUTE(faceIsForward);
755   for (n = 1; n <= nbt; n++)
756   {
757     int inode1 = nust[m++];
758     int inode2 = nust[m++];
759     int inode3 = nust[m++];
760
761     const SMDS_MeshNode *n1, *n2, *n3;
762     n1 = mefistoToDS[inode1];
763     n2 = mefistoToDS[inode2];
764     n3 = mefistoToDS[inode3];
765     //MESSAGE("-- "<<inode1<<" "<<inode2<<" "<<inode3);
766
767     // triangle points must be in trigonometric order if face is Forward
768     // else they must be put clockwise
769
770     bool triangleIsWellOriented = faceIsForward;
771
772     SMDS_MeshElement * elt;
773     if (triangleIsWellOriented)
774       //elt = meshDS->AddFace(n1, n2, n3);
775       elt = myTool->AddFace(n1, n2, n3);
776     else
777       //elt = meshDS->AddFace(n1, n3, n2);
778       elt = myTool->AddFace(n1, n3, n2);
779
780     meshDS->SetMeshElementOnShape(elt, faceID);
781     m++;
782   }
783
784   // remove bad elements build on vertices shared by wires
785
786   list<const SMDS_MeshNode*>::iterator itN = myNodesOnCommonV.begin();
787   for ( ; itN != myNodesOnCommonV.end(); itN++ )
788   {
789     const SMDS_MeshNode* node = *itN;
790     SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
791     while ( invElemIt->more() )
792     {
793       const SMDS_MeshElement* elem = invElemIt->next();
794       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
795       int nbSame = 0;
796       while ( itN->more() )
797         if ( itN->next() == node)
798           nbSame++;
799       if (nbSame > 1) {
800         MESSAGE( "RM bad element " << elem->GetID());
801         meshDS->RemoveElement( elem );
802       }
803     }
804   }
805
806 }
807
808 //=============================================================================
809 /*!
810  *  
811  */
812 //=============================================================================
813
814 double StdMeshers_MEFISTO_2D::ComputeEdgeElementLength(SMESH_Mesh & aMesh,
815         const TopoDS_Shape & aShape)
816 {
817         //MESSAGE("StdMeshers_MEFISTO_2D::ComputeEdgeElementLength");
818         // **** a mettre dans SMESH_2D_Algo ?
819
820         //const TopoDS_Face & FF = TopoDS::Face(aShape);
821         //bool faceIsForward = (FF.Orientation() == TopAbs_FORWARD);
822         //TopoDS_Face F = TopoDS::Face(FF.Oriented(TopAbs_FORWARD));
823
824         double meanElementLength = 100;
825         double wireLength = 0;
826         int wireElementsNumber = 0;
827                 for (TopExp_Explorer expe(aShape, TopAbs_EDGE); expe.More(); expe.Next())
828                 {
829                         const TopoDS_Edge & E = TopoDS::Edge(expe.Current());
830                         int nb = aMesh.GetSubMesh(E)->GetSubMeshDS()->NbNodes();
831                         double length = EdgeLength(E);
832                         wireLength += length;
833                         wireElementsNumber += nb;
834                 }
835         if (wireElementsNumber)
836                 meanElementLength = wireLength / wireElementsNumber;
837         //SCRUTE(meanElementLength);
838         return meanElementLength;
839 }
840
841 //=============================================================================
842 /*!
843  *  
844  */
845 //=============================================================================
846
847 ostream & StdMeshers_MEFISTO_2D::SaveTo(ostream & save)
848 {
849   return save;
850 }
851
852 //=============================================================================
853 /*!
854  *  
855  */
856 //=============================================================================
857
858 istream & StdMeshers_MEFISTO_2D::LoadFrom(istream & load)
859 {
860   return load;
861 }
862
863 //=============================================================================
864 /*!
865  *  
866  */
867 //=============================================================================
868
869 ostream & operator <<(ostream & save, StdMeshers_MEFISTO_2D & hyp)
870 {
871   return hyp.SaveTo( save );
872 }
873
874 //=============================================================================
875 /*!
876  *  
877  */
878 //=============================================================================
879
880 istream & operator >>(istream & load, StdMeshers_MEFISTO_2D & hyp)
881 {
882   return hyp.LoadFrom( load );
883 }