Salome HOME
Fix for problem: SIGSEGV appears if to select group after opening "Edit Group" dialog...
[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 = TopAbs_FACE;
80         _shapeType = (1 << TopAbs_FACE);
81         _compatibleHypothesis.push_back("MaxElementArea");
82         _compatibleHypothesis.push_back("LengthFromEdges");
83
84         _edgeLength = 0;
85         _maxElementArea = 0;
86         _hypMaxElementArea = NULL;
87         _hypLengthFromEdges = NULL;
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         myOuterWire = BRepTools::OuterWire(F);
224         nbpnt += NumberOfPoints(aMesh, myOuterWire);
225         if ( nbpnt < 3 ) // ex: a circle with 2 segments
226           return false;
227         nudslf[iw++] = nbpnt;
228
229         for (TopExp_Explorer exp(F, TopAbs_WIRE); exp.More(); exp.Next())
230         {
231                 const TopoDS_Wire & W = TopoDS::Wire(exp.Current());
232                 if (!myOuterWire.IsSame(W))
233                 {
234                         nbpnt += NumberOfPoints(aMesh, W);
235                         nudslf[iw++] = nbpnt;
236                 }
237         }
238
239         // avoid passing same uv points for a vertex common to 2 wires
240         TopTools_IndexedDataMapOfShapeListOfShape VWMap;
241         if ( iw - 1 > 1 ) // nbofWires > 1
242           TopExp::MapShapesAndAncestors( F , TopAbs_VERTEX, TopAbs_WIRE, VWMap );
243
244         uvslf = new R2[nudslf[nblf]];
245         int m = 0;
246
247         double scalex, scaley;
248         ComputeScaleOnFace(aMesh, F, scalex, scaley);
249
250         map<int, const SMDS_MeshNode*> mefistoToDS;     // correspondence mefisto index--> points IDNodes
251         if ( !LoadPoints(aMesh, F, myOuterWire, uvslf, m,
252                          mefistoToDS, scalex, scaley, VWMap))
253           return false;
254
255         for (TopExp_Explorer exp(F, TopAbs_WIRE); exp.More(); exp.Next())
256         {
257                 const TopoDS_Wire & W = TopoDS::Wire(exp.Current());
258                 if (!myOuterWire.IsSame(W))
259                 {
260                         if (! LoadPoints(aMesh, F, W, uvslf, m,
261                                          mefistoToDS, scalex, scaley, VWMap ))
262                           return false;
263                 }
264         }
265
266         uvst = NULL;
267         nust = NULL;
268         aptrte(nutysu, aretmx,
269                 nblf, nudslf, uvslf, nbpti, uvpti, nbst, uvst, nbt, nust, ierr);
270
271         if (ierr == 0)
272           {
273             MESSAGE("... End Triangulation Generated Triangle Number " << nbt);
274             MESSAGE("                                    Node Number " << nbst);
275             StoreResult(aMesh, nbst, uvst, nbt, nust, F,
276                         faceIsForward, mefistoToDS, scalex, scaley);
277             isOk = true;
278           }
279         else
280         {
281                 MESSAGE("Error in Triangulation");
282                 isOk = false;
283         }
284         if (nudslf != NULL)
285                 delete[]nudslf;
286         if (uvslf != NULL)
287                 delete[]uvslf;
288         if (uvst != NULL)
289                 delete[]uvst;
290         if (nust != NULL)
291                 delete[]nust;
292         return isOk;
293 }
294
295 //=======================================================================
296 //function : fixOverlappedLinkUV
297 //purpose  : prevent failure due to overlapped adjacent links
298 //=======================================================================
299
300 static bool fixOverlappedLinkUV( R2& uv0, const R2& uv1, const R2& uv2 )
301 {
302   gp_XY v1( uv0.x - uv1.x, uv0.y - uv1.y );
303   gp_XY v2( uv2.x - uv1.x, uv2.y - uv1.y );
304
305   double tol2 = DBL_MIN * DBL_MIN;
306   double sqMod1 = v1.SquareModulus();
307   if ( sqMod1 <= tol2 ) return false;
308   double sqMod2 = v2.SquareModulus();
309   if ( sqMod2 <= tol2 ) return false;
310
311   double dot = v1*v2;
312
313   // check sinus >= 1.e-3
314   const double minSin = 1.e-3;
315   if ( dot > 0 && 1 - dot * dot / ( sqMod1 * sqMod2 ) < minSin * minSin ) {
316     MESSAGE(" ___ FIX UV ____" << uv0.x << " " << uv0.y);
317     v1.SetCoord( -v1.Y(), v1.X() );
318     double delta = sqrt( sqMod1 ) * minSin;
319     if ( v1.X() < 0 )
320       uv0.x -= delta;
321     else
322       uv0.x += delta;
323     if ( v1.Y() < 0 )
324       uv0.y -= delta;
325     else
326       uv0.y += delta;
327 //    MESSAGE(" -> " << uv0.x << " " << uv0.y << " ");
328 //     MESSAGE("v1( " << v1.X() << " " << v1.Y() << " ) " <<
329 //       "v2( " << v2.X() << " " << v2.Y() << " ) ");
330 //    MESSAGE("SIN: " << sqrt(1 - dot * dot / (sqMod1 * sqMod2)));
331 //     v1.SetCoord( uv0.x - uv1.x, uv0.y - uv1.y );
332 //     v2.SetCoord( uv2.x - uv1.x, uv2.y - uv1.y );
333 //     gp_XY v3( uv2.x - uv0.x, uv2.y - uv0.y );
334 //     sqMod1 = v1.SquareModulus();
335 //     sqMod2 = v2.SquareModulus();
336 //     dot = v1*v2;
337 //     double sin = sqrt(1 - dot * dot / (sqMod1 * sqMod2));
338 //     MESSAGE("NEW SIN: " << sin);
339     return true;
340   }
341   return false;
342 }
343
344 //=======================================================================
345 //function : fixCommonVertexUV
346 //purpose  : 
347 //=======================================================================
348
349 static bool fixCommonVertexUV (gp_Pnt2d &           theUV,
350                                const TopoDS_Vertex& theV,
351                                const TopoDS_Wire&   theW,
352                                const TopoDS_Wire&   theOW,
353                                const TopoDS_Face&   theF,
354                                const TopTools_IndexedDataMapOfShapeListOfShape & theVWMap,
355                                SMESH_Mesh &         theMesh)
356 {
357   if( theW.IsSame( theOW ) ||
358       !theVWMap.Contains( theV )) return false;
359
360   // check if there is another wire sharing theV
361   const TopTools_ListOfShape& WList = theVWMap.FindFromKey( theV );
362   TopTools_ListIteratorOfListOfShape aWIt;
363   for ( aWIt.Initialize( WList ); aWIt.More(); aWIt.Next() )
364     if ( !theW.IsSame( aWIt.Value() ))
365       break;
366   if ( !aWIt.More() ) return false;
367
368   TopTools_ListOfShape EList;
369   list< double >       UList;
370
371   // find edges of theW sharing theV
372   // and find 2d normal to them at theV
373   gp_Vec2d N(0.,0.);
374   TopoDS_Iterator itE( theW );
375   for (  ; itE.More(); itE.Next() )
376   {
377     const TopoDS_Edge& E = TopoDS::Edge( itE.Value() );
378     TopoDS_Iterator itV( E );
379     for ( ; itV.More(); itV.Next() )
380     {
381       const TopoDS_Vertex & V = TopoDS::Vertex( itV.Value() );
382       if ( !V.IsSame( theV ))
383         continue;
384       EList.Append( E );
385       Standard_Real u = BRep_Tool::Parameter( V, E );
386       UList.push_back( u );
387       double f, l;
388       Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, theF, f, l);
389       gp_Vec2d d1;
390       gp_Pnt2d p;
391       C2d->D1( u, p, d1 );
392       gp_Vec2d n( d1.Y(), -d1.X() );
393       if ( E.Orientation() == TopAbs_REVERSED )
394         n.Reverse();
395       N += n.Normalized();
396     }
397   }
398
399   // define step size by which to move theUV
400
401   gp_Pnt2d nextUV; // uv of next node on edge, most distant of the four
402   double maxDist = -DBL_MAX;
403   TopTools_ListIteratorOfListOfShape aEIt (EList);
404   list< double >::iterator aUIt = UList.begin();
405   for ( ; aEIt.More(); aEIt.Next(), aUIt++ )
406   {
407     const TopoDS_Edge& E = TopoDS::Edge( aEIt.Value() );
408     double f, l;
409     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, theF, f, l);
410
411     double umin = DBL_MAX, umax = -DBL_MAX;
412     SMDS_NodeIteratorPtr nIt = theMesh.GetSubMesh(E)->GetSubMeshDS()->GetNodes();
413     if ( !nIt->more() ) // no nodes on edge, only on vertices
414     {
415       umin = l;
416       umax = f;
417     }
418     else
419     {
420       while ( nIt->more() ) {
421         const SMDS_MeshNode* node = nIt->next();
422         const SMDS_EdgePosition* epos =
423           static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
424         double u = epos->GetUParameter();
425         if ( u < umin )
426           umin = u;
427         if ( u > umax )
428           umax = u;
429       }
430     }
431     bool isFirstCommon = ( *aUIt == f );
432     gp_Pnt2d uv = C2d->Value( isFirstCommon ? umin : umax );
433     double dist = theUV.SquareDistance( uv );
434     if ( dist > maxDist ) {
435       maxDist = dist;
436       nextUV  = uv;
437     }
438   }
439   R2 uv0, uv1, uv2;
440   uv0.x = theUV.X();    uv0.y = theUV.Y(); 
441   uv1.x = nextUV.X();   uv1.y = nextUV.Y(); 
442   uv2.x = uv0.x;        uv2.y = uv0.y;
443   if ( fixOverlappedLinkUV( uv0, uv1, uv2 ))
444   {
445     double step = theUV.Distance( gp_Pnt2d( uv0.x, uv0.y ));
446
447     // move theUV along the normal by the step
448
449     N *= step;
450
451     MESSAGE("--fixCommonVertexUV move(" << theUV.X() << " " << theUV.Y()
452             << ") by (" << N.X() << " " << N.Y() << ")" 
453             << endl << "--- MAX DIST " << maxDist);
454
455     theUV.SetXY( theUV.XY() + N.XY() );
456
457     return true;
458   }
459   return false;
460 }
461
462 //=============================================================================
463 /*!
464  *  
465  */
466 //=============================================================================
467
468 bool StdMeshers_MEFISTO_2D::LoadPoints(SMESH_Mesh &        aMesh,
469                                        const TopoDS_Face & FF,
470                                        const TopoDS_Wire & WW,
471                                        R2 *                uvslf,
472                                        int &               m,
473                                        map<int, const SMDS_MeshNode*>&mefistoToDS,
474                                        double              scalex,
475                                        double              scaley,
476                                        const TopTools_IndexedDataMapOfShapeListOfShape& VWMap)
477 {
478 //  MESSAGE("StdMeshers_MEFISTO_2D::LoadPoints");
479
480   SMDS_Mesh * meshDS = aMesh.GetMeshDS();
481
482   TopoDS_Face F = TopoDS::Face(FF.Oriented(TopAbs_FORWARD));
483
484   int mInit = m, mFirst, iEdge;
485   gp_XY scale( scalex, scaley );
486
487   TopoDS_Wire W = TopoDS::Wire(WW.Oriented(TopAbs_FORWARD));
488   BRepTools_WireExplorer wexp(W, F);
489   for (wexp.Init(W, F), iEdge = 0; wexp.More(); wexp.Next(), iEdge++)
490   {
491     const TopoDS_Edge & E = wexp.Current();
492
493     // --- IDNodes of first and last Vertex
494
495     TopoDS_Vertex VFirst, VLast;
496     TopExp::Vertices(E, VFirst, VLast); // corresponds to f and l
497
498     ASSERT(!VFirst.IsNull());
499     SMDS_NodeIteratorPtr lid=
500       aMesh.GetSubMesh(VFirst)->GetSubMeshDS()->GetNodes();
501     if ( !lid->more() ) {
502       MESSAGE (" NO NODE BUILT ON VERTEX ");
503       return false;
504     }
505     const SMDS_MeshNode* idFirst = lid->next();
506
507     ASSERT(!VLast.IsNull());
508     lid=aMesh.GetSubMesh(VLast)->GetSubMeshDS()->GetNodes();
509     if ( !lid->more() ) {
510       MESSAGE (" NO NODE BUILT ON VERTEX ");
511       return false;
512     }
513     const SMDS_MeshNode* idLast = lid->next();
514
515     // --- edge internal IDNodes (relies on good order storage, not checked)
516
517     int nbPoints = aMesh.GetSubMesh(E)->GetSubMeshDS()->NbNodes();
518
519     double f, l;
520     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, F, f, l);
521
522     SMDS_NodeIteratorPtr ite= aMesh.GetSubMesh(E)->GetSubMeshDS()->GetNodes();
523
524     bool isForward = (E.Orientation() == TopAbs_FORWARD);
525     map<double, const SMDS_MeshNode*> params;
526
527     while(ite->more())
528     {
529       const SMDS_MeshNode * node = ite->next();
530       const SMDS_EdgePosition* epos =
531         static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
532       double param = epos->GetUParameter();
533       params[param] = node;
534     }
535     if ( nbPoints != params.size())
536     {
537       MESSAGE( "BAD NODE ON EDGE POSITIONS" );
538       return false;
539     }
540
541     mFirst = m;
542
543     // --- load 2D values into MEFISTO structure,
544     //     add IDNodes in mefistoToDS map
545     if (E.Orientation() == TopAbs_FORWARD)
546     {
547       gp_Pnt2d p = C2d->Value(f).XY().Multiplied( scale );       // first point = Vertex Forward
548       if ( fixCommonVertexUV( p, VFirst, W, myOuterWire, F, VWMap, aMesh ))
549         myNodesOnCommonV.push_back( idFirst );
550       uvslf[m].x = p.X();
551       uvslf[m].y = p.Y();
552       mefistoToDS[m + 1] = idFirst;
553       //MESSAGE(" "<<m<<" "<<mefistoToDS[m+1]);
554       //MESSAGE("__ f "<<f<<" "<<uvslf[m].x <<" "<<uvslf[m].y);
555       m++;
556       map<double, const SMDS_MeshNode*>::iterator itp = params.begin();
557       for (int i = 1; i <= nbPoints; i++)       // nbPoints internal
558       {
559         double param = (*itp).first;
560         gp_Pnt2d p = C2d->Value(param).XY().Multiplied( scale );
561         uvslf[m].x = p.X();
562         uvslf[m].y = p.Y();
563         mefistoToDS[m + 1] = (*itp).second;
564         //MESSAGE(" "<<m<<" "<<mefistoToDS[m+1]);
565         //MESSAGE("__ "<<i<<" "<<param<<" "<<uvslf[m].x <<" "<<uvslf[m].y);
566         m++;
567         itp++;
568       }
569     }
570     else
571     {
572       gp_Pnt2d p = C2d->Value(l).XY().Multiplied( scale );       // last point = Vertex Reversed
573       if ( fixCommonVertexUV( p, VLast, W, myOuterWire, F, VWMap, aMesh ))
574         myNodesOnCommonV.push_back( idLast );
575       uvslf[m].x = p.X();
576       uvslf[m].y = p.Y();
577       mefistoToDS[m + 1] = idLast;
578       //MESSAGE(" "<<m<<" "<<mefistoToDS[m+1]);
579       //MESSAGE("__ l "<<l<<" "<<uvslf[m].x <<" "<<uvslf[m].y);
580       m++;
581       map<double, const SMDS_MeshNode*>::reverse_iterator itp = params.rbegin();
582       for (int i = nbPoints; i >= 1; i--)
583       {
584         double param = (*itp).first;
585         gp_Pnt2d p = C2d->Value(param).XY().Multiplied( scale );
586         uvslf[m].x = p.X();
587         uvslf[m].y = p.Y();
588         mefistoToDS[m + 1] = (*itp).second;
589         //MESSAGE(" "<<m<<" "<<mefistoToDS[m+1]);
590         //MESSAGE("__ "<<i<<" "<<param<<" "<<uvslf[m].x <<" "<<uvslf[m].y);
591         m++;
592         itp++;
593       }
594     }
595     // prevent failure on overlapped adjacent links
596     if ( iEdge > 0 )
597       fixOverlappedLinkUV (uvslf[ mFirst - 1],
598                            uvslf[ mFirst ],
599                            uvslf[ mFirst + 1 ]);
600     
601   } // for  wexp
602
603   fixOverlappedLinkUV (uvslf[ m - 1],
604                        uvslf[ mInit ],
605                        uvslf[ mInit + 1 ]);
606
607   return true;
608 }
609
610 //=============================================================================
611 /*!
612  *  
613  */
614 //=============================================================================
615
616 void StdMeshers_MEFISTO_2D::ComputeScaleOnFace(SMESH_Mesh & aMesh,
617         const TopoDS_Face & aFace, double &scalex, double &scaley)
618 {
619   //MESSAGE("StdMeshers_MEFISTO_2D::ComputeScaleOnFace");
620   TopoDS_Face F = TopoDS::Face(aFace.Oriented(TopAbs_FORWARD));
621   TopoDS_Wire W = BRepTools::OuterWire(F);
622
623   double xmin = 1.e300;         // min & max of face 2D parametric coord.
624   double xmax = -1.e300;
625   double ymin = 1.e300;
626   double ymax = -1.e300;
627   int nbp = 23;
628   scalex = 1;
629   scaley = 1;
630
631   TopExp_Explorer wexp(W, TopAbs_EDGE);
632   for ( ; wexp.More(); wexp.Next())
633   {
634     const TopoDS_Edge & E = TopoDS::Edge( wexp.Current() );
635     double f, l;
636     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, F, f, l);
637     if ( C2d.IsNull() ) continue;
638     double du = (l - f) / double (nbp);
639     for (int i = 0; i <= nbp; i++)
640     {
641       double param = f + double (i) * du;
642       gp_Pnt2d p = C2d->Value(param);
643       if (p.X() < xmin)
644         xmin = p.X();
645       if (p.X() > xmax)
646         xmax = p.X();
647       if (p.Y() < ymin)
648         ymin = p.Y();
649       if (p.Y() > ymax)
650         ymax = p.Y();
651       //    MESSAGE(" "<< f<<" "<<l<<" "<<param<<" "<<xmin<<" "<<xmax<<" "<<ymin<<" "<<ymax);
652     }
653   }
654   //   SCRUTE(xmin);
655   //   SCRUTE(xmax);
656   //   SCRUTE(ymin);
657   //   SCRUTE(ymax);
658   double xmoy = (xmax + xmin) / 2.;
659   double ymoy = (ymax + ymin) / 2.;
660   double xsize = xmax - xmin;
661   double ysize = ymax - ymin;
662
663   Handle(Geom_Surface) S = BRep_Tool::Surface(F);       // 3D surface
664
665   double length_x = 0;
666   double length_y = 0;
667   gp_Pnt PX0 = S->Value(xmin, ymoy);
668   gp_Pnt PY0 = S->Value(xmoy, ymin);
669   double dx = xsize / double (nbp);
670   double dy = ysize / double (nbp);
671   for (int i = 1; i <= nbp; i++)
672   {
673     double x = xmin + double (i) * dx;
674     gp_Pnt PX = S->Value(x, ymoy);
675     double y = ymin + double (i) * dy;
676     gp_Pnt PY = S->Value(xmoy, y);
677     length_x += PX.Distance(PX0);
678     length_y += PY.Distance(PY0);
679     PX0 = PX;
680     PY0 = PY;
681   }
682   scalex = length_x / xsize;
683   scaley = length_y / ysize;
684 //   SCRUTE(xsize);
685 //   SCRUTE(ysize);
686   double xyratio = xsize*scalex/(ysize*scaley);
687   const double maxratio = 1.e2;
688   //SCRUTE(xyratio);
689   if (xyratio > maxratio) {
690     SCRUTE( scaley );
691     scaley *= xyratio / maxratio;
692     SCRUTE( scaley );
693   }
694   else if (xyratio < 1./maxratio) {
695     SCRUTE( scalex );
696     scalex *= 1 / xyratio / maxratio;
697     SCRUTE( scalex );
698   }
699   ASSERT(scalex);
700   ASSERT(scaley);
701 }
702
703 //=============================================================================
704 /*!
705  *  
706  */
707 //=============================================================================
708
709 void StdMeshers_MEFISTO_2D::StoreResult(SMESH_Mesh & aMesh,
710                                         Z nbst, R2 * uvst, Z nbt, Z * nust,
711                                         const TopoDS_Face & F, bool faceIsForward,
712                                         map<int, const SMDS_MeshNode*>&mefistoToDS,
713                                         double scalex, double scaley)
714 {
715   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
716
717   Z n, m;
718   Handle(Geom_Surface) S = BRep_Tool::Surface(F);
719
720   for (n = 0; n < nbst; n++)
721   {
722     if (mefistoToDS.find(n + 1) == mefistoToDS.end())
723     {
724       double u = uvst[n][0] / scalex;
725       double v = uvst[n][1] / scaley;
726       gp_Pnt P = S->Value(u, v);
727
728       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
729       meshDS->SetNodeOnFace(node, F);
730
731       //MESSAGE(P.X()<<" "<<P.Y()<<" "<<P.Z());
732       mefistoToDS[n + 1] = node;
733       //MESSAGE("NEW: "<<n<<" "<<mefistoToDS[n+1]);
734       SMDS_FacePosition* fpos =
735         static_cast<SMDS_FacePosition*>(node->GetPosition().get());
736       fpos->SetUParameter(u);
737       fpos->SetVParameter(v);
738     }
739   }
740
741   m = 0;
742   int mt = 0;
743
744   //SCRUTE(faceIsForward);
745   for (n = 1; n <= nbt; n++)
746   {
747     int inode1 = nust[m++];
748     int inode2 = nust[m++];
749     int inode3 = nust[m++];
750
751     const SMDS_MeshNode *n1, *n2, *n3;
752     n1 = mefistoToDS[inode1];
753     n2 = mefistoToDS[inode2];
754     n3 = mefistoToDS[inode3];
755     //MESSAGE("-- "<<inode1<<" "<<inode2<<" "<<inode3);
756
757     // triangle points must be in trigonometric order if face is Forward
758     // else they must be put clockwise
759
760     bool triangleIsWellOriented = faceIsForward;
761
762     SMDS_MeshElement * elt;
763     if (triangleIsWellOriented)
764       elt = meshDS->AddFace(n1, n2, n3);
765     else
766       elt = meshDS->AddFace(n1, n3, n2);
767
768     meshDS->SetMeshElementOnShape(elt, F);
769     m++;
770   }
771
772   // remove bad elements build on vertices shared by wires
773
774   list<const SMDS_MeshNode*>::iterator itN = myNodesOnCommonV.begin();
775   for ( ; itN != myNodesOnCommonV.end(); itN++ )
776   {
777     const SMDS_MeshNode* node = *itN;
778     SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
779     while ( invElemIt->more() )
780     {
781       const SMDS_MeshElement* elem = invElemIt->next();
782       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
783       int nbSame = 0;
784       while ( itN->more() )
785         if ( itN->next() == node)
786           nbSame++;
787       if (nbSame > 1) {
788         MESSAGE( "RM bad element " << elem->GetID());
789         meshDS->RemoveElement( elem );
790       }
791     }
792   }
793
794 }
795
796 //=============================================================================
797 /*!
798  *  
799  */
800 //=============================================================================
801
802 double StdMeshers_MEFISTO_2D::ComputeEdgeElementLength(SMESH_Mesh & aMesh,
803         const TopoDS_Shape & aShape)
804 {
805         //MESSAGE("StdMeshers_MEFISTO_2D::ComputeEdgeElementLength");
806         // **** a mettre dans SMESH_2D_Algo ?
807
808         const TopoDS_Face & FF = TopoDS::Face(aShape);
809         bool faceIsForward = (FF.Orientation() == TopAbs_FORWARD);
810         TopoDS_Face F = TopoDS::Face(FF.Oriented(TopAbs_FORWARD));
811
812         double meanElementLength = 100;
813         double wireLength = 0;
814         int wireElementsNumber = 0;
815         for (TopExp_Explorer exp(F, TopAbs_WIRE); exp.More(); exp.Next())
816         {
817                 const TopoDS_Wire & W = TopoDS::Wire(exp.Current());
818                 for (TopExp_Explorer expe(W, TopAbs_EDGE); expe.More(); expe.Next())
819                 {
820                         const TopoDS_Edge & E = TopoDS::Edge(expe.Current());
821                         int nb = aMesh.GetSubMesh(E)->GetSubMeshDS()->NbNodes();
822                         double length = EdgeLength(E);
823                         wireLength += length;
824                         wireElementsNumber += nb;
825                 }
826         }
827         if (wireElementsNumber)
828                 meanElementLength = wireLength / wireElementsNumber;
829         //SCRUTE(meanElementLength);
830         return meanElementLength;
831 }
832
833 //=============================================================================
834 /*!
835  *  
836  */
837 //=============================================================================
838
839 ostream & StdMeshers_MEFISTO_2D::SaveTo(ostream & save)
840 {
841   return save;
842 }
843
844 //=============================================================================
845 /*!
846  *  
847  */
848 //=============================================================================
849
850 istream & StdMeshers_MEFISTO_2D::LoadFrom(istream & load)
851 {
852   return load;
853 }
854
855 //=============================================================================
856 /*!
857  *  
858  */
859 //=============================================================================
860
861 ostream & operator <<(ostream & save, StdMeshers_MEFISTO_2D & hyp)
862 {
863   return hyp.SaveTo( save );
864 }
865
866 //=============================================================================
867 /*!
868  *  
869  */
870 //=============================================================================
871
872 istream & operator >>(istream & load, StdMeshers_MEFISTO_2D & hyp)
873 {
874   return hyp.LoadFrom( load );
875 }