Salome HOME
Porting documentation on the Doxygen-1.8.0
[modules/smesh.git] / src / StdMeshers / StdMeshers_RadialQuadrangle_1D2D.cxx
1 // Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18
19 //  SMESH SMESH : implementaion of SMESH idl descriptions
20 // File      : StdMeshers_RadialQuadrangle_1D2D.cxx
21 // Module    : SMESH
22 // Created   : Fri Oct 20 11:37:07 2006
23 // Author    : Edward AGAPOV (eap)
24
25 #include "StdMeshers_RadialQuadrangle_1D2D.hxx"
26
27 #include "StdMeshers_NumberOfLayers.hxx"
28 #include "StdMeshers_LayerDistribution.hxx"
29 #include "StdMeshers_Regular_1D.hxx"
30 #include "StdMeshers_NumberOfSegments.hxx"
31
32 #include "SMDS_MeshNode.hxx"
33 #include "SMESHDS_SubMesh.hxx"
34 #include "SMESH_Gen.hxx"
35 #include "SMESH_HypoFilter.hxx"
36 #include "SMESH_Mesh.hxx"
37 #include "SMESH_MesherHelper.hxx"
38 #include "SMESH_subMesh.hxx"
39 #include "SMESH_subMeshEventListener.hxx"
40
41 #include "utilities.h"
42
43 #include <BRepAdaptor_Curve.hxx>
44 #include <BRepBuilderAPI_MakeEdge.hxx>
45 #include <BRep_Tool.hxx>
46 #include <GeomAPI_ProjectPointOnSurf.hxx>
47 #include <Geom_Circle.hxx>
48 #include <Geom_Line.hxx>
49 #include <Geom_TrimmedCurve.hxx>
50 #include <TColgp_SequenceOfPnt.hxx>
51 #include <TColgp_SequenceOfPnt2d.hxx>
52 #include <TopExp.hxx>
53 #include <TopExp_Explorer.hxx>
54 #include <TopTools_ListIteratorOfListOfShape.hxx>
55 #include <TopoDS.hxx>
56
57
58 using namespace std;
59
60 #define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; }
61 #define gpXYZ(n) gp_XYZ(n->X(),n->Y(),n->Z())
62
63
64 //=======================================================================
65 //function : StdMeshers_RadialQuadrangle_1D2D
66 //purpose  : 
67 //=======================================================================
68
69 StdMeshers_RadialQuadrangle_1D2D::StdMeshers_RadialQuadrangle_1D2D(int hypId,
70                                                                    int studyId,
71                                                                    SMESH_Gen* gen)
72   :SMESH_2D_Algo(hypId, studyId, gen)
73 {
74   _name = "RadialQuadrangle_1D2D";
75   _shapeType = (1 << TopAbs_FACE);        // 1 bit per shape type
76
77   _compatibleHypothesis.push_back("LayerDistribution2D");
78   _compatibleHypothesis.push_back("NumberOfLayers2D");
79   myNbLayerHypo = 0;
80   myDistributionHypo = 0;
81   _requireDiscreteBoundary = false;
82   _supportSubmeshes = true;
83 }
84
85
86 //================================================================================
87 /*!
88  * \brief Destructor
89  */
90 //================================================================================
91
92 StdMeshers_RadialQuadrangle_1D2D::~StdMeshers_RadialQuadrangle_1D2D()
93 {}
94
95
96 //=======================================================================
97 //function : CheckHypothesis
98 //purpose  : 
99 //=======================================================================
100
101 bool StdMeshers_RadialQuadrangle_1D2D::CheckHypothesis
102                            (SMESH_Mesh&                          aMesh,
103                             const TopoDS_Shape&                  aShape,
104                             SMESH_Hypothesis::Hypothesis_Status& aStatus)
105 {
106   // check aShape 
107   myNbLayerHypo = 0;
108   myDistributionHypo = 0;
109
110   list <const SMESHDS_Hypothesis * >::const_iterator itl;
111
112   const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape);
113   if ( hyps.size() == 0 ) {
114     aStatus = SMESH_Hypothesis::HYP_OK;
115     return true;  // can work with no hypothesis
116   }
117
118   if ( hyps.size() > 1 ) {
119     aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST;
120     return false;
121   }
122
123   const SMESHDS_Hypothesis *theHyp = hyps.front();
124
125   string hypName = theHyp->GetName();
126
127   if (hypName == "NumberOfLayers2D") {
128     myNbLayerHypo = static_cast<const StdMeshers_NumberOfLayers *>(theHyp);
129     aStatus = SMESH_Hypothesis::HYP_OK;
130     return true;
131   }
132   if (hypName == "LayerDistribution2D") {
133     myDistributionHypo = static_cast<const StdMeshers_LayerDistribution *>(theHyp);
134     aStatus = SMESH_Hypothesis::HYP_OK;
135     return true;
136   }
137   aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
138   return true;
139 }
140
141 namespace
142 {
143   // ------------------------------------------------------------------------------
144   /*!
145    * \brief Listener used to mark edges meshed by StdMeshers_RadialQuadrangle_1D2D
146    */
147   class TEdgeMarker : public SMESH_subMeshEventListener
148   {
149     TEdgeMarker(): SMESH_subMeshEventListener(/*isDeletable=*/false,
150                                               "StdMeshers_RadialQuadrangle_1D2D::TEdgeMarker") {}
151   public:
152     //!<  Return static listener
153     static SMESH_subMeshEventListener* getListener()
154     {
155       static TEdgeMarker theEdgeMarker;
156       return &theEdgeMarker;
157     }
158     //! Clear face sumbesh if something happens on edges
159     void ProcessEvent(const int          event,
160                       const int          eventType,
161                       SMESH_subMesh*     edgeSubMesh,
162                       EventListenerData* data,
163                       const SMESH_Hypothesis*  /*hyp*/)
164     {
165       if ( data && !data->mySubMeshes.empty() && eventType == SMESH_subMesh::ALGO_EVENT)
166       {
167         ASSERT( data->mySubMeshes.front() != edgeSubMesh );
168         SMESH_subMesh* faceSubMesh = data->mySubMeshes.front();
169         faceSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
170       }
171     }
172   };
173
174   // ------------------------------------------------------------------------------
175   /*!
176    * \brief Mark an edge as computed by StdMeshers_RadialQuadrangle_1D2D
177    */
178   void markEdgeAsComputedByMe(const TopoDS_Edge& edge, SMESH_subMesh* faceSubMesh)
179   {
180     if ( SMESH_subMesh* edgeSM = faceSubMesh->GetFather()->GetSubMeshContaining( edge ))
181     {
182       if ( !edgeSM->GetEventListenerData( TEdgeMarker::getListener() ))
183         faceSubMesh->SetEventListener( TEdgeMarker::getListener(),
184                                        SMESH_subMeshEventListenerData::MakeData(faceSubMesh),
185                                        edgeSM);
186     }
187   }
188   // ------------------------------------------------------------------------------
189   /*!
190    * \brief Return true if a radial edge was meshed with StdMeshers_RadialQuadrangle_1D2D with
191    * the same radial distribution
192    */
193 //   bool isEdgeCompatiballyMeshed(const TopoDS_Edge& edge, SMESH_subMesh* faceSubMesh)
194 //   {
195 //     if ( SMESH_subMesh* edgeSM = faceSubMesh->GetFather()->GetSubMeshContaining( edge ))
196 //     {
197 //       if ( SMESH_subMeshEventListenerData* otherFaceData =
198 //            edgeSM->GetEventListenerData( TEdgeMarker::getListener() ))
199 //       {
200 //         // compare hypothesis aplied to two disk faces sharing radial edges
201 //         SMESH_Mesh& mesh = *faceSubMesh->GetFather();
202 //         SMESH_Algo* radialQuadAlgo = mesh.GetGen()->GetAlgo(mesh, faceSubMesh->GetSubShape() );
203 //         SMESH_subMesh* otherFaceSubMesh = otherFaceData->mySubMeshes.front();
204 //         list <const SMESHDS_Hypothesis *> hyps1 =
205 //           radialQuadAlgo->GetUsedHypothesis( mesh, faceSubMesh->GetSubShape());
206 //         list <const SMESHDS_Hypothesis *> hyps2 =
207 //           radialQuadAlgo->GetUsedHypothesis( mesh, otherFaceSubMesh->GetSubShape());
208 //         if( hyps1.empty() && hyps2.empty() )
209 //           return true; // defaul hyps
210 //         if ( hyps1.size() != hyps2.size() )
211 //           return false;
212 //         return *hyps1.front() == *hyps2.front();
213 //       }
214 //     }
215 //     return false;
216 //   }
217
218   //================================================================================
219   /*!
220    * \brief Return base curve of the edge and extremum parameters
221    */
222   //================================================================================
223
224   Handle(Geom_Curve) getCurve(const TopoDS_Edge& edge, double* f=0, double* l=0)
225   {
226     Handle(Geom_Curve) C;
227     if ( !edge.IsNull() )
228     {
229       double first = 0., last = 0.;
230       C = BRep_Tool::Curve(edge, first, last);
231       if ( !C.IsNull() )
232       {
233         Handle(Geom_TrimmedCurve) tc = Handle(Geom_TrimmedCurve)::DownCast(C);
234         while( !tc.IsNull() ) {
235           C = tc->BasisCurve();
236           tc = Handle(Geom_TrimmedCurve)::DownCast(C);
237         }
238         if ( f ) *f = first;
239         if ( l ) *l = last;
240       }
241     }
242     return C;
243   }
244
245   //================================================================================
246   /*!
247    * \brief Return edges of the face
248    *  \retval int - nb of edges
249    */
250   //================================================================================
251
252   int analyseFace(const TopoDS_Shape& face,
253                   TopoDS_Edge&        CircEdge,
254                   TopoDS_Edge&        LinEdge1,
255                   TopoDS_Edge&        LinEdge2)
256   {
257     CircEdge.Nullify(); LinEdge1.Nullify(); LinEdge2.Nullify();
258     int nbe = 0;
259
260     for ( TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next(), ++nbe )
261     {
262       const TopoDS_Edge& E = TopoDS::Edge( exp.Current() );
263       double f,l;
264       Handle(Geom_Curve) C = getCurve(E,&f,&l);
265       if ( !C.IsNull() )
266       {
267         if ( C->IsKind( STANDARD_TYPE(Geom_Circle)))
268         {
269           if ( CircEdge.IsNull() )
270             CircEdge = E;
271           else
272             return 0;
273         }
274         else if ( LinEdge1.IsNull() )
275           LinEdge1 = E;
276         else
277           LinEdge2 = E;
278       }
279     }
280     return nbe;
281   }
282
283 //================================================================================
284 //================================================================================
285 /*!
286  * \brief Class computing layers distribution using data of
287  *        StdMeshers_LayerDistribution hypothesis
288  */
289 //================================================================================
290 //================================================================================
291
292 class TNodeDistributor: public StdMeshers_Regular_1D
293 {
294   list <const SMESHDS_Hypothesis *> myUsedHyps;
295 public:
296   // -----------------------------------------------------------------------------
297   static TNodeDistributor* GetDistributor(SMESH_Mesh& aMesh)
298   {
299     const int myID = -1000;
300     map < int, SMESH_1D_Algo * > & algoMap = aMesh.GetGen()->_map1D_Algo;
301     map < int, SMESH_1D_Algo * >::iterator id_algo = algoMap.find( myID );
302     if ( id_algo == algoMap.end() )
303       return new TNodeDistributor( myID, 0, aMesh.GetGen() );
304     return static_cast< TNodeDistributor* >( id_algo->second );
305   }
306   // -----------------------------------------------------------------------------
307   //! Computes distribution of nodes on a straight line ending at pIn and pOut
308   bool Compute( vector< double > &      positions,
309                 gp_Pnt                  pIn,
310                 gp_Pnt                  pOut,
311                 SMESH_Mesh&             aMesh,
312                 const SMESH_Hypothesis* hyp1d)
313   {
314     if ( !hyp1d ) return error( "Invalid LayerDistribution hypothesis");
315
316     double len = pIn.Distance( pOut );
317     if ( len <= DBL_MIN ) return error("Too close points of inner and outer shells");
318
319     myUsedHyps.clear();
320     myUsedHyps.push_back( hyp1d );
321
322     TopoDS_Edge edge = BRepBuilderAPI_MakeEdge( pIn, pOut );
323     SMESH_Hypothesis::Hypothesis_Status aStatus;
324     if ( !StdMeshers_Regular_1D::CheckHypothesis( aMesh, edge, aStatus ))
325       return error( "StdMeshers_Regular_1D::CheckHypothesis() failed "
326                     "with LayerDistribution hypothesis");
327
328     BRepAdaptor_Curve C3D(edge);
329     double f = C3D.FirstParameter(), l = C3D.LastParameter();
330     list< double > params;
331     if ( !StdMeshers_Regular_1D::computeInternalParameters( aMesh, C3D, len, f, l, params, false ))
332       return error("StdMeshers_Regular_1D failed to compute layers distribution");
333
334     positions.clear();
335     positions.reserve( params.size() );
336     for (list<double>::iterator itU = params.begin(); itU != params.end(); itU++)
337       positions.push_back( *itU / len );
338     return true;
339   }
340   // -----------------------------------------------------------------------------
341   //! Make mesh on an adge using assigned 1d hyp or defaut nb of segments
342   bool ComputeCircularEdge(SMESH_Mesh&         aMesh,
343                            const TopoDS_Edge& anEdge)
344   {
345     _gen->Compute( aMesh, anEdge);
346     SMESH_subMesh *sm = aMesh.GetSubMesh(anEdge);
347     if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK)
348     {
349       // find any 1d hyp assigned (there can be a hyp w/o algo)
350       myUsedHyps = SMESH_Algo::GetUsedHypothesis(aMesh, anEdge, /*ignoreAux=*/true);
351       Hypothesis_Status aStatus;
352       if ( !StdMeshers_Regular_1D::CheckHypothesis( aMesh, anEdge, aStatus ))
353       {
354         // no valid 1d hyp assigned, use default nb of segments
355         _hypType                    = NB_SEGMENTS;
356         _ivalue[ DISTR_TYPE_IND ]   = StdMeshers_NumberOfSegments::DT_Regular;
357         _ivalue[ NB_SEGMENTS_IND  ] = _gen->GetDefaultNbSegments();
358       }
359       return StdMeshers_Regular_1D::Compute( aMesh, anEdge );
360     }
361     return true;
362   }
363   // -----------------------------------------------------------------------------
364   //! Make mesh on an adge using assigned 1d hyp or defaut nb of segments
365   bool EvaluateCircularEdge(SMESH_Mesh&        aMesh,
366                             const TopoDS_Edge& anEdge,
367                             MapShapeNbElems&   aResMap)
368   {
369     _gen->Evaluate( aMesh, anEdge, aResMap );
370     if ( aResMap.count( aMesh.GetSubMesh( anEdge )))
371       return true;
372
373     // find any 1d hyp assigned
374     myUsedHyps = SMESH_Algo::GetUsedHypothesis(aMesh, anEdge, /*ignoreAux=*/true);
375     Hypothesis_Status aStatus;
376     if ( !StdMeshers_Regular_1D::CheckHypothesis( aMesh, anEdge, aStatus ))
377     {
378       // no valid 1d hyp assigned, use default nb of segments
379       _hypType                    = NB_SEGMENTS;
380       _ivalue[ DISTR_TYPE_IND ]   = StdMeshers_NumberOfSegments::DT_Regular;
381       _ivalue[ NB_SEGMENTS_IND  ] = _gen->GetDefaultNbSegments();
382     }
383     return StdMeshers_Regular_1D::Evaluate( aMesh, anEdge, aResMap );
384   }
385 protected:
386   // -----------------------------------------------------------------------------
387   TNodeDistributor( int hypId, int studyId, SMESH_Gen* gen)
388     : StdMeshers_Regular_1D( hypId, studyId, gen)
389   {
390   }
391   // -----------------------------------------------------------------------------
392   virtual const list <const SMESHDS_Hypothesis *> &
393     GetUsedHypothesis(SMESH_Mesh &, const TopoDS_Shape &, const bool)
394   {
395     return myUsedHyps;
396   }
397   // -----------------------------------------------------------------------------
398 };
399 }
400
401 //=======================================================================
402 /*!
403  * \brief Allow algo to do something after persistent restoration
404  * \param subMesh - restored submesh
405  *
406  * call markEdgeAsComputedByMe()
407  */
408 //=======================================================================
409
410 void StdMeshers_RadialQuadrangle_1D2D::SubmeshRestored(SMESH_subMesh* faceSubMesh)
411 {
412   if ( !faceSubMesh->IsEmpty() )
413   {
414     TopoDS_Edge CircEdge, LinEdge1, LinEdge2;
415     analyseFace( faceSubMesh->GetSubShape(), CircEdge, LinEdge1, LinEdge2 );
416     if ( !CircEdge.IsNull() ) markEdgeAsComputedByMe( CircEdge, faceSubMesh );
417     if ( !LinEdge1.IsNull() ) markEdgeAsComputedByMe( LinEdge1, faceSubMesh );
418     if ( !LinEdge2.IsNull() ) markEdgeAsComputedByMe( LinEdge2, faceSubMesh );
419   }
420 }
421
422 //=======================================================================
423 //function : Compute
424 //purpose  : 
425 //=======================================================================
426
427 bool StdMeshers_RadialQuadrangle_1D2D::Compute(SMESH_Mesh&         aMesh,
428                                                const TopoDS_Shape& aShape)
429 {
430   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
431
432   myHelper = new SMESH_MesherHelper( aMesh );
433   myHelper->IsQuadraticSubMesh( aShape );
434   // to delete helper at exit from Compute()
435   auto_ptr<SMESH_MesherHelper> helperDeleter( myHelper );
436
437   TNodeDistributor* algo1d = TNodeDistributor::GetDistributor(aMesh);
438
439   TopoDS_Edge CircEdge, LinEdge1, LinEdge2;
440   int nbe = analyseFace( aShape, CircEdge, LinEdge1, LinEdge2 );
441   Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge ));
442   if( nbe>3 || nbe < 1 || aCirc.IsNull() )
443     return error("The face must be a full circle or a part of circle (i.e. the number of edges is less or equal to 3 and one of them is a circle curve)");
444   
445   gp_Pnt P0, P1;
446   // points for rotation
447   TColgp_SequenceOfPnt Points;
448   // angles for rotation
449   TColStd_SequenceOfReal Angles;
450   // Nodes1 and Nodes2 - nodes along radiuses
451   // CNodes - nodes on circle edge
452   vector< const SMDS_MeshNode* > Nodes1, Nodes2, CNodes;
453   SMDS_MeshNode * NC;
454   // parameters edge nodes on face
455   TColgp_SequenceOfPnt2d Pnts2d1;
456   gp_Pnt2d PC;
457
458   int faceID = meshDS->ShapeToIndex(aShape);
459   TopoDS_Face F = TopoDS::Face(aShape);
460   Handle(Geom_Surface) S = BRep_Tool::Surface(F);
461
462
463   if(nbe==1)
464   {
465     if (!algo1d->ComputeCircularEdge( aMesh, CircEdge ))
466       return error( algo1d->GetComputeError() );
467     map< double, const SMDS_MeshNode* > theNodes;
468     if ( !GetSortedNodesOnEdge(aMesh.GetMeshDS(),CircEdge,true,theNodes))
469       return error("Circular edge is incorrectly meshed");
470
471     CNodes.clear();
472     map< double, const SMDS_MeshNode* >::iterator itn = theNodes.begin();
473     const SMDS_MeshNode* NF = (*itn).second;
474     CNodes.push_back( (*itn).second );
475     double fang = (*itn).first;
476     if ( itn != theNodes.end() ) {
477       itn++;
478       for(; itn != theNodes.end(); itn++ ) {
479         CNodes.push_back( (*itn).second );
480         double ang = (*itn).first - fang;
481         if( ang>M_PI ) ang = ang - 2.*M_PI;
482         if( ang<-M_PI ) ang = ang + 2.*M_PI;
483         Angles.Append( ang ); 
484       }
485     }
486     P1 = gp_Pnt( NF->X(), NF->Y(), NF->Z() );
487     P0 = aCirc->Location();
488
489     if ( !computeLayerPositions(P0,P1))
490       return false;
491
492     TopoDS_Vertex V1 = myHelper->IthVertex(0, CircEdge );
493     gp_Pnt2d p2dV = BRep_Tool::Parameters( V1, TopoDS::Face(aShape) );
494
495     NC = meshDS->AddNode(P0.X(), P0.Y(), P0.Z());
496     GeomAPI_ProjectPointOnSurf PPS(P0,S);
497     double U0,V0;
498     PPS.Parameters(1,U0,V0);
499     meshDS->SetNodeOnFace(NC, faceID, U0, V0);
500     PC = gp_Pnt2d(U0,V0);
501
502     gp_Vec aVec(P0,P1);
503     gp_Vec2d aVec2d(PC,p2dV);
504     Nodes1.resize( myLayerPositions.size()+1 );
505     Nodes2.resize( myLayerPositions.size()+1 );
506     int i = 0;
507     for(; i<myLayerPositions.size(); i++) {
508       gp_Pnt P( P0.X() + aVec.X()*myLayerPositions[i],
509                 P0.Y() + aVec.Y()*myLayerPositions[i],
510                 P0.Z() + aVec.Z()*myLayerPositions[i] );
511       Points.Append(P);
512       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
513       Nodes1[i] = node;
514       Nodes2[i] = node;
515       double U = PC.X() + aVec2d.X()*myLayerPositions[i];
516       double V = PC.Y() + aVec2d.Y()*myLayerPositions[i];
517       meshDS->SetNodeOnFace( node, faceID, U, V );
518       Pnts2d1.Append(gp_Pnt2d(U,V));
519     }
520     Nodes1[Nodes1.size()-1] = NF;
521     Nodes2[Nodes1.size()-1] = NF;
522   }
523   else if(nbe==2 && LinEdge1.Orientation() != TopAbs_INTERNAL )
524   {
525     // one curve must be a half of circle and other curve must be
526     // a segment of line
527     double fp, lp;
528     Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge, &fp, &lp ));
529     if( fabs(fabs(lp-fp)-M_PI) > Precision::Confusion() ) {
530       // not half of circle
531       return error(COMPERR_BAD_SHAPE);
532     }
533     Handle(Geom_Line) aLine = Handle(Geom_Line)::DownCast( getCurve( LinEdge1 ));
534     if( aLine.IsNull() ) {
535       // other curve not line
536       return error(COMPERR_BAD_SHAPE);
537     }
538
539     if ( !algo1d->ComputeCircularEdge( aMesh, CircEdge ))
540       return error( algo1d->GetComputeError() );
541     map< double, const SMDS_MeshNode* > theNodes;
542     if ( !GetSortedNodesOnEdge(aMesh.GetMeshDS(),CircEdge,true,theNodes) )
543       return error("Circular edge is incorrectly meshed");
544
545     map< double, const SMDS_MeshNode* >::iterator itn = theNodes.begin();
546     CNodes.clear();
547     CNodes.push_back( itn->second );
548     double fang = (*itn).first;
549     itn++;
550     for(; itn != theNodes.end(); itn++ ) {
551       CNodes.push_back( (*itn).second );
552       double ang = (*itn).first - fang;
553       if( ang>M_PI ) ang = ang - 2.*M_PI;
554       if( ang<-M_PI ) ang = ang + 2.*M_PI;
555       Angles.Append( ang );
556     }
557     const SMDS_MeshNode* NF = theNodes.begin()->second;
558     const SMDS_MeshNode* NL = theNodes.rbegin()->second;
559     P1 = gp_Pnt( NF->X(), NF->Y(), NF->Z() );
560     gp_Pnt P2( NL->X(), NL->Y(), NL->Z() );
561     P0 = aCirc->Location();
562
563     bool linEdgeComputed;
564     if ( !computeLayerPositions(P0,P1,LinEdge1,&linEdgeComputed))
565       return false;
566
567     if ( linEdgeComputed )
568     {
569       if (!GetSortedNodesOnEdge(aMesh.GetMeshDS(),LinEdge1,true,theNodes))
570         return error("Invalid mesh on a straight edge");
571
572       Nodes1.resize( myLayerPositions.size()+1 );
573       Nodes2.resize( myLayerPositions.size()+1 );
574       vector< const SMDS_MeshNode* > *pNodes1 = &Nodes1, *pNodes2 = &Nodes2;
575       bool nodesFromP0ToP1 = ( theNodes.rbegin()->second == NF );
576       if ( !nodesFromP0ToP1 ) std::swap( pNodes1, pNodes2 );
577
578       map< double, const SMDS_MeshNode* >::reverse_iterator ritn = theNodes.rbegin();
579       itn = theNodes.begin();
580       for ( int i = Nodes1.size()-1; i > -1; ++itn, ++ritn, --i )
581       {
582         (*pNodes1)[i] = ritn->second;
583         (*pNodes2)[i] =  itn->second;
584         Points.Prepend( gpXYZ( Nodes1[i]));
585         Pnts2d1.Prepend( myHelper->GetNodeUV( F, Nodes1[i]));
586       }
587       NC = const_cast<SMDS_MeshNode*>( itn->second );
588       Points.Remove( Nodes1.size() );
589     }
590     else
591     {
592       gp_Vec aVec(P0,P1);
593       int edgeID = meshDS->ShapeToIndex(LinEdge1);
594       // check orientation
595       Handle(Geom_Curve) Crv = BRep_Tool::Curve(LinEdge1,fp,lp);
596       gp_Pnt Ptmp;
597       Crv->D0(fp,Ptmp);
598       bool ori = true;
599       if( P1.Distance(Ptmp) > Precision::Confusion() )
600         ori = false;
601       // get UV points for edge
602       gp_Pnt2d PF,PL;
603       BRep_Tool::UVPoints( LinEdge1, TopoDS::Face(aShape), PF, PL );
604       PC = gp_Pnt2d( (PF.X()+PL.X())/2, (PF.Y()+PL.Y())/2 );
605       gp_Vec2d V2d;
606       if(ori) V2d = gp_Vec2d(PC,PF);
607       else V2d = gp_Vec2d(PC,PL);
608       // add nodes on edge
609       double cp = (fp+lp)/2;
610       double dp2 = (lp-fp)/2;
611       NC = meshDS->AddNode(P0.X(), P0.Y(), P0.Z());
612       meshDS->SetNodeOnEdge(NC, edgeID, cp);
613       Nodes1.resize( myLayerPositions.size()+1 );
614       Nodes2.resize( myLayerPositions.size()+1 );
615       int i = 0;
616       for(; i<myLayerPositions.size(); i++) {
617         gp_Pnt P( P0.X() + aVec.X()*myLayerPositions[i],
618                   P0.Y() + aVec.Y()*myLayerPositions[i],
619                   P0.Z() + aVec.Z()*myLayerPositions[i] );
620         Points.Append(P);
621         SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
622         Nodes1[i] = node;
623         double param;
624         if(ori)
625           param = fp + dp2*(1-myLayerPositions[i]);
626         else
627           param = cp + dp2*myLayerPositions[i];
628         meshDS->SetNodeOnEdge(node, edgeID, param);
629         P = gp_Pnt( P0.X() - aVec.X()*myLayerPositions[i],
630                     P0.Y() - aVec.Y()*myLayerPositions[i],
631                     P0.Z() - aVec.Z()*myLayerPositions[i] );
632         node = meshDS->AddNode(P.X(), P.Y(), P.Z());
633         Nodes2[i] = node;
634         if(!ori)
635           param = fp + dp2*(1-myLayerPositions[i]);
636         else
637           param = cp + dp2*myLayerPositions[i];
638         meshDS->SetNodeOnEdge(node, edgeID, param);
639         // parameters on face
640         gp_Pnt2d P2d( PC.X() + V2d.X()*myLayerPositions[i],
641                       PC.Y() + V2d.Y()*myLayerPositions[i] );
642         Pnts2d1.Append(P2d);
643       }
644       Nodes1[ myLayerPositions.size() ] = NF;
645       Nodes2[ myLayerPositions.size() ] = NL;
646       // create 1D elements on edge
647       vector< const SMDS_MeshNode* > tmpNodes;
648       tmpNodes.resize(2*Nodes1.size()+1);
649       for(i=0; i<Nodes2.size(); i++)
650         tmpNodes[Nodes2.size()-i-1] = Nodes2[i];
651       tmpNodes[Nodes2.size()] = NC;
652       for(i=0; i<Nodes1.size(); i++)
653         tmpNodes[Nodes2.size()+1+i] = Nodes1[i];
654       for(i=1; i<tmpNodes.size(); i++) {
655         SMDS_MeshEdge* ME = myHelper->AddEdge( tmpNodes[i-1], tmpNodes[i] );
656         if(ME) meshDS->SetMeshElementOnShape(ME, edgeID);
657       }
658       markEdgeAsComputedByMe( LinEdge1, aMesh.GetSubMesh( F ));
659     }
660   }
661   else // nbe==3 or ( nbe==2 && linEdge is INTERNAL )
662   {
663     if (nbe==2 && LinEdge1.Orientation() == TopAbs_INTERNAL )
664       LinEdge2 = LinEdge1;
665
666     // one curve must be a part of circle and other curves must be
667     // segments of line
668     double fp, lp;
669     Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge ));
670     Handle(Geom_Line)  aLine1 = Handle(Geom_Line)::DownCast( getCurve( LinEdge1 ));
671     Handle(Geom_Line)  aLine2 = Handle(Geom_Line)::DownCast( getCurve( LinEdge2 ));
672     if( aCirc.IsNull() || aLine1.IsNull() || aLine2.IsNull() )
673       return error(COMPERR_BAD_SHAPE);
674
675     if ( !algo1d->ComputeCircularEdge( aMesh, CircEdge ))
676       return error( algo1d->GetComputeError() );
677     map< double, const SMDS_MeshNode* > theNodes;
678     if ( !GetSortedNodesOnEdge(aMesh.GetMeshDS(),CircEdge,true,theNodes))
679       return error("Circular edge is incorrectly meshed");
680
681     const SMDS_MeshNode* NF = theNodes.begin()->second;
682     const SMDS_MeshNode* NL = theNodes.rbegin()->second;
683     CNodes.clear();
684     CNodes.push_back( NF );
685     map< double, const SMDS_MeshNode* >::iterator itn = theNodes.begin();
686     double fang = (*itn).first;
687     itn++;
688     for(; itn != theNodes.end(); itn++ ) {
689       CNodes.push_back( (*itn).second );
690       double ang = (*itn).first - fang;
691       if( ang>M_PI ) ang = ang - 2.*M_PI;
692       if( ang<-M_PI ) ang = ang + 2.*M_PI;
693       Angles.Append( ang );
694     }
695     P1 = gp_Pnt( NF->X(), NF->Y(), NF->Z() );
696     gp_Pnt P2( NL->X(), NL->Y(), NL->Z() );
697     P0 = aCirc->Location();
698
699     // make P1 belong to LinEdge1
700     TopoDS_Vertex V1 = myHelper->IthVertex( 0, LinEdge1 );
701     TopoDS_Vertex V2 = myHelper->IthVertex( 1, LinEdge1 );
702     gp_Pnt PE1 = BRep_Tool::Pnt(V1);
703     gp_Pnt PE2 = BRep_Tool::Pnt(V2);
704     if( ( P1.Distance(PE1) > Precision::Confusion() ) &&
705         ( P1.Distance(PE2) > Precision::Confusion() ) )
706       std::swap( LinEdge1, LinEdge2 );
707
708     bool linEdge1Computed, linEdge2Computed;
709     if ( !computeLayerPositions(P0,P1,LinEdge1,&linEdge1Computed))
710       return false;
711
712     Nodes1.resize( myLayerPositions.size()+1 );
713     Nodes2.resize( myLayerPositions.size()+1 );
714
715     // check that both linear edges have same hypotheses
716     if ( !computeLayerPositions(P0,P2,LinEdge2, &linEdge2Computed))
717          return false;
718     if ( Nodes1.size() != myLayerPositions.size()+1 )
719       return error("Different hypotheses apply to radial edges");
720
721     // find the central vertex
722     TopoDS_Vertex VC = V2;
723     if( ( P1.Distance(PE1) > Precision::Confusion() ) &&
724         ( P2.Distance(PE1) > Precision::Confusion() ) )
725       VC = V1;
726     int vertID = meshDS->ShapeToIndex(VC);
727
728     // LinEdge1
729     if ( linEdge1Computed )
730     {
731       if (!GetSortedNodesOnEdge(aMesh.GetMeshDS(),LinEdge1,true,theNodes))
732         return error("Invalid mesh on a straight edge");
733
734       bool nodesFromP0ToP1 = ( theNodes.rbegin()->second == NF );
735       NC = const_cast<SMDS_MeshNode*>
736         ( nodesFromP0ToP1 ? theNodes.begin()->second : theNodes.rbegin()->second );
737       int i = 0, ir = Nodes1.size()-1;
738       int * pi = nodesFromP0ToP1 ? &i : &ir;
739       itn = theNodes.begin();
740       if ( nodesFromP0ToP1 ) ++itn;
741       for ( ; i < Nodes1.size(); ++i, --ir, ++itn )
742       {
743         Nodes1[*pi] = itn->second;
744       }
745       for ( i = 0; i < Nodes1.size()-1; ++i )
746       {
747         Points.Append( gpXYZ( Nodes1[i]));
748         Pnts2d1.Append( myHelper->GetNodeUV( F, Nodes1[i]));
749       }
750     }
751     else
752     {
753       int edgeID = meshDS->ShapeToIndex(LinEdge1);
754       gp_Vec aVec(P0,P1);
755       // check orientation
756       Handle(Geom_Curve) Crv = BRep_Tool::Curve(LinEdge1,fp,lp);
757       gp_Pnt Ptmp = Crv->Value(fp);
758       bool ori = false;
759       if( P1.Distance(Ptmp) > Precision::Confusion() )
760         ori = true;
761       // get UV points for edge
762       gp_Pnt2d PF,PL;
763       BRep_Tool::UVPoints( LinEdge1, TopoDS::Face(aShape), PF, PL );
764       gp_Vec2d V2d;
765       if(ori) {
766         V2d = gp_Vec2d(PF,PL);
767         PC = PF;
768       }
769       else {
770         V2d = gp_Vec2d(PL,PF);
771         PC = PL;
772       }
773       NC = const_cast<SMDS_MeshNode*>( VertexNode( VC, meshDS ));
774       if ( !NC )
775       {
776         NC = meshDS->AddNode(P0.X(), P0.Y(), P0.Z());
777         meshDS->SetNodeOnVertex(NC, vertID);
778       }
779       double dp = lp-fp;
780       int i = 0;
781       for(; i<myLayerPositions.size(); i++) {
782         gp_Pnt P( P0.X() + aVec.X()*myLayerPositions[i],
783                   P0.Y() + aVec.Y()*myLayerPositions[i],
784                   P0.Z() + aVec.Z()*myLayerPositions[i] );
785         Points.Append(P);
786         SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
787         Nodes1[i] = node;
788         double param;
789         if(!ori)
790           param = fp + dp*(1-myLayerPositions[i]);
791         else
792           param = fp + dp*myLayerPositions[i];
793         meshDS->SetNodeOnEdge(node, edgeID, param);
794         // parameters on face
795         gp_Pnt2d P2d( PC.X() + V2d.X()*myLayerPositions[i],
796                       PC.Y() + V2d.Y()*myLayerPositions[i] );
797         Pnts2d1.Append(P2d);
798       }
799       Nodes1[ myLayerPositions.size() ] = NF;
800       // create 1D elements on edge
801       SMDS_MeshEdge* ME = myHelper->AddEdge( NC, Nodes1[0] );
802       if(ME) meshDS->SetMeshElementOnShape(ME, edgeID);
803       for(i=1; i<Nodes1.size(); i++) {
804         ME = myHelper->AddEdge( Nodes1[i-1], Nodes1[i] );
805         if(ME) meshDS->SetMeshElementOnShape(ME, edgeID);
806       }
807       if (nbe==2 && LinEdge1.Orientation() == TopAbs_INTERNAL )
808         Nodes2 = Nodes1;
809     }
810     markEdgeAsComputedByMe( LinEdge1, aMesh.GetSubMesh( F ));
811
812     // LinEdge2
813     if ( linEdge2Computed )
814     {
815       if (!GetSortedNodesOnEdge(aMesh.GetMeshDS(),LinEdge2,true,theNodes))
816         return error("Invalid mesh on a straight edge");
817
818       bool nodesFromP0ToP2 = ( theNodes.rbegin()->second == NL );
819       int i = 0, ir = Nodes1.size()-1;
820       int * pi = nodesFromP0ToP2 ? &i : &ir;
821       itn = theNodes.begin();
822       if ( nodesFromP0ToP2 ) ++itn;
823       for ( ; i < Nodes2.size(); ++i, --ir, ++itn )
824         Nodes2[*pi] = itn->second;
825     }
826     else
827     {
828       int edgeID = meshDS->ShapeToIndex(LinEdge2);
829       gp_Vec aVec = gp_Vec(P0,P2);
830       // check orientation
831       Handle(Geom_Curve) Crv = BRep_Tool::Curve(LinEdge2,fp,lp);
832       gp_Pnt Ptmp = Crv->Value(fp);
833       bool ori = false;
834       if( P2.Distance(Ptmp) > Precision::Confusion() )
835         ori = true;
836       // get UV points for edge
837       gp_Pnt2d PF,PL;
838       BRep_Tool::UVPoints( LinEdge2, TopoDS::Face(aShape), PF, PL );
839       gp_Vec2d V2d;
840       if(ori) {
841         V2d = gp_Vec2d(PF,PL);
842         PC = PF;
843       }
844       else {
845         V2d = gp_Vec2d(PL,PF);
846         PC = PL;
847       }
848       double dp = lp-fp;
849       for(int i=0; i<myLayerPositions.size(); i++) {
850         gp_Pnt P( P0.X() + aVec.X()*myLayerPositions[i],
851                   P0.Y() + aVec.Y()*myLayerPositions[i],
852                   P0.Z() + aVec.Z()*myLayerPositions[i] );
853         SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
854         Nodes2[i] = node;
855         double param;
856         if(!ori)
857           param = fp + dp*(1-myLayerPositions[i]);
858         else
859           param = fp + dp*myLayerPositions[i];
860         meshDS->SetNodeOnEdge(node, edgeID, param);
861         // parameters on face
862         gp_Pnt2d P2d( PC.X() + V2d.X()*myLayerPositions[i],
863                       PC.Y() + V2d.Y()*myLayerPositions[i] );
864       }
865       Nodes2[ myLayerPositions.size() ] = NL;
866       // create 1D elements on edge
867       SMDS_MeshEdge* ME = myHelper->AddEdge( NC, Nodes2[0] );
868       if(ME) meshDS->SetMeshElementOnShape(ME, edgeID);
869       for(int i=1; i<Nodes2.size(); i++) {
870         ME = myHelper->AddEdge( Nodes2[i-1], Nodes2[i] );
871         if(ME) meshDS->SetMeshElementOnShape(ME, edgeID);
872       }
873     }
874     markEdgeAsComputedByMe( LinEdge2, aMesh.GetSubMesh( F ));
875   }
876   markEdgeAsComputedByMe( CircEdge, aMesh.GetSubMesh( F ));
877
878   // orientation
879   bool IsForward = ( CircEdge.Orientation()==TopAbs_FORWARD );
880
881   // create nodes and mesh elements on face
882   // find axis of rotation
883   gp_Pnt P2 = gp_Pnt( CNodes[1]->X(), CNodes[1]->Y(), CNodes[1]->Z() );
884   gp_Vec Vec1(P0,P1);
885   gp_Vec Vec2(P0,P2);
886   gp_Vec Axis = Vec1.Crossed(Vec2);
887   // create elements
888   int i = 1;
889   //cout<<"Angles.Length() = "<<Angles.Length()<<"   Points.Length() = "<<Points.Length()<<endl;
890   //cout<<"Nodes1.size() = "<<Nodes1.size()<<"   Pnts2d1.Length() = "<<Pnts2d1.Length()<<endl;
891   for(; i<Angles.Length(); i++) {
892     vector< const SMDS_MeshNode* > tmpNodes;
893     tmpNodes.reserve(Nodes1.size());
894     gp_Trsf aTrsf;
895     gp_Ax1 theAxis(P0,gp_Dir(Axis));
896     aTrsf.SetRotation( theAxis, Angles.Value(i) );
897     gp_Trsf2d aTrsf2d;
898     aTrsf2d.SetRotation( PC, Angles.Value(i) );
899     // create nodes
900     int j = 1;
901     for(; j<=Points.Length(); j++) {
902       double cx,cy,cz;
903       Points.Value(j).Coord( cx, cy, cz );
904       aTrsf.Transforms( cx, cy, cz );
905       SMDS_MeshNode* node = myHelper->AddNode( cx, cy, cz );
906       // find parameters on face
907       Pnts2d1.Value(j).Coord( cx, cy );
908       aTrsf2d.Transforms( cx, cy );
909       // set node on face
910       meshDS->SetNodeOnFace( node, faceID, cx, cy );
911       tmpNodes[j-1] = node;
912     }
913     // create faces
914     tmpNodes[Points.Length()] = CNodes[i];
915     // quad
916     for(j=0; j<Nodes1.size()-1; j++) {
917       SMDS_MeshFace* MF;
918       if(IsForward)
919         MF = myHelper->AddFace( tmpNodes[j], Nodes1[j],
920                                 Nodes1[j+1], tmpNodes[j+1] );
921       else
922         MF = myHelper->AddFace( tmpNodes[j], tmpNodes[j+1],
923                                 Nodes1[j+1], Nodes1[j] );
924       if(MF) meshDS->SetMeshElementOnShape(MF, faceID);
925     }
926     // tria
927     SMDS_MeshFace* MF;
928     if(IsForward)
929       MF = myHelper->AddFace( NC, Nodes1[0], tmpNodes[0] );
930     else
931       MF = myHelper->AddFace( NC, tmpNodes[0], Nodes1[0] );
932     if(MF) meshDS->SetMeshElementOnShape(MF, faceID);
933     for(j=0; j<Nodes1.size(); j++) {
934       Nodes1[j] = tmpNodes[j];
935     }
936   }
937   // create last faces
938   // quad
939   for(i=0; i<Nodes1.size()-1; i++) {
940     SMDS_MeshFace* MF;
941     if(IsForward)
942       MF = myHelper->AddFace( Nodes2[i], Nodes1[i],
943                               Nodes1[i+1], Nodes2[i+1] );
944     else
945       MF = myHelper->AddFace( Nodes2[i],  Nodes2[i+1],
946                               Nodes1[i+1], Nodes1[i] );
947     if(MF) meshDS->SetMeshElementOnShape(MF, faceID);
948   }
949   // tria
950   SMDS_MeshFace* MF;
951   if(IsForward)
952     MF = myHelper->AddFace( NC, Nodes1[0], Nodes2[0] );
953   else
954     MF = myHelper->AddFace( NC, Nodes2[0], Nodes1[0] );
955   if(MF) meshDS->SetMeshElementOnShape(MF, faceID);
956
957   return true;
958 }
959
960 //================================================================================
961 /*!
962  * \brief Compute positions of nodes on the radial edge
963   * \retval bool - is a success
964  */
965 //================================================================================
966
967 bool StdMeshers_RadialQuadrangle_1D2D::computeLayerPositions(const gp_Pnt&      p1,
968                                                              const gp_Pnt&      p2,
969                                                              const TopoDS_Edge& linEdge,
970                                                              bool*              linEdgeComputed)
971 {
972   // First, try to compute positions of layers
973
974   myLayerPositions.clear();
975
976   SMESH_Mesh * mesh = myHelper->GetMesh();
977
978   const SMESH_Hypothesis* hyp1D = myDistributionHypo ? myDistributionHypo->GetLayerDistribution() : 0;
979   int                  nbLayers = myNbLayerHypo ? myNbLayerHypo->GetNumberOfLayers() : 0;
980
981   if ( !hyp1D && !nbLayers )
982   {
983     // No own algo hypotheses assigned, so first try to find any 1D hypothesis.
984     // We need some edge
985     TopoDS_Shape edge = linEdge;
986     if ( edge.IsNull() && !myHelper->GetSubShape().IsNull())
987       for ( TopExp_Explorer e(myHelper->GetSubShape(), TopAbs_EDGE); e.More(); e.Next())
988         edge = e.Current();
989     if ( !edge.IsNull() )
990     {
991       // find a hyp usable by TNodeDistributor
992       SMESH_HypoFilter hypKind;
993       TNodeDistributor::GetDistributor(*mesh)->InitCompatibleHypoFilter(hypKind,/*ignoreAux=*/1);
994       hyp1D = mesh->GetHypothesis( edge, hypKind, /*fromAncestors=*/true);
995     }
996   }
997   if ( hyp1D ) // try to compute with hyp1D
998   {
999     if ( !TNodeDistributor::GetDistributor(*mesh)->Compute( myLayerPositions,p1,p2,*mesh,hyp1D )) {
1000       if ( myDistributionHypo ) { // bad hyp assigned 
1001         return error( TNodeDistributor::GetDistributor(*mesh)->GetComputeError() );
1002       }
1003       else {
1004         // bad hyp found, its Ok, lets try with default nb of segnents
1005       }
1006     }
1007   }
1008   
1009   if ( myLayerPositions.empty() ) // try to use nb of layers
1010   {
1011     if ( !nbLayers )
1012       nbLayers = _gen->GetDefaultNbSegments();
1013
1014     if ( nbLayers )
1015     {
1016       myLayerPositions.resize( nbLayers - 1 );
1017       for ( int z = 1; z < nbLayers; ++z )
1018         myLayerPositions[ z - 1 ] = double( z )/ double( nbLayers );
1019     }
1020   }
1021
1022   // Second, check presence of a mesh built by other algo on linEdge
1023   // and mesh conformity to my hypothesis
1024
1025   bool meshComputed = (!linEdge.IsNull() && !mesh->GetSubMesh(linEdge)->IsEmpty() );
1026   if ( linEdgeComputed ) *linEdgeComputed = meshComputed;
1027
1028   if ( meshComputed )
1029   {
1030     vector< double > nodeParams;
1031     GetNodeParamOnEdge( mesh->GetMeshDS(), linEdge, nodeParams );
1032
1033     // nb of present nodes must be different in cases of 1 and 2 straight edges
1034
1035     TopoDS_Vertex VV[2];
1036     TopExp::Vertices( linEdge, VV[0], VV[1]);
1037     const gp_Pnt* points[] = { &p1, &p2 };
1038     gp_Pnt       vPoints[] = { BRep_Tool::Pnt(VV[0]), BRep_Tool::Pnt(VV[1]) };
1039     const double     tol[] = { BRep_Tool::Tolerance(VV[0]), BRep_Tool::Tolerance(VV[1]) };
1040     bool pointsAreOnVertices = true;
1041     for ( int iP = 0; iP < 2 && pointsAreOnVertices; ++iP )
1042       pointsAreOnVertices = ( points[iP]->Distance( vPoints[0] ) < tol[0] ||
1043                               points[iP]->Distance( vPoints[1] ) < tol[1] );
1044
1045     int nbNodes = nodeParams.size() - 2; // 2 straight edges
1046     if ( !pointsAreOnVertices )
1047       nbNodes = ( nodeParams.size() - 3 ) / 2; // 1 straight edge
1048
1049     if ( myLayerPositions.empty() )
1050     {
1051       myLayerPositions.resize( nbNodes );
1052     }
1053     else if ( myDistributionHypo || myNbLayerHypo )
1054     {
1055       // linEdge is computed by other algo. Check if there is a meshed face
1056       // using nodes on linEdge
1057       bool nodesAreUsed = false;
1058       TopTools_ListIteratorOfListOfShape ancestIt = mesh->GetAncestors( linEdge );
1059       for ( ; ancestIt.More() && !nodesAreUsed; ancestIt.Next() )
1060         if ( ancestIt.Value().ShapeType() == TopAbs_FACE )
1061           nodesAreUsed = (!mesh->GetSubMesh( ancestIt.Value() )->IsEmpty());
1062       if ( !nodesAreUsed ) {
1063         // rebuild them
1064         mesh->GetSubMesh( linEdge )->ComputeStateEngine( SMESH_subMesh::CLEAN );
1065         if ( linEdgeComputed ) *linEdgeComputed = false;
1066       }
1067       else {
1068         
1069         if ( myLayerPositions.size() != nbNodes )
1070           return error("Radial edge is meshed by other algorithm");
1071       }
1072     }
1073   }
1074
1075   return !myLayerPositions.empty();
1076 }
1077
1078
1079 //=======================================================================
1080 //function : Evaluate
1081 //purpose  : 
1082 //=======================================================================
1083
1084 bool StdMeshers_RadialQuadrangle_1D2D::Evaluate(SMESH_Mesh& aMesh,
1085                                                 const TopoDS_Shape& aShape,
1086                                                 MapShapeNbElems& aResMap)
1087 {
1088   if( aShape.ShapeType() != TopAbs_FACE ) {
1089     return false;
1090   }
1091   SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);
1092   if( aResMap.count(sm) )
1093     return false;
1094
1095   vector<int>& aResVec =
1096     aResMap.insert( make_pair(sm, vector<int>(SMDSEntity_Last,0))).first->second;
1097
1098   myHelper = new SMESH_MesherHelper( aMesh );
1099   myHelper->SetSubShape( aShape );
1100   auto_ptr<SMESH_MesherHelper> helperDeleter( myHelper );
1101
1102   TNodeDistributor* algo1d = TNodeDistributor::GetDistributor(aMesh);
1103
1104   TopoDS_Edge CircEdge, LinEdge1, LinEdge2;
1105   int nbe = analyseFace( aShape, CircEdge, LinEdge1, LinEdge2 );
1106   if( nbe>3 || nbe < 1 || CircEdge.IsNull() )
1107     return false;
1108
1109   Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge ));
1110   if( aCirc.IsNull() )
1111     return error(COMPERR_BAD_SHAPE);
1112
1113   gp_Pnt P0 = aCirc->Location();
1114   gp_Pnt P1 = aCirc->Value(0.);
1115   computeLayerPositions( P0, P1, LinEdge1 );
1116
1117   int nb0d=0, nb2d_tria=0, nb2d_quad=0;
1118   bool isQuadratic = false, ok = true;
1119   if(nbe==1)
1120   {
1121     // C1 must be a circle
1122     ok = algo1d->EvaluateCircularEdge( aMesh, CircEdge, aResMap );
1123     if(ok) {
1124       const vector<int>& aVec = aResMap[aMesh.GetSubMesh(CircEdge)];
1125       isQuadratic = aVec[SMDSEntity_Quad_Edge]>aVec[SMDSEntity_Edge];
1126       if(isQuadratic) {
1127         // main nodes
1128         nb0d = (aVec[SMDSEntity_Node]+1) * myLayerPositions.size();
1129         // radial medium nodes
1130         nb0d += (aVec[SMDSEntity_Node]+1) * (myLayerPositions.size()+1);
1131         // other medium nodes
1132         nb0d += (aVec[SMDSEntity_Node]+1) * myLayerPositions.size();
1133       }
1134       else {
1135         nb0d = (aVec[SMDSEntity_Node]+1) * myLayerPositions.size();
1136       }
1137       nb2d_tria = aVec[SMDSEntity_Node] + 1;
1138       nb2d_quad = nb0d;
1139     }
1140   }
1141   else if(nbe==2 && LinEdge1.Orientation() != TopAbs_INTERNAL)
1142   {
1143     // one curve must be a half of circle and other curve must be
1144     // a segment of line
1145     double fp, lp;
1146     Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge, &fp, &lp ));
1147     if( fabs(fabs(lp-fp)-M_PI) > Precision::Confusion() ) {
1148       // not half of circle
1149       return error(COMPERR_BAD_SHAPE);
1150     }
1151     Handle(Geom_Line) aLine = Handle(Geom_Line)::DownCast( getCurve( LinEdge1 ));
1152     if( aLine.IsNull() ) {
1153       // other curve not line
1154       return error(COMPERR_BAD_SHAPE);
1155     }
1156     ok = !aResMap.count( aMesh.GetSubMesh(LinEdge1) );
1157     if ( !ok ) {
1158       const vector<int>& aVec = aResMap[ aMesh.GetSubMesh(LinEdge1) ];
1159       ok = ( aVec[SMDSEntity_Node] == myLayerPositions.size() );
1160     }
1161     if(ok) {
1162       ok = algo1d->EvaluateCircularEdge( aMesh, CircEdge, aResMap );
1163     }
1164     if(ok) {
1165       const vector<int>& aVec = aResMap[ aMesh.GetSubMesh(CircEdge) ];
1166       isQuadratic = aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge];
1167       if(isQuadratic) {
1168         // main nodes
1169         nb0d = aVec[SMDSEntity_Node] * myLayerPositions.size();
1170         // radial medium nodes
1171         nb0d += aVec[SMDSEntity_Node] * (myLayerPositions.size()+1);
1172         // other medium nodes
1173         nb0d += (aVec[SMDSEntity_Node]+1) * myLayerPositions.size();
1174       }
1175       else {
1176         nb0d = aVec[SMDSEntity_Node] * myLayerPositions.size();
1177       }
1178       nb2d_tria = aVec[SMDSEntity_Node] + 1;
1179       nb2d_quad = nb2d_tria * myLayerPositions.size();
1180       // add evaluation for edges
1181       vector<int> aResVec(SMDSEntity_Last,0);
1182       if(isQuadratic) {
1183         aResVec[SMDSEntity_Node] = 4*myLayerPositions.size() + 3;
1184         aResVec[SMDSEntity_Quad_Edge] = 2*myLayerPositions.size() + 2;
1185       }
1186       else {
1187         aResVec[SMDSEntity_Node] = 2*myLayerPositions.size() + 1;
1188         aResVec[SMDSEntity_Edge] = 2*myLayerPositions.size() + 2;
1189       }
1190       aResMap[ aMesh.GetSubMesh(LinEdge1) ] = aResVec;
1191     }
1192   }
1193   else  // nbe==3 or ( nbe==2 && linEdge is INTERNAL )
1194   {
1195     if (nbe==2 && LinEdge1.Orientation() == TopAbs_INTERNAL )
1196       LinEdge2 = LinEdge1;
1197
1198     // one curve must be a part of circle and other curves must be
1199     // segments of line
1200     Handle(Geom_Line)  aLine1 = Handle(Geom_Line)::DownCast( getCurve( LinEdge1 ));
1201     Handle(Geom_Line)  aLine2 = Handle(Geom_Line)::DownCast( getCurve( LinEdge2 ));
1202     if( aLine1.IsNull() || aLine2.IsNull() ) {
1203       // other curve not line
1204       return error(COMPERR_BAD_SHAPE);
1205     }
1206     int nbLayers = myLayerPositions.size();
1207     computeLayerPositions( P0, P1, LinEdge2 );
1208     if ( nbLayers != myLayerPositions.size() )
1209       return error("Different hypotheses apply to radial edges");
1210       
1211     bool ok = !aResMap.count( aMesh.GetSubMesh(LinEdge1));
1212     if ( !ok ) {
1213       if ( myDistributionHypo || myNbLayerHypo )
1214         ok = true; // override other 1d hyps
1215       else {
1216         const vector<int>& aVec = aResMap[ aMesh.GetSubMesh(LinEdge1) ];
1217         ok = ( aVec[SMDSEntity_Node] == myLayerPositions.size() );
1218       }
1219     }
1220     if( ok && aResMap.count( aMesh.GetSubMesh(LinEdge2) )) {
1221       if ( myDistributionHypo || myNbLayerHypo )
1222         ok = true; // override other 1d hyps
1223       else {
1224         const vector<int>& aVec = aResMap[ aMesh.GetSubMesh(LinEdge2) ];
1225         ok = ( aVec[SMDSEntity_Node] == myLayerPositions.size() );
1226       }
1227     }
1228     if(ok) {
1229       ok = algo1d->EvaluateCircularEdge( aMesh, CircEdge, aResMap );
1230     }
1231     if(ok) {
1232       const vector<int>& aVec = aResMap[ aMesh.GetSubMesh(CircEdge) ];
1233       isQuadratic = aVec[SMDSEntity_Quad_Edge]>aVec[SMDSEntity_Edge];
1234       if(isQuadratic) {
1235         // main nodes
1236         nb0d = aVec[SMDSEntity_Node] * myLayerPositions.size();
1237         // radial medium nodes
1238         nb0d += aVec[SMDSEntity_Node] * (myLayerPositions.size()+1);
1239         // other medium nodes
1240         nb0d += (aVec[SMDSEntity_Node]+1) * myLayerPositions.size();
1241       }
1242       else {
1243         nb0d = aVec[SMDSEntity_Node] * myLayerPositions.size();
1244       }
1245       nb2d_tria = aVec[SMDSEntity_Node] + 1;
1246       nb2d_quad = nb2d_tria * myLayerPositions.size();
1247       // add evaluation for edges
1248       vector<int> aResVec(SMDSEntity_Last, 0);
1249       if(isQuadratic) {
1250         aResVec[SMDSEntity_Node] = 2*myLayerPositions.size() + 1;
1251         aResVec[SMDSEntity_Quad_Edge] = myLayerPositions.size() + 1;
1252       }
1253       else {
1254         aResVec[SMDSEntity_Node] = myLayerPositions.size();
1255         aResVec[SMDSEntity_Edge] = myLayerPositions.size() + 1;
1256       }
1257       sm = aMesh.GetSubMesh(LinEdge1);
1258       aResMap[sm] = aResVec;
1259       sm = aMesh.GetSubMesh(LinEdge2);
1260       aResMap[sm] = aResVec;
1261     }
1262   }
1263
1264   if(nb0d>0) {
1265     aResVec[0] = nb0d;
1266     if(isQuadratic) {
1267       aResVec[SMDSEntity_Quad_Triangle] = nb2d_tria;
1268       aResVec[SMDSEntity_Quad_Quadrangle] = nb2d_quad;
1269     }
1270     else {
1271       aResVec[SMDSEntity_Triangle] = nb2d_tria;
1272       aResVec[SMDSEntity_Quadrangle] = nb2d_quad;
1273     }
1274     return true;
1275   }
1276
1277   // invalid case
1278   sm = aMesh.GetSubMesh(aShape);
1279   SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
1280   smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,
1281                                         "Submesh can not be evaluated",this));
1282   return false;
1283
1284 }