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