Salome HOME
Implememtation of evaluation for improvement 0019296.
[modules/smesh.git] / src / StdMeshers / StdMeshers_MEFISTO_2D.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  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 //  SMESH SMESH : implementaion of SMESH idl descriptions
23 //  File   : StdMeshers_MEFISTO_2D.cxx
24 //           Moved here from SMESH_MEFISTO_2D.cxx
25 //  Author : Paul RASCLE, EDF
26 //  Module : SMESH
27 //
28 #include "StdMeshers_MEFISTO_2D.hxx"
29
30 #include "SMESH_Gen.hxx"
31 #include "SMESH_Mesh.hxx"
32 #include "SMESH_subMesh.hxx"
33 #include "SMESH_Block.hxx"
34 #include "SMESH_MesherHelper.hxx"
35 #include "SMESH_Comment.hxx"
36
37 #include "StdMeshers_FaceSide.hxx"
38 #include "StdMeshers_MaxElementArea.hxx"
39 #include "StdMeshers_LengthFromEdges.hxx"
40
41 #include "Rn.h"
42 #include "aptrte.h"
43
44 #include "SMDS_MeshElement.hxx"
45 #include "SMDS_MeshNode.hxx"
46 #include "SMDS_EdgePosition.hxx"
47 #include "SMDS_FacePosition.hxx"
48
49 #include "utilities.h"
50
51 #include <BRepTools.hxx>
52 #include <BRep_Tool.hxx>
53 #include <Geom_Curve.hxx>
54 #include <Geom2d_Curve.hxx>
55 #include <Geom_Surface.hxx>
56 #include <TopExp.hxx>
57 #include <TopExp_Explorer.hxx>
58 #include <TopTools_ListIteratorOfListOfShape.hxx>
59 #include <TopTools_ListOfShape.hxx>
60 #include <TopTools_MapOfShape.hxx>
61 #include <TopoDS.hxx>
62 #include <TopoDS_Edge.hxx>
63 #include <TopoDS_Face.hxx>
64 #include <TopoDS_Iterator.hxx>
65 #include <gp_Pnt2d.hxx>
66
67 #include <BRep_Tool.hxx>
68 #include <GProp_GProps.hxx>
69 #include <BRepGProp.hxx>
70
71 using namespace std;
72
73 //=============================================================================
74 /*!
75  *  
76  */
77 //=============================================================================
78
79 StdMeshers_MEFISTO_2D::StdMeshers_MEFISTO_2D(int hypId, int studyId, SMESH_Gen * gen):
80   SMESH_2D_Algo(hypId, studyId, gen)
81 {
82   MESSAGE("StdMeshers_MEFISTO_2D::StdMeshers_MEFISTO_2D");
83   _name = "MEFISTO_2D";
84   _shapeType = (1 << TopAbs_FACE);
85   _compatibleHypothesis.push_back("MaxElementArea");
86   _compatibleHypothesis.push_back("LengthFromEdges");
87
88   _edgeLength = 0;
89   _maxElementArea = 0;
90   _hypMaxElementArea = NULL;
91   _hypLengthFromEdges = NULL;
92   myTool = 0;
93 }
94
95 //=============================================================================
96 /*!
97  *  
98  */
99 //=============================================================================
100
101 StdMeshers_MEFISTO_2D::~StdMeshers_MEFISTO_2D()
102 {
103   MESSAGE("StdMeshers_MEFISTO_2D::~StdMeshers_MEFISTO_2D");
104 }
105
106 //=============================================================================
107 /*!
108  *  
109  */
110 //=============================================================================
111
112 bool StdMeshers_MEFISTO_2D::CheckHypothesis
113                          (SMESH_Mesh&                          aMesh,
114                           const TopoDS_Shape&                  aShape,
115                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
116 {
117   _hypMaxElementArea = NULL;
118   _hypLengthFromEdges = NULL;
119   _edgeLength = 0;
120   _maxElementArea = 0;
121
122   list <const SMESHDS_Hypothesis * >::const_iterator itl;
123   const SMESHDS_Hypothesis *theHyp;
124
125   const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape);
126   int nbHyp = hyps.size();
127   if (!nbHyp)
128   {
129     aStatus = SMESH_Hypothesis::HYP_OK; //SMESH_Hypothesis::HYP_MISSING;
130     return true;  // (PAL13464) can work with no hypothesis, LengthFromEdges is default one
131   }
132
133   itl = hyps.begin();
134   theHyp = (*itl); // use only the first hypothesis
135
136   string hypName = theHyp->GetName();
137
138   bool isOk = false;
139
140   if (hypName == "MaxElementArea")
141   {
142     _hypMaxElementArea = static_cast<const StdMeshers_MaxElementArea *>(theHyp);
143     ASSERT(_hypMaxElementArea);
144     _maxElementArea = _hypMaxElementArea->GetMaxArea();
145     isOk = true;
146     aStatus = SMESH_Hypothesis::HYP_OK;
147   }
148
149   else if (hypName == "LengthFromEdges")
150   {
151     _hypLengthFromEdges = static_cast<const StdMeshers_LengthFromEdges *>(theHyp);
152     ASSERT(_hypLengthFromEdges);
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 = sqrt(2. * _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   return isOk;
175 }
176
177 //=============================================================================
178 /*!
179  *  
180  */
181 //=============================================================================
182
183 bool StdMeshers_MEFISTO_2D::Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape)
184 {
185   MESSAGE("StdMeshers_MEFISTO_2D::Compute");
186
187   TopoDS_Face F = TopoDS::Face(aShape.Oriented(TopAbs_FORWARD));
188
189   // helper builds quadratic mesh if necessary
190   SMESH_MesherHelper helper(aMesh);
191   myTool = &helper;
192   _quadraticMesh = myTool->IsQuadraticSubMesh(aShape);
193   const bool ignoreMediumNodes = _quadraticMesh;
194
195   // get all edges of a face
196   TError problem;
197   TWireVector wires = StdMeshers_FaceSide::GetFaceWires( F, aMesh, ignoreMediumNodes, problem );
198   int nbWires = wires.size();
199   if ( problem && !problem->IsOK() ) return error( problem );
200   if ( nbWires == 0 ) return error( "Problem in StdMeshers_FaceSide::GetFaceWires()");
201   if ( wires[0]->NbSegments() < 3 ) // ex: a circle with 2 segments
202     return error(COMPERR_BAD_INPUT_MESH,
203                  SMESH_Comment("Too few segments: ")<<wires[0]->NbSegments());
204
205   // compute average edge length
206   if (!_hypMaxElementArea)
207   {
208     _edgeLength = 0;
209     int nbSegments = 0;
210     for ( int iW = 0; iW < nbWires; ++iW )
211     {
212       StdMeshers_FaceSidePtr wire = wires[ iW ];
213       _edgeLength += wire->Length();
214       nbSegments  += wire->NbSegments();
215     }
216     if ( nbSegments )
217       _edgeLength /= nbSegments;
218   }
219
220   if (/*_hypLengthFromEdges &&*/ _edgeLength < DBL_MIN )
221     _edgeLength = 100;
222
223   Z nblf;                 //nombre de lignes fermees (enveloppe en tete)
224   Z *nudslf = NULL;       //numero du dernier sommet de chaque ligne fermee
225   R2 *uvslf = NULL;       
226   Z nbpti = 0;            //nombre points internes futurs sommets de la triangulation
227   R2 *uvpti = NULL;
228   
229   Z nbst;
230   R2 *uvst = NULL;
231   Z nbt;
232   Z *nust = NULL;
233   Z ierr = 0;
234
235   Z nutysu = 1;           // 1: il existe un fonction areteideale_()
236   // Z  nutysu=0;         // 0: on utilise aretmx
237   R aretmx = _edgeLength; // longueur max aretes future triangulation
238   
239   nblf = nbWires;
240   
241   nudslf = new Z[1 + nblf];
242   nudslf[0] = 0;
243   int iw = 1;
244   int nbpnt = 0;
245
246   // count nb of input points
247   for ( int iW = 0; iW < nbWires; ++iW )
248   {
249     nbpnt += wires[iW]->NbPoints() - 1;
250     nudslf[iw++] = nbpnt;
251   }
252
253   uvslf = new R2[nudslf[nblf]];
254
255   double scalex, scaley;
256   ComputeScaleOnFace(aMesh, F, scalex, scaley);
257
258   // correspondence mefisto index --> Nodes
259   vector< const SMDS_MeshNode*> mefistoToDS(nbpnt, (const SMDS_MeshNode*)0);
260
261   bool isOk = false;
262
263   // fill input points UV
264   if ( LoadPoints(wires, uvslf, mefistoToDS, scalex, scaley) )
265   {
266     // Compute
267     aptrte(nutysu, aretmx,
268            nblf, nudslf, uvslf, nbpti, uvpti, nbst, uvst, nbt, nust, ierr);
269
270     if (ierr == 0)
271     {
272       MESSAGE("... End Triangulation Generated Triangle Number " << nbt);
273       MESSAGE("                                    Node Number " << nbst);
274       StoreResult(nbst, uvst, nbt, nust, mefistoToDS, scalex, scaley);
275       isOk = true;
276     }
277     else
278     {
279       error(ierr,"Error in Triangulation (aptrte())");
280     }
281   }
282   if (nudslf != NULL) delete[]nudslf;
283   if (uvslf != NULL)  delete[]uvslf;
284   if (uvst != NULL)   delete[]uvst;
285   if (nust != NULL)   delete[]nust;
286
287   return isOk;
288 }
289
290
291 //=============================================================================
292 /*!
293  *  
294  */
295 //=============================================================================
296
297 bool StdMeshers_MEFISTO_2D::Evaluate(SMESH_Mesh & aMesh,
298                                      const TopoDS_Shape & aShape,
299                                      MapShapeNbElems& aResMap)
300 {
301   MESSAGE("StdMeshers_MEFISTO_2D::Evaluate");
302
303   TopoDS_Face F = TopoDS::Face(aShape.Oriented(TopAbs_FORWARD));
304
305   double aLen = 0.0;
306   double NbSeg = 0;
307   bool IsQuadratic = false;
308   bool IsFirst = true;
309   TopExp_Explorer exp(F,TopAbs_EDGE);
310   for(; exp.More(); exp.Next()) {
311     TopoDS_Edge E = TopoDS::Edge(exp.Current());
312     MapShapeNbElemsItr anIt = aResMap.find( aMesh.GetSubMesh(E) );
313     if( anIt == aResMap.end() ) continue;
314     std::vector<int> aVec = (*anIt).second;
315     int nbe = Max(aVec[1],aVec[2]);
316     NbSeg += nbe;
317     if(IsFirst) {
318       IsQuadratic = ( aVec[2] > aVec[1] );
319       IsFirst = false;
320     }
321     double a,b;
322     TopLoc_Location L;
323     Handle(Geom_Curve) C = BRep_Tool::Curve(E,L,a,b);
324     gp_Pnt P1;
325     C->D0(a,P1);
326     double dp = (b-a)/nbe;
327     for(int i=1; i<=nbe; i++) {
328       gp_Pnt P2;
329       C->D0(a+i*dp,P2);
330       aLen += P1.Distance(P2);
331       P1 = P2;
332     }
333   }
334   aLen = aLen/NbSeg; // middle length
335
336   _edgeLength = DBL_MAX;
337   double tmpLength = Min( _edgeLength, aLen );
338
339   GProp_GProps G;
340   BRepGProp::SurfaceProperties(aShape,G);
341   double anArea = G.Mass();
342
343   int nbFaces = (int) anArea/(tmpLength*tmpLength*sqrt(3)/4);
344   int nbNodes = (int) ( nbFaces*3 - (NbSeg-1)*2 ) / 6;
345
346   std::vector<int> aVec(17);
347   for(int i=0; i<17; i++) aVec[i] = 0;
348   if(IsQuadratic) {
349     aVec[4] = nbFaces;
350     aVec[0] = nbNodes + nbFaces*3 - (NbSeg-1);
351   }
352   else {
353     aVec[0] = nbNodes;
354     aVec[3] = nbFaces;
355   }
356   SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);
357   aResMap.insert(std::make_pair(sm,aVec));
358
359   return true;
360 }
361
362
363 //=======================================================================
364 //function : fixOverlappedLinkUV
365 //purpose  : prevent failure due to overlapped adjacent links
366 //=======================================================================
367
368 static bool fixOverlappedLinkUV( R2& uv0, const R2& uv1, const R2& uv2 )
369 {
370   gp_XY v1( uv0.x - uv1.x, uv0.y - uv1.y );
371   gp_XY v2( uv2.x - uv1.x, uv2.y - uv1.y );
372
373   double tol2 = DBL_MIN * DBL_MIN;
374   double sqMod1 = v1.SquareModulus();
375   if ( sqMod1 <= tol2 ) return false;
376   double sqMod2 = v2.SquareModulus();
377   if ( sqMod2 <= tol2 ) return false;
378
379   double dot = v1*v2;
380
381   // check sinus >= 1.e-3
382   const double minSin = 1.e-3;
383   if ( dot > 0 && 1 - dot * dot / ( sqMod1 * sqMod2 ) < minSin * minSin ) {
384     MESSAGE(" ___ FIX UV ____" << uv0.x << " " << uv0.y);
385     v1.SetCoord( -v1.Y(), v1.X() );
386     double delta = sqrt( sqMod1 ) * minSin;
387     if ( v1.X() < 0 )
388       uv0.x -= delta;
389     else
390       uv0.x += delta;
391     if ( v1.Y() < 0 )
392       uv0.y -= delta;
393     else
394       uv0.y += delta;
395 // #ifdef _DEBUG_
396 //     MESSAGE(" -> " << uv0.x << " " << uv0.y << " ");
397 //     MESSAGE("v1( " << v1.X() << " " << v1.Y() << " ) " <<
398 //       "v2( " << v2.X() << " " << v2.Y() << " ) ");
399 //    MESSAGE("SIN: " << sqrt(1 - dot * dot / (sqMod1 * sqMod2)));
400 //     v1.SetCoord( uv0.x - uv1.x, uv0.y - uv1.y );
401 //     v2.SetCoord( uv2.x - uv1.x, uv2.y - uv1.y );
402 //     gp_XY v3( uv2.x - uv0.x, uv2.y - uv0.y );
403 //     sqMod1 = v1.SquareModulus();
404 //     sqMod2 = v2.SquareModulus();
405 //     dot = v1*v2;
406 //     double sin = sqrt(1 - dot * dot / (sqMod1 * sqMod2));
407 //     MESSAGE("NEW SIN: " << sin);
408 // #endif
409     return true;
410   }
411   return false;
412 }
413
414 //=======================================================================
415 //function : fixCommonVertexUV
416 //purpose  : 
417 //=======================================================================
418
419 static bool fixCommonVertexUV (R2 &                 theUV,
420                                const TopoDS_Vertex& theV,
421                                const TopoDS_Face&   theF,
422                                const TopTools_IndexedDataMapOfShapeListOfShape & theVWMap,
423                                SMESH_Mesh &         theMesh,
424                                const double         theScaleX,
425                                const double         theScaleY,
426                                const bool           theCreateQuadratic)
427 {
428   if( !theVWMap.Contains( theV )) return false;
429
430   // check if there is another wire sharing theV
431   const TopTools_ListOfShape& WList = theVWMap.FindFromKey( theV );
432   TopTools_ListIteratorOfListOfShape aWIt;
433   TopTools_MapOfShape aWires;
434   for ( aWIt.Initialize( WList ); aWIt.More(); aWIt.Next() )
435     aWires.Add( aWIt.Value() );
436   if ( aWires.Extent() < 2 ) return false;
437
438   TopoDS_Shape anOuterWire = BRepTools::OuterWire(theF);
439   TopoDS_Shape anInnerWire;
440   for ( aWIt.Initialize( WList ); aWIt.More() && anInnerWire.IsNull(); aWIt.Next() )
441     if ( !anOuterWire.IsSame( aWIt.Value() ))
442       anInnerWire = aWIt.Value();
443
444   TopTools_ListOfShape EList;
445   list< double >       UList;
446
447   // find edges of theW sharing theV
448   // and find 2d normal to them at theV
449   gp_Vec2d N(0.,0.);
450   TopoDS_Iterator itE( anInnerWire );
451   for (  ; itE.More(); itE.Next() )
452   {
453     const TopoDS_Edge& E = TopoDS::Edge( itE.Value() );
454     TopoDS_Iterator itV( E );
455     for ( ; itV.More(); itV.Next() )
456     {
457       const TopoDS_Vertex & V = TopoDS::Vertex( itV.Value() );
458       if ( !V.IsSame( theV ))
459         continue;
460       EList.Append( E );
461       Standard_Real u = BRep_Tool::Parameter( V, E );
462       UList.push_back( u );
463       double f, l;
464       Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, theF, f, l);
465       gp_Vec2d d1;
466       gp_Pnt2d p;
467       C2d->D1( u, p, d1 );
468       gp_Vec2d n( d1.Y() * theScaleX, -d1.X() * theScaleY);
469       if ( E.Orientation() == TopAbs_REVERSED )
470         n.Reverse();
471       N += n.Normalized();
472     }
473   }
474
475   // define step size by which to move theUV
476
477   gp_Pnt2d nextUV; // uv of next node on edge, most distant of the four
478   gp_Pnt2d thisUV( theUV.x, theUV.y );
479   double maxDist = -DBL_MAX;
480   TopTools_ListIteratorOfListOfShape aEIt (EList);
481   list< double >::iterator aUIt = UList.begin();
482   for ( ; aEIt.More(); aEIt.Next(), aUIt++ )
483   {
484     const TopoDS_Edge& E = TopoDS::Edge( aEIt.Value() );
485     double f, l;
486     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, theF, f, l);
487
488     double umin = DBL_MAX, umax = -DBL_MAX;
489     SMDS_NodeIteratorPtr nIt = theMesh.GetSubMesh(E)->GetSubMeshDS()->GetNodes();
490     if ( !nIt->more() ) // no nodes on edge, only on vertices
491     {
492       umin = l;
493       umax = f;
494     }
495     else {
496       while ( nIt->more() ) {
497         const SMDS_MeshNode* node = nIt->next();
498         // check if node is medium
499         if ( theCreateQuadratic && SMESH_MesherHelper::IsMedium( node, SMDSAbs_Edge ))
500           continue;
501         const SMDS_EdgePosition* epos =
502           static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
503         double u = epos->GetUParameter();
504         if ( u < umin )
505           umin = u;
506         if ( u > umax )
507           umax = u;
508       }
509     }
510     bool isFirstCommon = ( *aUIt == f );
511     gp_Pnt2d uv = C2d->Value( isFirstCommon ? umin : umax );
512     double dist = thisUV.SquareDistance( uv );
513     if ( dist > maxDist ) {
514       maxDist = dist;
515       nextUV  = uv;
516     }
517   }
518   R2 uv0, uv1, uv2;
519   uv0.x = thisUV.X();   uv0.y = thisUV.Y();
520   uv1.x = nextUV.X();   uv1.y = nextUV.Y(); 
521   uv2.x = thisUV.X();   uv2.y = thisUV.Y();
522
523   uv1.x *= theScaleX;   uv1.y *= theScaleY; 
524
525   if ( fixOverlappedLinkUV( uv0, uv1, uv2 ))
526   {
527     double step = thisUV.Distance( gp_Pnt2d( uv0.x, uv0.y ));
528
529     // move theUV along the normal by the step
530
531     N *= step;
532
533     MESSAGE("--fixCommonVertexUV move(" << theUV.x << " " << theUV.x
534             << ") by (" << N.X() << " " << N.Y() << ")" 
535             << endl << "--- MAX DIST " << maxDist);
536
537     theUV.x += N.X();
538     theUV.y += N.Y();
539
540     return true;
541   }
542   return false;
543 }
544
545 //=============================================================================
546 /*!
547  *  
548  */
549 //=============================================================================
550
551 bool StdMeshers_MEFISTO_2D::LoadPoints(TWireVector &                 wires,
552                                        R2 *                          uvslf,
553                                        vector<const SMDS_MeshNode*>& mefistoToDS,
554                                        double                        scalex,
555                                        double                        scaley)
556 {
557   // to avoid passing same uv points for a vertex common to 2 wires
558   TopoDS_Face F;
559   TopTools_IndexedDataMapOfShapeListOfShape VWMap;
560   if ( wires.size() > 1 )
561   {
562     F = TopoDS::Face( myTool->GetSubShape() );
563     TopExp::MapShapesAndAncestors( F, TopAbs_VERTEX, TopAbs_WIRE, VWMap );
564     int nbVertices = 0;
565     for ( int iW = 0; iW < wires.size(); ++iW )
566       nbVertices += wires[ iW ]->NbEdges();
567     if ( nbVertices == VWMap.Extent() )
568       VWMap.Clear(); // wires have no common vertices
569   }
570
571   int m = 0;
572
573   for ( int iW = 0; iW < wires.size(); ++iW )
574   {
575     const vector<UVPtStruct>& uvPtVec = wires[ iW ]->GetUVPtStruct();
576     if ( uvPtVec.size() != wires[ iW ]->NbPoints() ) {
577       return error(COMPERR_BAD_INPUT_MESH,SMESH_Comment("Unexpected nb of points on wire ")
578                    << iW << ": " << uvPtVec.size()<<" != "<<wires[ iW ]->NbPoints()
579                    << ", probably because of invalid node parameters on geom edges");
580     }
581     if ( m + uvPtVec.size()-1 > mefistoToDS.size() ) {
582       MESSAGE("Wrong mefistoToDS.size: "<<mefistoToDS.size()<<" < "<<m + uvPtVec.size()-1);
583       return error("Internal error");
584     }
585
586     list< int > mOnVertex;
587     vector<UVPtStruct>::const_iterator uvPt = uvPtVec.begin();
588     for ( ++uvPt; uvPt != uvPtVec.end(); ++uvPt )
589     {
590       // bind mefisto ID to node
591       mefistoToDS[m] = uvPt->node;
592       // set UV
593       uvslf[m].x = uvPt->u * scalex;
594       uvslf[m].y = uvPt->v * scaley;
595       if ( uvPt->node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
596         mOnVertex.push_back( m );
597       m++;
598     }
599
600     int mFirst = mOnVertex.front(), mLast = m - 1;
601     list< int >::iterator mIt = mOnVertex.begin();
602     for ( ; mIt != mOnVertex.end(); ++mIt)
603     {
604       int m = *mIt;
605       if ( iW && !VWMap.IsEmpty()) { // except outer wire
606         // avoid passing same uv point for a vertex common to 2 wires
607         int vID = mefistoToDS[m]->GetPosition()->GetShapeId();
608         TopoDS_Vertex V = TopoDS::Vertex( myTool->GetMeshDS()->IndexToShape( vID ));
609         if ( fixCommonVertexUV( uvslf[m], V, F, VWMap, *myTool->GetMesh(),
610                                 scalex, scaley, _quadraticMesh )) {
611           myNodesOnCommonV.push_back( mefistoToDS[m] );
612           continue;
613         }
614       }
615       // prevent failure on overlapped adjacent links,
616       // check only links ending in vertex nodes
617       int mB = m - 1, mA = m + 1; // indices Before and After
618       if ( mB < mFirst ) mB = mLast;
619       if ( mA > mLast )  mA = mFirst;
620       fixOverlappedLinkUV (uvslf[ mB ], uvslf[ m ], uvslf[ mA ]);
621     }
622   }
623
624   return true;
625 }
626
627 //=============================================================================
628 /*!
629  *  
630  */
631 //=============================================================================
632
633 void StdMeshers_MEFISTO_2D::ComputeScaleOnFace(SMESH_Mesh &        aMesh,
634                                                const TopoDS_Face & aFace,
635                                                double &            scalex,
636                                                double &            scaley)
637 {
638   TopoDS_Wire W = BRepTools::OuterWire(aFace);
639
640   double xmin = 1.e300;         // min & max of face 2D parametric coord.
641   double xmax = -1.e300;
642   double ymin = 1.e300;
643   double ymax = -1.e300;
644   int nbp = 23;
645   scalex = 1;
646   scaley = 1;
647
648   TopExp_Explorer wexp(W, TopAbs_EDGE);
649   for ( ; wexp.More(); wexp.Next())
650   {
651     const TopoDS_Edge & E = TopoDS::Edge( wexp.Current() );
652     double f, l;
653     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, aFace, f, l);
654     if ( C2d.IsNull() ) continue;
655     double du = (l - f) / double (nbp);
656     for (int i = 0; i <= nbp; i++)
657     {
658       double param = f + double (i) * du;
659       gp_Pnt2d p = C2d->Value(param);
660       if (p.X() < xmin)
661         xmin = p.X();
662       if (p.X() > xmax)
663         xmax = p.X();
664       if (p.Y() < ymin)
665         ymin = p.Y();
666       if (p.Y() > ymax)
667         ymax = p.Y();
668       //    MESSAGE(" "<< f<<" "<<l<<" "<<param<<" "<<xmin<<" "<<xmax<<" "<<ymin<<" "<<ymax);
669     }
670   }
671   //   SCRUTE(xmin);
672   //   SCRUTE(xmax);
673   //   SCRUTE(ymin);
674   //   SCRUTE(ymax);
675   double xmoy = (xmax + xmin) / 2.;
676   double ymoy = (ymax + ymin) / 2.;
677   double xsize = xmax - xmin;
678   double ysize = ymax - ymin;
679
680   TopLoc_Location L;
681   Handle(Geom_Surface) S = BRep_Tool::Surface(aFace,L);       // 3D surface
682
683   double length_x = 0;
684   double length_y = 0;
685   gp_Pnt PX0 = S->Value(xmin, ymoy);
686   gp_Pnt PY0 = S->Value(xmoy, ymin);
687   double dx = xsize / double (nbp);
688   double dy = ysize / double (nbp);
689   for (int i = 1; i <= nbp; i++)
690   {
691     double x = xmin + double (i) * dx;
692     gp_Pnt PX = S->Value(x, ymoy);
693     double y = ymin + double (i) * dy;
694     gp_Pnt PY = S->Value(xmoy, y);
695     length_x += PX.Distance(PX0);
696     length_y += PY.Distance(PY0);
697     PX0 = PX;
698     PY0 = PY;
699   }
700   scalex = length_x / xsize;
701   scaley = length_y / ysize;
702 //   SCRUTE(xsize);
703 //   SCRUTE(ysize);
704   double xyratio = xsize*scalex/(ysize*scaley);
705   const double maxratio = 1.e2;
706   //SCRUTE(xyratio);
707   if (xyratio > maxratio) {
708     SCRUTE( scaley );
709     scaley *= xyratio / maxratio;
710     SCRUTE( scaley );
711   }
712   else if (xyratio < 1./maxratio) {
713     SCRUTE( scalex );
714     scalex *= 1 / xyratio / maxratio;
715     SCRUTE( scalex );
716   }
717   ASSERT(scalex);
718   ASSERT(scaley);
719 }
720
721 //=============================================================================
722 /*!
723  *  
724  */
725 //=============================================================================
726
727 void StdMeshers_MEFISTO_2D::StoreResult(Z nbst, R2 * uvst, Z nbt, Z * nust,
728                                         vector< const SMDS_MeshNode*>&mefistoToDS,
729                                         double scalex, double scaley)
730 {
731   SMESHDS_Mesh * meshDS = myTool->GetMeshDS();
732   int faceID = myTool->GetSubShapeID();
733
734   TopoDS_Face F = TopoDS::Face( myTool->GetSubShape() );
735   Handle(Geom_Surface) S = BRep_Tool::Surface( F );
736
737   Z n = mefistoToDS.size(); // nb input points
738   mefistoToDS.resize( nbst );
739   for ( ; n < nbst; n++)
740   {
741     if (!mefistoToDS[n])
742     {
743       double u = uvst[n][0] / scalex;
744       double v = uvst[n][1] / scaley;
745       gp_Pnt P = S->Value(u, v);
746
747       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
748       meshDS->SetNodeOnFace(node, faceID, u, v);
749
750       //MESSAGE(P.X()<<" "<<P.Y()<<" "<<P.Z());
751       mefistoToDS[n] = node;
752       //MESSAGE("NEW: "<<n<<" "<<mefistoToDS[n+1]);
753     }
754   }
755
756   Z m = 0;
757
758   // triangle points must be in trigonometric order if face is Forward
759   // else they must be put clockwise
760
761   bool triangleIsWellOriented = ( F.Orientation() == TopAbs_FORWARD );
762
763   for (n = 1; n <= nbt; n++)
764   {
765     const SMDS_MeshNode * n1 = mefistoToDS[ nust[m++] - 1 ];
766     const SMDS_MeshNode * n2 = mefistoToDS[ nust[m++] - 1 ];
767     const SMDS_MeshNode * n3 = mefistoToDS[ nust[m++] - 1 ];
768
769     SMDS_MeshElement * elt;
770     if (triangleIsWellOriented)
771       elt = myTool->AddFace(n1, n2, n3);
772     else
773       elt = myTool->AddFace(n1, n3, n2);
774
775     meshDS->SetMeshElementOnShape(elt, faceID);
776     m++;
777   }
778
779   // remove bad elements built on vertices shared by wires
780
781   list<const SMDS_MeshNode*>::iterator itN = myNodesOnCommonV.begin();
782   for ( ; itN != myNodesOnCommonV.end(); itN++ )
783   {
784     const SMDS_MeshNode* node = *itN;
785     SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
786     while ( invElemIt->more() )
787     {
788       const SMDS_MeshElement* elem = invElemIt->next();
789       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
790       int nbSame = 0;
791       while ( itN->more() )
792         if ( itN->next() == node)
793           nbSame++;
794       if (nbSame > 1) {
795         MESSAGE( "RM bad element " << elem->GetID());
796         meshDS->RemoveElement( elem );
797       }
798     }
799   }
800 }