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