Salome HOME
Merge from OCC_development_generic_2006
[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 // #ifdef _DEBUG_
328 //     MESSAGE(" -> " << uv0.x << " " << uv0.y << " ");
329 //     MESSAGE("v1( " << v1.X() << " " << v1.Y() << " ) " <<
330 //       "v2( " << v2.X() << " " << v2.Y() << " ) ");
331 //    MESSAGE("SIN: " << sqrt(1 - dot * dot / (sqMod1 * sqMod2)));
332 //     v1.SetCoord( uv0.x - uv1.x, uv0.y - uv1.y );
333 //     v2.SetCoord( uv2.x - uv1.x, uv2.y - uv1.y );
334 //     gp_XY v3( uv2.x - uv0.x, uv2.y - uv0.y );
335 //     sqMod1 = v1.SquareModulus();
336 //     sqMod2 = v2.SquareModulus();
337 //     dot = v1*v2;
338 //     double sin = sqrt(1 - dot * dot / (sqMod1 * sqMod2));
339 //     MESSAGE("NEW SIN: " << sin);
340 // #endif
341     return true;
342   }
343   return false;
344 }
345
346 //=======================================================================
347 //function : fixCommonVertexUV
348 //purpose  : 
349 //=======================================================================
350
351 static bool fixCommonVertexUV (gp_Pnt2d &           theUV,
352                                const TopoDS_Vertex& theV,
353                                const TopoDS_Wire&   theW,
354                                const TopoDS_Wire&   theOW,
355                                const TopoDS_Face&   theF,
356                                const TopTools_IndexedDataMapOfShapeListOfShape & theVWMap,
357                                SMESH_Mesh &         theMesh)
358 {
359   if( theW.IsSame( theOW ) ||
360       !theVWMap.Contains( theV )) return false;
361
362   // check if there is another wire sharing theV
363   const TopTools_ListOfShape& WList = theVWMap.FindFromKey( theV );
364   TopTools_ListIteratorOfListOfShape aWIt;
365   for ( aWIt.Initialize( WList ); aWIt.More(); aWIt.Next() )
366     if ( !theW.IsSame( aWIt.Value() ))
367       break;
368   if ( !aWIt.More() ) return false;
369
370   TopTools_ListOfShape EList;
371   list< double >       UList;
372
373   // find edges of theW sharing theV
374   // and find 2d normal to them at theV
375   gp_Vec2d N(0.,0.);
376   TopoDS_Iterator itE( theW );
377   for (  ; itE.More(); itE.Next() )
378   {
379     const TopoDS_Edge& E = TopoDS::Edge( itE.Value() );
380     TopoDS_Iterator itV( E );
381     for ( ; itV.More(); itV.Next() )
382     {
383       const TopoDS_Vertex & V = TopoDS::Vertex( itV.Value() );
384       if ( !V.IsSame( theV ))
385         continue;
386       EList.Append( E );
387       Standard_Real u = BRep_Tool::Parameter( V, E );
388       UList.push_back( u );
389       double f, l;
390       Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, theF, f, l);
391       gp_Vec2d d1;
392       gp_Pnt2d p;
393       C2d->D1( u, p, d1 );
394       gp_Vec2d n( d1.Y(), -d1.X() );
395       if ( E.Orientation() == TopAbs_REVERSED )
396         n.Reverse();
397       N += n.Normalized();
398     }
399   }
400
401   // define step size by which to move theUV
402
403   gp_Pnt2d nextUV; // uv of next node on edge, most distant of the four
404   double maxDist = -DBL_MAX;
405   TopTools_ListIteratorOfListOfShape aEIt (EList);
406   list< double >::iterator aUIt = UList.begin();
407   for ( ; aEIt.More(); aEIt.Next(), aUIt++ )
408   {
409     const TopoDS_Edge& E = TopoDS::Edge( aEIt.Value() );
410     double f, l;
411     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, theF, f, l);
412
413     double umin = DBL_MAX, umax = -DBL_MAX;
414     SMDS_NodeIteratorPtr nIt = theMesh.GetSubMesh(E)->GetSubMeshDS()->GetNodes();
415     if ( !nIt->more() ) // no nodes on edge, only on vertices
416     {
417       umin = l;
418       umax = f;
419     }
420     else
421     {
422       while ( nIt->more() ) {
423         const SMDS_MeshNode* node = nIt->next();
424         const SMDS_EdgePosition* epos =
425           static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
426         double u = epos->GetUParameter();
427         if ( u < umin )
428           umin = u;
429         if ( u > umax )
430           umax = u;
431       }
432     }
433     bool isFirstCommon = ( *aUIt == f );
434     gp_Pnt2d uv = C2d->Value( isFirstCommon ? umin : umax );
435     double dist = theUV.SquareDistance( uv );
436     if ( dist > maxDist ) {
437       maxDist = dist;
438       nextUV  = uv;
439     }
440   }
441   R2 uv0, uv1, uv2;
442   uv0.x = theUV.X();    uv0.y = theUV.Y(); 
443   uv1.x = nextUV.X();   uv1.y = nextUV.Y(); 
444   uv2.x = uv0.x;        uv2.y = uv0.y;
445   if ( fixOverlappedLinkUV( uv0, uv1, uv2 ))
446   {
447     double step = theUV.Distance( gp_Pnt2d( uv0.x, uv0.y ));
448
449     // move theUV along the normal by the step
450
451     N *= step;
452
453     MESSAGE("--fixCommonVertexUV move(" << theUV.X() << " " << theUV.Y()
454             << ") by (" << N.X() << " " << N.Y() << ")" 
455             << endl << "--- MAX DIST " << maxDist);
456
457     theUV.SetXY( theUV.XY() + N.XY() );
458
459     return true;
460   }
461   return false;
462 }
463
464 //=============================================================================
465 /*!
466  *  
467  */
468 //=============================================================================
469
470 bool StdMeshers_MEFISTO_2D::LoadPoints(SMESH_Mesh &        aMesh,
471                                        const TopoDS_Face & FF,
472                                        const TopoDS_Wire & WW,
473                                        R2 *                uvslf,
474                                        int &               m,
475                                        map<int, const SMDS_MeshNode*>&mefistoToDS,
476                                        double              scalex,
477                                        double              scaley,
478                                        const TopTools_IndexedDataMapOfShapeListOfShape& VWMap)
479 {
480   //  MESSAGE("StdMeshers_MEFISTO_2D::LoadPoints");
481
482   TopoDS_Face F = TopoDS::Face(FF.Oriented(TopAbs_FORWARD));
483
484   list< int > mOnVertex;
485
486   gp_XY scale( scalex, scaley );
487
488   TopoDS_Wire W = TopoDS::Wire(WW.Oriented(TopAbs_FORWARD));
489   BRepTools_WireExplorer wexp(W, F);
490   for ( wexp.Init(W, F); wexp.More(); wexp.Next() )
491   {
492     const TopoDS_Edge & E = wexp.Current();
493     bool isForward = (E.Orientation() == TopAbs_FORWARD);
494
495     // --- IDNodes of first and last Vertex
496
497     TopoDS_Vertex VFirst, VLast, V;
498     TopExp::Vertices(E, VFirst, VLast); // corresponds to f and l
499     V = isForward ? VFirst : VLast;
500
501     ASSERT(!V.IsNull());
502     SMDS_NodeIteratorPtr lid= aMesh.GetSubMesh(V)->GetSubMeshDS()->GetNodes();
503     if ( !lid->more() ) {
504       MESSAGE (" NO NODE BUILT ON VERTEX ");
505       return false;
506     }
507     const SMDS_MeshNode* idFirst = lid->next();
508
509     // --- edge internal IDNodes (relies on good order storage, not checked)
510
511     map<double, const SMDS_MeshNode*> params;
512     const SMDS_MeshNode * node;
513
514     SMDS_NodeIteratorPtr nodeIt= aMesh.GetSubMesh(E)->GetSubMeshDS()->GetNodes();
515     while ( nodeIt->more() )
516     {
517       node = nodeIt->next();
518       const SMDS_EdgePosition* epos =
519         static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
520       params[ epos->GetUParameter() ] = node;
521     }
522     int nbPoints = aMesh.GetSubMesh(E)->GetSubMeshDS()->NbNodes();
523     if ( nbPoints != params.size())
524     {
525       MESSAGE( "BAD NODE ON EDGE POSITIONS" );
526       return false;
527     }
528
529     // --- load 2D values into MEFISTO structure,
530     //     add IDNodes in mefistoToDS map
531
532     double f, l, uFirst, u;
533     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, F, f, l);
534     uFirst = isForward ? f : l;
535
536     // vertex node
537     gp_Pnt2d p = C2d->Value( uFirst ).XY().Multiplied( scale );
538     if ( fixCommonVertexUV( p, V, W, myOuterWire, F, VWMap, aMesh ))
539       myNodesOnCommonV.push_back( idFirst );
540     mOnVertex.push_back( m );
541     uvslf[m].x = p.X();
542     uvslf[m].y = p.Y();
543     mefistoToDS[m + 1] = idFirst;
544     //MESSAGE(" "<<m<<" "<<mefistoToDS[m+1]);
545     //MESSAGE("__ f "<<uFirst<<" "<<uvslf[m].x <<" "<<uvslf[m].y);
546     m++;
547
548     // internal nodes
549     map<double, const SMDS_MeshNode*>::iterator u_n = params.begin();
550     map<double, const SMDS_MeshNode*>::reverse_iterator u_n_rev = params.rbegin();
551     for ( int i = 0; i < nbPoints; ++i )
552     {
553       if ( isForward ) {
554         u    = u_n->first;
555         node = u_n->second;
556         ++u_n;
557       } else {
558         u    = u_n_rev->first;
559         node = u_n_rev->second;
560         ++u_n_rev;
561       }
562       gp_Pnt2d p = C2d->Value( u ).XY().Multiplied( scale );
563       uvslf[m].x = p.X();
564       uvslf[m].y = p.Y();
565       mefistoToDS[m + 1] = node;
566       //MESSAGE(" "<<m<<" "<<mefistoToDS[m+1]);
567       //MESSAGE("__ "<<i<<" "<<param<<" "<<uvslf[m].x <<" "<<uvslf[m].y);
568       m++;
569     }
570   } // for  wexp
571
572   // prevent failure on overlapped adjacent links,
573   // check only links ending in vertex nodes
574   int mFirst = mOnVertex.front(), mLast = m - 1;
575   list< int >::iterator mIt = mOnVertex.begin();
576   for ( ; mIt != mOnVertex.end(); ++mIt ) {
577     int i = *mIt;
578     int iB = i - 1, iA = i + 1; // indices Before and After
579     if ( iB < mFirst ) iB = mLast;
580     if ( iA > mLast )  iA = mFirst;
581     fixOverlappedLinkUV (uvslf[ iB ], uvslf[ i ], uvslf[ iA ]);
582   }
583
584   return true;
585 }
586
587 //=============================================================================
588 /*!
589  *  
590  */
591 //=============================================================================
592
593 void StdMeshers_MEFISTO_2D::ComputeScaleOnFace(SMESH_Mesh & aMesh,
594         const TopoDS_Face & aFace, double &scalex, double &scaley)
595 {
596   //MESSAGE("StdMeshers_MEFISTO_2D::ComputeScaleOnFace");
597   TopoDS_Face F = TopoDS::Face(aFace.Oriented(TopAbs_FORWARD));
598   TopoDS_Wire W = BRepTools::OuterWire(F);
599
600   double xmin = 1.e300;         // min & max of face 2D parametric coord.
601   double xmax = -1.e300;
602   double ymin = 1.e300;
603   double ymax = -1.e300;
604   int nbp = 23;
605   scalex = 1;
606   scaley = 1;
607
608   TopExp_Explorer wexp(W, TopAbs_EDGE);
609   for ( ; wexp.More(); wexp.Next())
610   {
611     const TopoDS_Edge & E = TopoDS::Edge( wexp.Current() );
612     double f, l;
613     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, F, f, l);
614     if ( C2d.IsNull() ) continue;
615     double du = (l - f) / double (nbp);
616     for (int i = 0; i <= nbp; i++)
617     {
618       double param = f + double (i) * du;
619       gp_Pnt2d p = C2d->Value(param);
620       if (p.X() < xmin)
621         xmin = p.X();
622       if (p.X() > xmax)
623         xmax = p.X();
624       if (p.Y() < ymin)
625         ymin = p.Y();
626       if (p.Y() > ymax)
627         ymax = p.Y();
628       //    MESSAGE(" "<< f<<" "<<l<<" "<<param<<" "<<xmin<<" "<<xmax<<" "<<ymin<<" "<<ymax);
629     }
630   }
631   //   SCRUTE(xmin);
632   //   SCRUTE(xmax);
633   //   SCRUTE(ymin);
634   //   SCRUTE(ymax);
635   double xmoy = (xmax + xmin) / 2.;
636   double ymoy = (ymax + ymin) / 2.;
637   double xsize = xmax - xmin;
638   double ysize = ymax - ymin;
639
640   Handle(Geom_Surface) S = BRep_Tool::Surface(F);       // 3D surface
641
642   double length_x = 0;
643   double length_y = 0;
644   gp_Pnt PX0 = S->Value(xmin, ymoy);
645   gp_Pnt PY0 = S->Value(xmoy, ymin);
646   double dx = xsize / double (nbp);
647   double dy = ysize / double (nbp);
648   for (int i = 1; i <= nbp; i++)
649   {
650     double x = xmin + double (i) * dx;
651     gp_Pnt PX = S->Value(x, ymoy);
652     double y = ymin + double (i) * dy;
653     gp_Pnt PY = S->Value(xmoy, y);
654     length_x += PX.Distance(PX0);
655     length_y += PY.Distance(PY0);
656     PX0 = PX;
657     PY0 = PY;
658   }
659   scalex = length_x / xsize;
660   scaley = length_y / ysize;
661 //   SCRUTE(xsize);
662 //   SCRUTE(ysize);
663   double xyratio = xsize*scalex/(ysize*scaley);
664   const double maxratio = 1.e2;
665   //SCRUTE(xyratio);
666   if (xyratio > maxratio) {
667     SCRUTE( scaley );
668     scaley *= xyratio / maxratio;
669     SCRUTE( scaley );
670   }
671   else if (xyratio < 1./maxratio) {
672     SCRUTE( scalex );
673     scalex *= 1 / xyratio / maxratio;
674     SCRUTE( scalex );
675   }
676   ASSERT(scalex);
677   ASSERT(scaley);
678 }
679
680 //=============================================================================
681 /*!
682  *  
683  */
684 //=============================================================================
685
686 void StdMeshers_MEFISTO_2D::StoreResult(SMESH_Mesh & aMesh,
687                                         Z nbst, R2 * uvst, Z nbt, Z * nust,
688                                         const TopoDS_Face & F, bool faceIsForward,
689                                         map<int, const SMDS_MeshNode*>&mefistoToDS,
690                                         double scalex, double scaley)
691 {
692   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
693   int faceID = meshDS->ShapeToIndex( F );
694
695   Z n, m;
696   Handle(Geom_Surface) S = BRep_Tool::Surface(F);
697
698   for (n = 0; n < nbst; n++)
699   {
700     if (mefistoToDS.find(n + 1) == mefistoToDS.end())
701     {
702       double u = uvst[n][0] / scalex;
703       double v = uvst[n][1] / scaley;
704       gp_Pnt P = S->Value(u, v);
705
706       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
707       meshDS->SetNodeOnFace(node, faceID, u, v);
708
709       //MESSAGE(P.X()<<" "<<P.Y()<<" "<<P.Z());
710       mefistoToDS[n + 1] = node;
711       //MESSAGE("NEW: "<<n<<" "<<mefistoToDS[n+1]);
712     }
713   }
714
715   m = 0;
716   //int mt = 0;
717
718   //SCRUTE(faceIsForward);
719   for (n = 1; n <= nbt; n++)
720   {
721     int inode1 = nust[m++];
722     int inode2 = nust[m++];
723     int inode3 = nust[m++];
724
725     const SMDS_MeshNode *n1, *n2, *n3;
726     n1 = mefistoToDS[inode1];
727     n2 = mefistoToDS[inode2];
728     n3 = mefistoToDS[inode3];
729     //MESSAGE("-- "<<inode1<<" "<<inode2<<" "<<inode3);
730
731     // triangle points must be in trigonometric order if face is Forward
732     // else they must be put clockwise
733
734     bool triangleIsWellOriented = faceIsForward;
735
736     SMDS_MeshElement * elt;
737     if (triangleIsWellOriented)
738       elt = meshDS->AddFace(n1, n2, n3);
739     else
740       elt = meshDS->AddFace(n1, n3, n2);
741
742     meshDS->SetMeshElementOnShape(elt, faceID);
743     m++;
744   }
745
746   // remove bad elements build on vertices shared by wires
747
748   list<const SMDS_MeshNode*>::iterator itN = myNodesOnCommonV.begin();
749   for ( ; itN != myNodesOnCommonV.end(); itN++ )
750   {
751     const SMDS_MeshNode* node = *itN;
752     SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
753     while ( invElemIt->more() )
754     {
755       const SMDS_MeshElement* elem = invElemIt->next();
756       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
757       int nbSame = 0;
758       while ( itN->more() )
759         if ( itN->next() == node)
760           nbSame++;
761       if (nbSame > 1) {
762         MESSAGE( "RM bad element " << elem->GetID());
763         meshDS->RemoveElement( elem );
764       }
765     }
766   }
767
768 }
769
770 //=============================================================================
771 /*!
772  *  
773  */
774 //=============================================================================
775
776 double StdMeshers_MEFISTO_2D::ComputeEdgeElementLength(SMESH_Mesh & aMesh,
777         const TopoDS_Shape & aShape)
778 {
779         //MESSAGE("StdMeshers_MEFISTO_2D::ComputeEdgeElementLength");
780         // **** a mettre dans SMESH_2D_Algo ?
781
782         const TopoDS_Face & FF = TopoDS::Face(aShape);
783         //bool faceIsForward = (FF.Orientation() == TopAbs_FORWARD);
784         TopoDS_Face F = TopoDS::Face(FF.Oriented(TopAbs_FORWARD));
785
786         double meanElementLength = 100;
787         double wireLength = 0;
788         int wireElementsNumber = 0;
789         for (TopExp_Explorer exp(F, TopAbs_WIRE); exp.More(); exp.Next())
790         {
791                 const TopoDS_Wire & W = TopoDS::Wire(exp.Current());
792                 for (TopExp_Explorer expe(W, TopAbs_EDGE); expe.More(); expe.Next())
793                 {
794                         const TopoDS_Edge & E = TopoDS::Edge(expe.Current());
795                         int nb = aMesh.GetSubMesh(E)->GetSubMeshDS()->NbNodes();
796                         double length = EdgeLength(E);
797                         wireLength += length;
798                         wireElementsNumber += nb;
799                 }
800         }
801         if (wireElementsNumber)
802                 meanElementLength = wireLength / wireElementsNumber;
803         //SCRUTE(meanElementLength);
804         return meanElementLength;
805 }
806
807 //=============================================================================
808 /*!
809  *  
810  */
811 //=============================================================================
812
813 ostream & StdMeshers_MEFISTO_2D::SaveTo(ostream & save)
814 {
815   return save;
816 }
817
818 //=============================================================================
819 /*!
820  *  
821  */
822 //=============================================================================
823
824 istream & StdMeshers_MEFISTO_2D::LoadFrom(istream & load)
825 {
826   return load;
827 }
828
829 //=============================================================================
830 /*!
831  *  
832  */
833 //=============================================================================
834
835 ostream & operator <<(ostream & save, StdMeshers_MEFISTO_2D & hyp)
836 {
837   return hyp.SaveTo( save );
838 }
839
840 //=============================================================================
841 /*!
842  *  
843  */
844 //=============================================================================
845
846 istream & operator >>(istream & load, StdMeshers_MEFISTO_2D & hyp)
847 {
848   return hyp.LoadFrom( load );
849 }