Salome HOME
Fix compilation problems on Mandriva64 and Mandriva
[modules/smesh.git] / src / StdMeshers / StdMeshers_ProjectionUtils.cxx
1 //  SMESH SMESH : idl implementation based on 'SMESH' unit's calsses
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_ProjectionUtils.cxx
25 // Created   : Fri Oct 27 10:24:28 2006
26 // Author    : Edward AGAPOV (eap)
27
28
29 #include "StdMeshers_ProjectionUtils.hxx"
30
31 #include "StdMeshers_ProjectionSource1D.hxx"
32 #include "StdMeshers_ProjectionSource2D.hxx"
33 #include "StdMeshers_ProjectionSource3D.hxx"
34
35 #include "SMESH_Algo.hxx"
36 #include "SMESH_Block.hxx"
37 #include "SMESH_Gen.hxx"
38 #include "SMESH_Hypothesis.hxx"
39 #include "SMESH_IndexedDataMapOfShapeIndexedMapOfShape.hxx"
40 #include "SMESH_Mesh.hxx"
41 #include "SMESH_MeshEditor.hxx"
42 #include "SMESH_subMesh.hxx"
43 #include "SMESH_subMeshEventListener.hxx"
44 #include "SMDS_EdgePosition.hxx"
45
46 #include "utilities.h"
47
48 #include <BRepAdaptor_Curve.hxx>
49 #include <BRepTools.hxx>
50 #include <BRepTools_WireExplorer.hxx>
51 #include <BRep_Tool.hxx>
52 #include <Bnd_Box.hxx>
53 #include <TopAbs.hxx>
54 #include <TopTools_Array1OfShape.hxx>
55 #include <TopTools_DataMapOfShapeShape.hxx>
56 #include <TopTools_ListIteratorOfListOfShape.hxx>
57 #include <TopTools_ListOfShape.hxx>
58 #include <TopTools_MapOfShape.hxx>
59 #include <TopoDS_Shape.hxx>
60 #include <gp_Ax3.hxx>
61 #include <gp_Pnt.hxx>
62 #include <gp_Trsf.hxx>
63 #include <gp_Vec.hxx>
64
65
66 #define RETURN_BAD_RESULT(msg) { MESSAGE(msg); return false; }
67 #define SHOW_VERTEX(v,msg) // { \
68 //  if ( v.IsNull() ) cout << msg << " NULL SHAPE" << endl; \
69 // else if (v.ShapeType() == TopAbs_VERTEX) {\
70 //   gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( v ));\
71 //   cout << msg << (v).TShape().operator->()<<" ( " <<p.X()<<", "<<p.Y()<<", "<<p.Z()<<" )"<<endl;}\
72 // else {\
73 // cout << msg << " "; TopAbs::Print(v.ShapeType(),cout) <<" "<<(v).TShape().operator->()<<endl;}\
74 // }
75 #define SHOW_LIST(msg,l) \
76 // { \
77 //     cout << msg << " ";\
78 //     list< TopoDS_Edge >::const_iterator e = l.begin();\
79 //     for ( int i = 0; e != l.end(); ++e, ++i ) {\
80 //       cout << i << "V (" << TopExp::FirstVertex( *e, true ).TShape().operator->() << ") "\
81 //            << i << "E (" << e->TShape().operator->() << "); "; }\
82 //     cout << endl;\
83 //   }
84
85 namespace {
86   //================================================================================
87   /*!
88    * \brief Reverse order of edges in a list and their orientation
89     * \param edges - list of edges to reverse
90     * \param nbEdges - number of edges to reverse
91    */
92   //================================================================================
93
94   void Reverse( list< TopoDS_Edge > & edges, const int nbEdges )
95   {
96     SHOW_LIST("BEFORE REVERSE", edges);
97
98     list< TopoDS_Edge >::iterator eIt = edges.begin();
99     if ( edges.size() == nbEdges )
100     {
101       edges.reverse();
102     }
103     else  // reverse only the given nb of edges
104     {
105       // look for the last edge to be reversed
106       list< TopoDS_Edge >::iterator eBackIt = edges.begin();
107       for ( int i = 1; i < nbEdges; ++i )
108         ++eBackIt;
109       // reverse
110       while ( eIt != eBackIt ) {
111         std::swap( *eIt, *eBackIt );
112         SHOW_LIST("# AFTER SWAP", edges)
113         if ( (++eIt) != eBackIt )
114           --eBackIt;
115       }
116     }
117     for ( eIt = edges.begin(); eIt != edges.end(); ++eIt )
118       eIt->Reverse();
119     SHOW_LIST("ATFER REVERSE", edges)
120   }
121
122   //================================================================================
123   /*!
124    * \brief Check if propagation is possible
125     * \param theMesh1 - source mesh
126     * \param theMesh2 - target mesh
127     * \retval bool - true if possible
128    */
129   //================================================================================
130
131   bool IsPropagationPossible( SMESH_Mesh* theMesh1, SMESH_Mesh* theMesh2 )
132   {
133     if ( theMesh1 != theMesh2 ) {
134       TopoDS_Shape mainShape1 = theMesh1->GetMeshDS()->ShapeToMesh();
135       TopoDS_Shape mainShape2 = theMesh2->GetMeshDS()->ShapeToMesh();
136       return mainShape1.IsSame( mainShape2 );
137     }
138     return true;
139   }
140
141   //================================================================================
142   /*!
143    * \brief Fix up association of edges in faces by possible propagation
144     * \param nbEdges - nb of edges in an outer wire
145     * \param edges1 - edges of one face
146     * \param edges2 - matching edges of another face
147     * \param theMesh1 - mesh 1
148     * \param theMesh2 - mesh 2
149    */
150   //================================================================================
151
152   void FixAssocByPropagation( const int             nbEdges,
153                               list< TopoDS_Edge > & edges1,
154                               list< TopoDS_Edge > & edges2,
155                               SMESH_Mesh*           theMesh1,
156                               SMESH_Mesh*           theMesh2)
157   {
158     if ( nbEdges == 2 && IsPropagationPossible( theMesh1, theMesh2 ) )
159     {
160       list< TopoDS_Edge >::iterator eIt2 = ++edges2.begin(); // 2nd edge of the 2nd face
161       TopoDS_Edge edge2 =
162         StdMeshers_ProjectionUtils::GetPropagationEdge( theMesh1, *eIt2, edges1.front() );
163       if ( !edge2.IsNull() ) // propagation found for the second edge
164         Reverse( edges2, nbEdges );
165     }
166   }
167 }
168
169 //=======================================================================
170 /*!
171  * \brief Looks for association of all subshapes of two shapes
172  * \param theShape1 - shape 1
173  * \param theMesh1 - mesh built on shape 1
174  * \param theShape2 - shape 2
175  * \param theMesh2 - mesh built on shape 2
176  * \param theAssociation - association map to be filled that may
177  *                         contain association of one or two pairs of vertices
178  * \retval bool - true if association found
179  */
180 //=======================================================================
181
182 bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& theShape1,
183                                                          SMESH_Mesh*         theMesh1,
184                                                          const TopoDS_Shape& theShape2,
185                                                          SMESH_Mesh*         theMesh2,
186                                                          TShapeShapeMap &    theMap)
187 {
188   if ( theShape1.ShapeType() != theShape2.ShapeType() )
189     RETURN_BAD_RESULT("Different shape types");
190
191   bool bidirect = ( !theShape1.IsSame( theShape2 ));
192   if ( !theMap.IsEmpty())
193   {
194     switch ( theShape1.ShapeType() ) {
195
196     case TopAbs_EDGE: {
197       // ----------------------------------------------------------------------
198       if ( theMap.Extent() != 2 )
199         RETURN_BAD_RESULT("Wrong map extent " << theMap.Extent() );
200       TopoDS_Edge edge1 = TopoDS::Edge( theShape1 );
201       TopoDS_Edge edge2 = TopoDS::Edge( theShape2 );
202       TopoDS_Vertex VV1[2], VV2[2];
203       TopExp::Vertices( edge1, VV1[0], VV1[1] );
204       TopExp::Vertices( edge2, VV2[0], VV2[1] );
205       int i1 = 0, i2 = 0;
206       if ( theMap.IsBound( VV1[ i1 ] )) i1 = 1;
207       if ( theMap.IsBound( VV2[ i2 ] )) i2 = 1;
208       InsertAssociation( VV1[ i1 ], VV2[ i2 ], theMap, bidirect);
209       return true;
210     }
211
212     case TopAbs_FACE: {
213       // ----------------------------------------------------------------------
214       TopoDS_Face face1 = TopoDS::Face( theShape1 );
215       TopoDS_Face face2 = TopoDS::Face( theShape2 );
216
217       TopoDS_Vertex VV1[2], VV2[2];
218       // find a not closed edge of face1 both vertices of which are associated
219       int nbEdges = 0;
220       TopExp_Explorer exp ( face1, TopAbs_EDGE );
221       for ( ; VV2[ 1 ].IsNull() && exp.More(); exp.Next(), ++nbEdges ) {
222         TopExp::Vertices( TopoDS::Edge( exp.Current() ), VV1[0], VV1[1] );
223         if ( theMap.IsBound( VV1[0] ) ) {
224           VV2[ 0 ] = TopoDS::Vertex( theMap( VV1[0] ));
225           if ( theMap.IsBound( VV1[1] ) && !VV1[0].IsSame( VV1[1] ))
226             VV2[ 1 ] = TopoDS::Vertex( theMap( VV1[1] ));
227         }
228       }
229       if ( VV2[ 1 ].IsNull() ) { // 2 bound vertices not found
230         if ( nbEdges > 1 ) {
231           RETURN_BAD_RESULT("2 bound vertices not found" );
232         } else {
233           VV2[ 1 ] = VV2[ 0 ];
234         }
235       }
236       list< TopoDS_Edge > edges1, edges2;
237       int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2 );
238       if ( !nbE ) RETURN_BAD_RESULT("FindFaceAssociation() failed");
239       FixAssocByPropagation( nbE, edges1, edges2, theMesh1, theMesh2 );
240
241       list< TopoDS_Edge >::iterator eIt1 = edges1.begin();
242       list< TopoDS_Edge >::iterator eIt2 = edges2.begin();
243       for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 )
244       {
245         InsertAssociation( *eIt1, *eIt2, theMap, bidirect);
246         VV1[0] = TopExp::FirstVertex( *eIt1, true );
247         VV2[0] = TopExp::FirstVertex( *eIt2, true );
248         InsertAssociation( VV1[0], VV2[0], theMap, bidirect);
249       }
250       return true;
251     }
252
253     case TopAbs_SHELL:
254     case TopAbs_SOLID: {
255       // ----------------------------------------------------------------------
256       TopoDS_Vertex VV1[2], VV2[2];
257       // find a not closed edge of shape1 both vertices of which are associated
258       TopoDS_Edge edge1;
259       TopExp_Explorer exp ( theShape1, TopAbs_EDGE );
260       for ( ; VV2[ 1 ].IsNull() && exp.More(); exp.Next() ) {
261         edge1 = TopoDS::Edge( exp.Current() );
262         TopExp::Vertices( edge1 , VV1[0], VV1[1] );
263         if ( theMap.IsBound( VV1[0] )) {
264           VV2[ 0 ] = TopoDS::Vertex( theMap( VV1[0] ));
265           if ( theMap.IsBound( VV1[1] ) && !VV1[0].IsSame( VV1[1] ))
266             VV2[ 1 ] = TopoDS::Vertex( theMap( VV1[1] ));
267         }
268       }
269       if ( VV2[ 1 ].IsNull() ) // 2 bound vertices not found
270         RETURN_BAD_RESULT("2 bound vertices not found" );
271       TopoDS_Edge edge2 = GetEdgeByVertices( theMesh2, VV2[ 0 ], VV2[ 1 ]);
272       if ( edge2.IsNull() )
273         RETURN_BAD_RESULT("GetEdgeByVertices() failed");
274
275       // get a face sharing edge1
276       TopoDS_Shape F1, F2, FF2[2];
277       TopTools_ListIteratorOfListOfShape ancestIt = theMesh1->GetAncestors( edge1 );
278       for ( ; F1.IsNull() && ancestIt.More(); ancestIt.Next() )
279         if ( ancestIt.Value().ShapeType() == TopAbs_FACE )
280           F1 = ancestIt.Value().Oriented( TopAbs_FORWARD );
281       if ( F1.IsNull() )
282         RETURN_BAD_RESULT(" Face1 not found");
283
284       // get 2 faces sharing edge2
285       ancestIt = theMesh2->GetAncestors( edge2 );
286       for ( int i = 0; FF2[1].IsNull() && ancestIt.More(); ancestIt.Next() )
287         if ( ancestIt.Value().ShapeType() == TopAbs_FACE )
288           FF2[ i++ ] = ancestIt.Value().Oriented( TopAbs_FORWARD );
289       if ( FF2[1].IsNull() )
290         RETURN_BAD_RESULT("2 faces not found");
291
292       // get oriented edge1 and edge2 from F1 and FF2[0]
293       for ( exp.Init( F1, TopAbs_EDGE ); exp.More(); exp.Next() )
294         if ( edge1.IsSame( exp.Current() )) {
295           edge1 = TopoDS::Edge( exp.Current() );
296           break;
297         }
298       
299       for ( exp.Init( FF2[ 0 ], TopAbs_EDGE ); exp.More(); exp.Next() )
300         if ( edge2.IsSame( exp.Current() )) {
301           edge2 = TopoDS::Edge( exp.Current() );
302           break;
303         }
304
305       // compare first vertices of edge1 and edge2
306       TopExp::Vertices( edge1, VV1[0], VV1[1], true );
307       TopExp::Vertices( edge2, VV2[0], VV2[1], true );
308       F2 = FF2[ 0 ];
309       if ( !VV1[ 0 ].IsSame( theMap( VV2[ 0 ]))) {
310         F2 = FF2[ 1 ];
311         edge2.Reverse();
312       }
313
314       TopTools_MapOfShape boundEdges; 
315
316       // association of face subshapes and neighbour faces
317       list< pair < TopoDS_Face, TopoDS_Edge > > FE1, FE2;
318       list< pair < TopoDS_Face, TopoDS_Edge > >::iterator fe1, fe2;
319       FE1.push_back( make_pair( TopoDS::Face( F1 ), edge1 ));
320       FE2.push_back( make_pair( TopoDS::Face( F2 ), edge2 ));
321       for ( fe1 = FE1.begin(), fe2 = FE2.begin(); fe1 != FE1.end(); ++fe1, ++fe2 )
322       {
323         const TopoDS_Face& face1 = fe1->first;
324         if ( theMap.IsBound( face1 ) ) continue;
325         const TopoDS_Face& face2 = fe2->first;
326         edge1 = fe1->second;
327         edge2 = fe2->second;
328         TopExp::Vertices( edge1, VV1[0], VV1[1], true );
329         TopExp::Vertices( edge2, VV2[0], VV2[1], true );
330         list< TopoDS_Edge > edges1, edges2;
331         int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2 );
332         if ( !nbE ) RETURN_BAD_RESULT("FindFaceAssociation() failed");
333         FixAssocByPropagation( nbE, edges1, edges2, theMesh1, theMesh2 );
334         
335         InsertAssociation( face1, face2, theMap, bidirect); // assoc faces
336         list< TopoDS_Edge >::iterator eIt1 = edges1.begin();
337         list< TopoDS_Edge >::iterator eIt2 = edges2.begin();
338         for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 )
339         {
340           if ( !boundEdges.Add( *eIt1 )) continue; // already associated
341           InsertAssociation( *eIt1, *eIt2, theMap, bidirect);  // assoc edges
342           VV1[0] = TopExp::FirstVertex( *eIt1, true );
343           VV2[0] = TopExp::FirstVertex( *eIt2, true );
344           InsertAssociation( VV1[0], VV2[0], theMap, bidirect); // assoc vertices
345
346           // add adjacent faces to process
347           TopoDS_Face nextFace1 = GetNextFace( theMesh1, *eIt1, face1 );
348           TopoDS_Face nextFace2 = GetNextFace( theMesh2, *eIt2, face2 );
349           if ( !nextFace1.IsNull() && !nextFace2.IsNull() ) {
350             FE1.push_back( make_pair( nextFace1, *eIt1 ));
351             FE2.push_back( make_pair( nextFace2, *eIt2 ));
352           }
353         }
354       }
355       return true;
356     }
357     default:
358       RETURN_BAD_RESULT("Unexpected shape type");
359
360     } // end switch by shape type
361   } // end case of available initial vertex association
362
363   //----------------------------------------------------------------------
364   // NO INITIAL VERTEX ASSOCIATION
365   //----------------------------------------------------------------------
366
367   switch ( theShape1.ShapeType() ) {
368
369   case TopAbs_EDGE: {
370     // ----------------------------------------------------------------------
371     TopoDS_Edge edge1 = TopoDS::Edge( theShape1 );
372     TopoDS_Edge edge2 = TopoDS::Edge( theShape2 );
373     if ( IsPropagationPossible( theMesh1, theMesh2 ))
374     {
375       TopoDS_Edge prpEdge = GetPropagationEdge( theMesh1, edge2, edge1 );
376       if ( !prpEdge.IsNull() )
377       {
378         TopoDS_Vertex VV1[2], VV2[2];
379         TopExp::Vertices( edge1,   VV1[0], VV1[1], true );
380         TopExp::Vertices( prpEdge, VV2[0], VV2[1], true );
381         InsertAssociation( VV1[ 0 ], VV2[ 0 ], theMap, bidirect);
382         InsertAssociation( VV1[ 1 ], VV2[ 1 ], theMap, bidirect);
383         if ( VV1[0].IsSame( VV1[1] ) || // one of edges is closed
384              VV2[0].IsSame( VV2[1] ) )
385         {
386           InsertAssociation( edge1, prpEdge, theMap, bidirect); // insert with a proper orientation
387         }
388         return true; // done
389       }
390     }
391     if ( IsClosedEdge( edge1 ) && IsClosedEdge( edge2 ))
392     {
393       // TODO: find out a proper orientation (is it possible?)
394       InsertAssociation( edge1, edge2, theMap, bidirect); // insert with a proper orientation
395       InsertAssociation( TopExp::FirstVertex(edge1), TopExp::FirstVertex(edge2),
396                          theMap, bidirect);
397       return true; // done
398     }
399     break; // try by vertex closeness
400   }
401
402   case TopAbs_FACE: {
403     // ----------------------------------------------------------------------
404     if ( IsPropagationPossible( theMesh1, theMesh2 )) // try by propagation in one mesh
405     {
406       TopoDS_Face face1 = TopoDS::Face(theShape1);
407       TopoDS_Face face2 = TopoDS::Face(theShape2);
408       // get outer edge of theShape1
409       TopoDS_Edge edge1 = TopoDS::Edge( OuterShape( face1, TopAbs_EDGE ));
410       // find out if any edge of face2 is a propagation edge of outer edge1
411       for ( TopExp_Explorer exp( face2, TopAbs_EDGE ); exp.More(); exp.Next() ) {
412         TopoDS_Edge edge2 = TopoDS::Edge( exp.Current() );
413         edge2 = GetPropagationEdge( theMesh1, edge2, edge1 );
414         if ( !edge2.IsNull() ) // propagation found
415         {
416           TopoDS_Vertex VV1[2], VV2[2];
417           TopExp::Vertices( edge1, VV1[0], VV1[1], true );
418           TopExp::Vertices( edge2, VV2[0], VV2[1], true );
419           list< TopoDS_Edge > edges1, edges2;
420           int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2 );
421           if ( !nbE ) RETURN_BAD_RESULT("FindFaceAssociation() failed");
422           if ( nbE == 2 ) // only 2 edges
423           {
424             // take care of proper association of propagated edges
425             bool same1 = edge1.IsSame( edges1.front() );
426             bool same2 = edge2.IsSame( edges2.front() );
427             if ( same1 != same2 )
428               Reverse(edges2, nbE);
429           }
430           // store association
431           list< TopoDS_Edge >::iterator eIt1 = edges1.begin();
432           list< TopoDS_Edge >::iterator eIt2 = edges2.begin();
433           for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 )
434           {
435             InsertAssociation( *eIt1, *eIt2, theMap, bidirect);
436             VV1[0] = TopExp::FirstVertex( *eIt1, true );
437             VV2[0] = TopExp::FirstVertex( *eIt2, true );
438             InsertAssociation( VV1[0], VV2[0], theMap, bidirect);
439           }
440           return true;
441         }
442       }
443     }
444     break; // try by vertex closeness
445   }
446   default:;
447   }
448
449   // Find association by closeness of vertices
450   // ------------------------------------------
451
452   TopTools_IndexedMapOfShape vMap1, vMap2;
453   TopExp::MapShapes( theShape1, TopAbs_VERTEX, vMap1 );
454   TopExp::MapShapes( theShape2, TopAbs_VERTEX, vMap2 );
455
456   if ( vMap1.Extent() != vMap2.Extent() )
457     RETURN_BAD_RESULT("Different nb of vertices");
458
459   if ( vMap1.Extent() == 1 ) {
460     InsertAssociation( vMap1(1), vMap2(1), theMap, bidirect);
461     if ( theShape1.ShapeType() == TopAbs_EDGE )
462       return true;
463     return FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap);
464   }
465
466   // Find transformation to make the shapes be of similar size at same location
467
468   Bnd_Box box[2];
469   for ( int i = 1; i <= vMap1.Extent(); ++i ) {
470     box[ 0 ].Add( BRep_Tool::Pnt ( TopoDS::Vertex( vMap1( i ))));
471     box[ 1 ].Add( BRep_Tool::Pnt ( TopoDS::Vertex( vMap2( i ))));
472   }
473
474   gp_Pnt gc[2]; // box center
475   double x0,y0,z0, x1,y1,z1;
476   box[0].Get( x0,y0,z0, x1,y1,z1 );
477   gc[0] = 0.5 * ( gp_XYZ( x0,y0,z0 ) + gp_XYZ( x1,y1,z1 ));
478   box[1].Get( x0,y0,z0, x1,y1,z1 );
479   gc[1] = 0.5 * ( gp_XYZ( x0,y0,z0 ) + gp_XYZ( x1,y1,z1 ));
480
481   // 1 -> 2
482   gp_Vec vec01( gc[0], gc[1] );
483   double scale = sqrt( box[1].SquareExtent() / box[0].SquareExtent() );
484
485   // Find 2 closest vertices
486
487   TopoDS_Vertex VV1[2], VV2[2];
488   // get 2 linked vertices of shape 1 not belonging to an inner wire of a face
489   TopoDS_Shape edge = theShape1;
490   TopExp_Explorer expF( theShape1, TopAbs_FACE ), expE;
491   for ( ; expF.More(); expF.Next() ) {
492     edge.Nullify();
493     TopoDS_Shape wire = OuterShape( TopoDS::Face( expF.Current() ), TopAbs_WIRE );
494     for ( expE.Init( wire, TopAbs_EDGE ); edge.IsNull() && expE.More(); expE.Next() )
495       if ( !IsClosedEdge( TopoDS::Edge( expE.Current() )))
496         edge = expE.Current();
497     if ( !edge.IsNull() )
498       break;
499   }
500   if ( edge.IsNull() || edge.ShapeType() != TopAbs_EDGE )
501     RETURN_BAD_RESULT("Edge not found");
502
503   TopExp::Vertices( TopoDS::Edge( edge ), VV1[0], VV1[1]);
504   if ( VV1[0].IsSame( VV1[1] ))
505     RETURN_BAD_RESULT("Only closed edges");
506
507   // find vertices closest to 2 linked vertices of shape 1
508   for ( int i1 = 0; i1 < 2; ++i1 )
509   {
510     double dist2 = DBL_MAX;
511     gp_Pnt p1 = BRep_Tool::Pnt( VV1[ i1 ]);
512     p1.Translate( vec01 );
513     p1.Scale( gc[1], scale );
514     for ( int i2 = 1; i2 <= vMap2.Extent(); ++i2 )
515     {
516       TopoDS_Vertex V2 = TopoDS::Vertex( vMap2( i2 ));
517       gp_Pnt p2 = BRep_Tool::Pnt ( V2 );
518       double d2 = p1.SquareDistance( p2 );
519       if ( d2 < dist2 && !V2.IsSame( VV2[ 0 ])) {
520         VV2[ i1 ] = V2; dist2 = d2;
521       }
522     }
523   }
524
525   InsertAssociation( VV1[ 0 ], VV2 [ 0 ], theMap, bidirect);
526   InsertAssociation( VV1[ 1 ], VV2 [ 1 ], theMap, bidirect);
527   if ( theShape1.ShapeType() == TopAbs_EDGE )
528     return true;
529
530   return FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap );
531 }
532
533 //================================================================================
534 /*!
535  * \brief Find association of edges of faces
536  * \param face1 - face 1
537  * \param VV1 - vertices of face 1
538  * \param face2 - face 2
539  * \param VV2 - vertices of face 2 associated with oned of face 1
540  * \param edges1 - out list of edges of face 1
541  * \param edges2 - out list of edges of face 2
542  * \retval int - nb of edges in an outer wire in a success case, else zero
543  */
544 //================================================================================
545
546 int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1,
547                                                     TopoDS_Vertex      VV1[2],
548                                                     const TopoDS_Face& face2,
549                                                     TopoDS_Vertex      VV2[2],
550                                                     list< TopoDS_Edge > & edges1,
551                                                     list< TopoDS_Edge > & edges2)
552 {
553   edges1.clear();
554   edges2.clear();
555
556   list< int > nbVInW1, nbVInW2;
557   if ( SMESH_Block::GetOrderedEdges( face1, VV1[0], edges1, nbVInW1) !=
558        SMESH_Block::GetOrderedEdges( face2, VV2[0], edges2, nbVInW2) )
559     RETURN_BAD_RESULT("Different number of wires in faces ");
560
561   if ( nbVInW1.front() != nbVInW2.front() )
562     RETURN_BAD_RESULT("Different number of edges in faces: " <<
563                       nbVInW1.front() << " != " << nbVInW2.front());
564
565   // Define if we need to reverse one of wires to make edges in lists match each other
566
567   bool reverse = false;
568
569   list< TopoDS_Edge >::iterator eBackIt;
570   if ( !VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) {
571     eBackIt = --edges1.end();
572     // check if the second vertex belongs to the first or last edge in the wire
573     if ( !VV1[1].IsSame( TopExp::FirstVertex( *eBackIt, true ))) {
574       bool KO = true; // belongs to none
575       if ( nbVInW1.size() > 1 ) { // several wires
576         eBackIt = edges1.begin();
577         for ( int i = 1; i < nbVInW1.front(); ++i ) ++eBackIt;
578         KO = !VV1[1].IsSame( TopExp::FirstVertex( *eBackIt, true ));
579       }
580       if ( KO )
581         RETURN_BAD_RESULT("GetOrderedEdges() failed");
582     }
583     reverse = true;
584   }
585   eBackIt = --edges2.end();
586   if ( !VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true ))) {
587     // check if the second vertex belongs to the first or last edge in the wire
588     if ( !VV2[1].IsSame( TopExp::FirstVertex( *eBackIt, true ))) {
589       bool KO = true; // belongs to none
590       if ( nbVInW2.size() > 1 ) { // several wires
591         eBackIt = edges2.begin();
592         for ( int i = 1; i < nbVInW2.front(); ++i ) ++eBackIt;
593         KO = !VV2[1].IsSame( TopExp::FirstVertex( *eBackIt, true ));
594       }
595       if ( KO )
596         RETURN_BAD_RESULT("GetOrderedEdges() failed");
597     }
598     reverse = !reverse;
599   }
600   if ( reverse )
601   {
602     Reverse( edges2 , nbVInW2.front());
603     if (( VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) !=
604         ( VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true ))))
605       RETURN_BAD_RESULT("GetOrderedEdges() failed");
606   }
607   return nbVInW2.front();
608 }
609
610 //=======================================================================
611 //function : InitVertexAssociation
612 //purpose  : 
613 //=======================================================================
614
615 void StdMeshers_ProjectionUtils::InitVertexAssociation( const SMESH_Hypothesis* theHyp,
616                                                         TShapeShapeMap &        theAssociationMap)
617 {
618   string hypName = theHyp->GetName();
619   if ( hypName == "ProjectionSource1D" ) {
620     const StdMeshers_ProjectionSource1D * hyp =
621       static_cast<const StdMeshers_ProjectionSource1D*>( theHyp );
622     if ( hyp->HasVertexAssociation() ) {
623       InsertAssociation( hyp->GetSourceVertex(),hyp->GetTargetVertex(),theAssociationMap);
624     }
625   }
626   else if ( hypName == "ProjectionSource2D" ) {
627     const StdMeshers_ProjectionSource2D * hyp =
628       static_cast<const StdMeshers_ProjectionSource2D*>( theHyp );
629     if ( hyp->HasVertexAssociation() ) {
630       InsertAssociation( hyp->GetSourceVertex(1),hyp->GetTargetVertex(1),theAssociationMap);
631       InsertAssociation( hyp->GetSourceVertex(2),hyp->GetTargetVertex(2),theAssociationMap);
632     }
633   }
634   else if ( hypName == "ProjectionSource3D" ) {
635     const StdMeshers_ProjectionSource3D * hyp =
636       static_cast<const StdMeshers_ProjectionSource3D*>( theHyp );
637     if ( hyp->HasVertexAssociation() ) {
638       InsertAssociation( hyp->GetSourceVertex(1),hyp->GetTargetVertex(1),theAssociationMap);
639       InsertAssociation( hyp->GetSourceVertex(2),hyp->GetTargetVertex(2),theAssociationMap);
640     }
641   }
642 }
643
644 //=======================================================================
645 /*!
646  * \brief Inserts association theShape1 <-> theShape2 to TShapeShapeMap
647  * \param theShape1 - shape 1
648  * \param theShape2 - shape 2
649  * \param theAssociationMap - association map 
650  * \retval bool - true if there was no association for these shapes before
651  */
652 //=======================================================================
653
654 bool StdMeshers_ProjectionUtils::InsertAssociation( const TopoDS_Shape& theShape1,
655                                                     const TopoDS_Shape& theShape2,
656                                                     TShapeShapeMap &    theAssociationMap,
657                                                     const bool          theBidirectional)
658 {
659   if ( !theShape1.IsNull() && !theShape2.IsNull() ) {
660     SHOW_VERTEX(theShape1,"Assoc ");
661     SHOW_VERTEX(theShape2," to ");
662     bool isNew = ( theAssociationMap.Bind( theShape1, theShape2 ));
663     if ( theBidirectional )
664       theAssociationMap.Bind( theShape2, theShape1 );
665     return isNew;
666   }
667   return false;
668 }
669
670 //=======================================================================
671 //function : IsSubShape
672 //purpose  : 
673 //=======================================================================
674
675 bool StdMeshers_ProjectionUtils::IsSubShape( const TopoDS_Shape& shape,
676                                              SMESH_Mesh*         aMesh )
677 {
678   if ( shape.IsNull() || !aMesh )
679     return false;
680   return aMesh->GetMeshDS()->ShapeToIndex( shape );
681 }
682
683 //=======================================================================
684 //function : IsSubShape
685 //purpose  : 
686 //=======================================================================
687
688 bool StdMeshers_ProjectionUtils::IsSubShape( const TopoDS_Shape& shape,
689                                              const TopoDS_Shape& mainShape )
690 {
691   if ( !shape.IsNull() && !mainShape.IsNull() )
692   {
693     for ( TopExp_Explorer exp( mainShape, shape.ShapeType());
694           exp.More();
695           exp.Next() )
696       if ( shape.IsSame( exp.Current() ))
697         return true;
698   }
699   SCRUTE((shape.IsNull()));
700   SCRUTE((mainShape.IsNull()));
701   return false;
702 }
703
704
705 //=======================================================================
706 /*!
707  * \brief Finds an edge by its vertices in a main shape of the mesh
708  * \param aMesh - the mesh
709  * \param V1 - vertex 1
710  * \param V2 - vertex 2
711  * \retval TopoDS_Edge - found edge
712  */
713 //=======================================================================
714
715 TopoDS_Edge StdMeshers_ProjectionUtils::GetEdgeByVertices( SMESH_Mesh*          theMesh,
716                                                            const TopoDS_Vertex& theV1,
717                                                            const TopoDS_Vertex& theV2)
718 {
719   if ( theMesh && !theV1.IsNull() && !theV2.IsNull() )
720   {
721     TopTools_ListIteratorOfListOfShape ancestorIt( theMesh->GetAncestors( theV1 ));
722     for ( ; ancestorIt.More(); ancestorIt.Next() )
723       if ( ancestorIt.Value().ShapeType() == TopAbs_EDGE )
724         for ( TopExp_Explorer expV ( ancestorIt.Value(), TopAbs_VERTEX );
725               expV.More();
726               expV.Next() )
727           if ( theV2.IsSame( expV.Current() ))
728             return TopoDS::Edge( ancestorIt.Value() );
729   }
730   return TopoDS_Edge();
731 }
732
733 //================================================================================
734 /*!
735  * \brief Return another face sharing an edge
736  * \param aMesh - mesh
737  * \param edge - edge
738  * \param face - face
739  * \retval TopoDS_Face - found face
740  */
741 //================================================================================
742
743 TopoDS_Face StdMeshers_ProjectionUtils::GetNextFace( SMESH_Mesh*        mesh,
744                                                      const TopoDS_Edge& edge,
745                                                      const TopoDS_Face& face)
746 {
747   if ( mesh && !edge.IsNull() && !face.IsNull() )
748   {
749     TopTools_ListIteratorOfListOfShape ancestorIt( mesh->GetAncestors( edge ));
750     for ( ; ancestorIt.More(); ancestorIt.Next() )
751       if ( ancestorIt.Value().ShapeType() == TopAbs_FACE &&
752            !face.IsSame( ancestorIt.Value() ))
753         return TopoDS::Face( ancestorIt.Value() );
754   }
755   return TopoDS_Face();
756   
757 }
758
759 //================================================================================
760 /*!
761  * \brief Return a propagation edge
762  * \param aMesh - mesh
763  * \param theEdge - edge to find by propagation
764  * \param fromEdge - start edge for propagation
765  * \retval TopoDS_Edge - found edge
766  */
767 //================================================================================
768
769 TopoDS_Edge StdMeshers_ProjectionUtils::GetPropagationEdge( SMESH_Mesh*        aMesh,
770                                                             const TopoDS_Edge& theEdge,
771                                                             const TopoDS_Edge& fromEdge)
772 {
773   SMESH_IndexedMapOfShape aChain;
774   //aChain.Add(fromEdge);
775
776   // List of edges, added to chain on the previous cycle pass
777   TopTools_ListOfShape listPrevEdges;
778   listPrevEdges.Append(fromEdge/*.Oriented( TopAbs_FORWARD )*/);
779
780   // Collect all edges pass by pass
781   while (listPrevEdges.Extent() > 0) {
782     // List of edges, added to chain on this cycle pass
783     TopTools_ListOfShape listCurEdges;
784
785     // Find the next portion of edges
786     TopTools_ListIteratorOfListOfShape itE (listPrevEdges);
787     for (; itE.More(); itE.Next()) {
788       TopoDS_Shape anE = itE.Value();
789
790       // Iterate on faces, having edge <anE>
791       TopTools_ListIteratorOfListOfShape itA (aMesh->GetAncestors(anE));
792       for (; itA.More(); itA.Next()) {
793         TopoDS_Shape aW = itA.Value();
794
795         // There are objects of different type among the ancestors of edge
796         if (aW.ShapeType() == TopAbs_WIRE) {
797           TopoDS_Shape anOppE;
798
799           BRepTools_WireExplorer aWE (TopoDS::Wire(aW));
800           Standard_Integer nb = 1, found = 0;
801           TopTools_Array1OfShape anEdges (1,4);
802           for (; aWE.More(); aWE.Next(), nb++) {
803             if (nb > 4) {
804               found = 0;
805               break;
806             }
807             anEdges(nb) = aWE.Current();
808             if (anEdges(nb).IsSame(anE)) found = nb;
809           }
810
811           if (nb == 5 && found > 0) {
812             // Quadrangle face found, get an opposite edge
813             Standard_Integer opp = found + 2;
814             if (opp > 4) opp -= 4;
815             anOppE = anEdges(opp);
816
817             // add anOppE to aChain if ...
818             if (!aChain.Contains(anOppE)) { // ... anOppE is not in aChain
819               // Add found edge to the chain oriented so that to
820               // have it co-directed with a forward MainEdge
821               TopAbs_Orientation ori = anE.Orientation();
822               if ( anEdges(opp).Orientation() == anEdges(found).Orientation() )
823                 ori = TopAbs::Reverse( ori );
824               anOppE.Orientation( ori );
825               if ( anOppE.IsSame( theEdge ))
826                 return TopoDS::Edge( anOppE );
827               aChain.Add(anOppE);
828               listCurEdges.Append(anOppE);
829             }
830           } // if (nb == 5 && found > 0)
831         } // if (aF.ShapeType() == TopAbs_WIRE)
832       } // for (; itF.More(); itF.Next())
833     } // for (; itE.More(); itE.Next())
834
835     listPrevEdges = listCurEdges;
836   } // while (listPrevEdges.Extent() > 0)
837
838   return TopoDS_Edge();
839 }
840
841 //================================================================================
842   /*!
843    * \brief Find corresponding nodes on two faces
844     * \param face1 - the first face
845     * \param mesh1 - mesh containing elements on the first face
846     * \param face2 - the second face
847     * \param mesh2 - mesh containing elements on the second face
848     * \param assocMap - map associating subshapes of the faces
849     * \param node1To2Map - map containing found matching nodes
850     * \retval bool - is a success
851    */
852 //================================================================================
853
854 bool StdMeshers_ProjectionUtils::
855 FindMatchingNodesOnFaces( const TopoDS_Face&     face1,
856                           SMESH_Mesh*            mesh1,
857                           const TopoDS_Face&     face2,
858                           SMESH_Mesh*            mesh2,
859                           const TShapeShapeMap & assocMap,
860                           TNodeNodeMap &         node1To2Map)
861 {
862   SMESHDS_Mesh* meshDS1 = mesh1->GetMeshDS();
863   SMESHDS_Mesh* meshDS2 = mesh2->GetMeshDS();
864   
865   SMESH_MesherHelper helper1( *mesh1 );
866   SMESH_MesherHelper helper2( *mesh2 );
867
868   // Get corresponding submeshes and roughly check match of meshes
869
870   SMESHDS_SubMesh * SM2 = meshDS2->MeshElements( face2 );
871   SMESHDS_SubMesh * SM1 = meshDS1->MeshElements( face1 );
872   if ( !SM2 || !SM1 )
873     RETURN_BAD_RESULT("Empty submeshes");
874   if ( SM2->NbNodes()    != SM1->NbNodes() ||
875        SM2->NbElements() != SM1->NbElements() )
876     RETURN_BAD_RESULT("Different meshes on corresponding faces "
877                       << meshDS1->ShapeToIndex( face1 ) << " and "
878                       << meshDS2->ShapeToIndex( face2 ));
879   if ( SM2->NbElements() == 0 )
880     RETURN_BAD_RESULT("Empty submeshes");
881
882   helper1.SetSubShape( face1 );
883   helper2.SetSubShape( face2 );
884   if ( helper1.HasSeam() != helper2.HasSeam() )
885     RETURN_BAD_RESULT("Different faces' geometry");
886
887   // Data to call SMESH_MeshEditor::FindMatchingNodes():
888
889   // 1. Nodes of corresponding links:
890
891   // get 2 matching edges, not seam ones
892   TopoDS_Edge edge1, edge2;
893   TopExp_Explorer eE( OuterShape( face2, TopAbs_WIRE ), TopAbs_EDGE );
894   do {
895     edge2 = TopoDS::Edge( eE.Current() );
896     eE.Next();
897   } while ( BRep_Tool::IsClosed( edge2, face2 ) && eE.More());
898   if ( !assocMap.IsBound( edge2 ))
899     RETURN_BAD_RESULT("Association not found for edge " << meshDS2->ShapeToIndex( edge2 ));
900   edge1 = TopoDS::Edge( assocMap( edge2 ));
901   if ( !IsSubShape( edge1, face1 ))
902     RETURN_BAD_RESULT("Wrong association, edge " << meshDS1->ShapeToIndex( edge1 ) <<
903                       " isn't a subshape of face " << meshDS1->ShapeToIndex( face1 ));
904
905   // get 2 matching vertices
906   TopoDS_Shape V2 = TopExp::FirstVertex( TopoDS::Edge( edge2 ));
907   if ( !assocMap.IsBound( V2 ))
908     RETURN_BAD_RESULT("Association not found for vertex " << meshDS2->ShapeToIndex( V2 ));
909   TopoDS_Shape V1 = assocMap( V2 );
910
911   // nodes on vertices
912   SMESHDS_SubMesh * vSM1 = meshDS1->MeshElements( V1 );
913   SMESHDS_SubMesh * vSM2 = meshDS2->MeshElements( V2 );
914   if ( !vSM1 || !vSM2 || vSM1->NbNodes() != 1 || vSM2->NbNodes() != 1 )
915     RETURN_BAD_RESULT("Bad node submesh");
916   const SMDS_MeshNode* vNode1 = vSM1->GetNodes()->next();
917   const SMDS_MeshNode* vNode2 = vSM2->GetNodes()->next();
918
919   // nodes on edges linked with nodes on vertices
920   const SMDS_MeshNode* nullNode = 0;
921   vector< const SMDS_MeshNode*> eNode1( 2, nullNode );
922   vector< const SMDS_MeshNode*> eNode2( 2, nullNode );
923   int nbNodeToGet = 1;
924   if ( IsClosedEdge( edge1 ) || IsClosedEdge( edge2 ) )
925     nbNodeToGet = 2;
926   for ( int is2 = 0; is2 < 2; ++is2 )
927   {
928     TopoDS_Edge &     edge  = is2 ? edge2 : edge1;
929     SMESHDS_Mesh *    smDS  = is2 ? meshDS2 : meshDS1;
930     SMESHDS_SubMesh* edgeSM = smDS->MeshElements( edge );
931     // nodes linked with ones on vertices
932     const SMDS_MeshNode*           vNode = is2 ? vNode2 : vNode1;
933     vector< const SMDS_MeshNode*>& eNode = is2 ? eNode2 : eNode1;
934     int nbGotNode = 0;
935     SMDS_ElemIteratorPtr vElem = vNode->GetInverseElementIterator();
936     while ( vElem->more() && nbGotNode != nbNodeToGet ) {
937       const SMDS_MeshElement* elem = vElem->next();
938       if ( elem->GetType() == SMDSAbs_Edge && edgeSM->Contains( elem ))
939         eNode[ nbGotNode++ ] = 
940           ( elem->GetNode(0) == vNode ) ? elem->GetNode(1) : elem->GetNode(0);
941     }
942     if ( nbGotNode > 1 ) // sort found nodes by param on edge
943     {
944       SMESH_MesherHelper* helper = is2 ? &helper2 : &helper1;
945       double u0 = helper->GetNodeU( edge, eNode[ 0 ]);
946       double u1 = helper->GetNodeU( edge, eNode[ 1 ]);
947       if ( u0 > u1 ) std::swap( eNode[ 0 ], eNode[ 1 ]);
948     }
949     if ( nbGotNode == 0 )
950       RETURN_BAD_RESULT("Found no nodes on edge " << smDS->ShapeToIndex( edge ) <<
951                         " linked to " << vNode );
952   }
953
954   // 2. face sets
955
956   set<const SMDS_MeshElement*> Elems1, Elems2;
957   for ( int is2 = 0; is2 < 2; ++is2 )
958   {
959     set<const SMDS_MeshElement*> & elems = is2 ? Elems2 : Elems1;
960     SMESHDS_SubMesh*                  sm = is2 ? SM2 : SM1;
961     SMESH_MesherHelper*           helper = is2 ? &helper2 : &helper1;
962     const TopoDS_Face &             face = is2 ? face2 : face1;
963     SMDS_ElemIteratorPtr eIt = sm->GetElements();
964
965     if ( !helper->IsSeamShape( is2 ? edge2 : edge1 ))
966     {
967       while ( eIt->more() ) elems.insert( eIt->next() );
968     }
969     else
970     {
971       // there is only seam edge in a face, i.e. it is a sphere.
972       // FindMatchingNodes() will not know which way to go from any edge.
973       // So we ignore all faces having nodes on edges or vertices except
974       // one of faces sharing current start nodes
975
976       // find a face to keep
977       const SMDS_MeshElement* faceToKeep = 0;
978       const SMDS_MeshNode* vNode = is2 ? vNode2 : vNode1;
979       const SMDS_MeshNode* eNode = is2 ? eNode2[0] : eNode1[0];
980       TIDSortedElemSet inSet, notInSet;
981
982       const SMDS_MeshElement* f1 =
983         SMESH_MeshEditor::FindFaceInSet( vNode, eNode, inSet, notInSet );
984       if ( !f1 ) RETURN_BAD_RESULT("The first face on seam not found");
985       notInSet.insert( f1 );
986
987       const SMDS_MeshElement* f2 =
988         SMESH_MeshEditor::FindFaceInSet( vNode, eNode, inSet, notInSet );
989       if ( !f2 ) RETURN_BAD_RESULT("The second face on seam not found");
990
991       // select a face with less UV of vNode
992       const SMDS_MeshNode* notSeamNode[2] = {0, 0};
993       for ( int iF = 0; iF < 2; ++iF ) {
994         const SMDS_MeshElement* f = ( iF ? f2 : f1 );
995         for ( int i = 0; !notSeamNode[ iF ] && i < f->NbNodes(); ++i ) {
996           const SMDS_MeshNode* node = f->GetNode( i );
997           if ( !helper->IsSeamShape( node->GetPosition()->GetShapeId() ))
998             notSeamNode[ iF ] = node;
999         }
1000       }
1001       gp_Pnt2d uv1 = helper->GetNodeUV( face, vNode, notSeamNode[0] );
1002       gp_Pnt2d uv2 = helper->GetNodeUV( face, vNode, notSeamNode[1] );
1003       if ( uv1.X() + uv1.Y() > uv2.X() + uv2.Y() )
1004         faceToKeep = f2;
1005       else
1006         faceToKeep = f1;
1007
1008       // fill elem set
1009       elems.insert( faceToKeep );
1010       while ( eIt->more() ) {
1011         const SMDS_MeshElement* f = eIt->next();
1012         int nbNodes = f->NbNodes();
1013         if ( f->IsQuadratic() )
1014           nbNodes /= 2;
1015         bool onBnd = false;
1016         for ( int i = 0; !onBnd && i < nbNodes; ++i ) {
1017           const SMDS_MeshNode* node = f->GetNode( i );
1018           onBnd = ( node->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE);
1019         }
1020         if ( !onBnd )
1021           elems.insert( f );
1022       }
1023     } // case on a sphere
1024   } // loop on 2 faces
1025
1026   node1To2Map.clear();
1027   int res = SMESH_MeshEditor::FindMatchingNodes( Elems1, Elems2,
1028                                                  vNode1, vNode2,
1029                                                  eNode1[0], eNode2[0],
1030                                                  node1To2Map);
1031   if ( res != SMESH_MeshEditor::SEW_OK )
1032     RETURN_BAD_RESULT("FindMatchingNodes() result " << res );
1033
1034
1035   // On a sphere, add matching nodes on the edge
1036
1037   if ( helper1.IsSeamShape( edge1 ))
1038   {
1039     // sort nodes on edges by param on edge
1040     map< double, const SMDS_MeshNode* > u2nodesMaps[2];
1041     for ( int is2 = 0; is2 < 2; ++is2 )
1042     {
1043       TopoDS_Edge &     edge  = is2 ? edge2 : edge1;
1044       SMESHDS_Mesh *    smDS  = is2 ? meshDS2 : meshDS1;
1045       SMESHDS_SubMesh* edgeSM = smDS->MeshElements( edge );
1046       map< double, const SMDS_MeshNode* > & pos2nodes = u2nodesMaps[ is2 ];
1047
1048       SMDS_NodeIteratorPtr nIt = edgeSM->GetNodes();
1049       while ( nIt->more() ) {
1050         const SMDS_MeshNode* node = nIt->next();
1051         const SMDS_EdgePosition* pos =
1052           static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
1053         pos2nodes.insert( make_pair( pos->GetUParameter(), node ));
1054       }
1055       if ( pos2nodes.size() != edgeSM->NbNodes() )
1056         RETURN_BAD_RESULT("Equal params of nodes on edge "
1057                           << smDS->ShapeToIndex( edge ) << " of face " << is2 );
1058     }
1059     if ( u2nodesMaps[0].size() != u2nodesMaps[1].size() )
1060       RETURN_BAD_RESULT("Different nb of new nodes on edges or wrong params");
1061
1062     // compare edge orientation
1063     double u1 = helper1.GetNodeU( edge1, vNode1 );
1064     double u2 = helper2.GetNodeU( edge2, vNode2 );
1065     bool isFirst1 = ( u1 < u2nodesMaps[0].begin()->first );
1066     bool isFirst2 = ( u2 < u2nodesMaps[1].begin()->first );
1067     bool reverse ( isFirst1 != isFirst2 );
1068
1069     // associate matching nodes
1070     map< double, const SMDS_MeshNode* >::iterator u_Node1, u_Node2, end1;
1071     map< double, const SMDS_MeshNode* >::reverse_iterator uR_Node2;
1072     u_Node1 = u2nodesMaps[0].begin();
1073     u_Node2 = u2nodesMaps[1].begin();
1074     uR_Node2 = u2nodesMaps[1].rbegin();
1075     end1 = u2nodesMaps[0].end();
1076     for ( ; u_Node1 != end1; ++u_Node1 ) {
1077       const SMDS_MeshNode* n1 = u_Node1->second;
1078       const SMDS_MeshNode* n2 = ( reverse ? (uR_Node2++)->second : (u_Node2++)->second );
1079       node1To2Map.insert( make_pair( n1, n2 ));
1080     }
1081
1082     // associate matching nodes on the last vertices
1083     V2 = TopExp::LastVertex( TopoDS::Edge( edge2 ));
1084     if ( !assocMap.IsBound( V2 ))
1085       RETURN_BAD_RESULT("Association not found for vertex " << meshDS2->ShapeToIndex( V2 ));
1086     V1 = assocMap( V2 );
1087     vSM1 = meshDS1->MeshElements( V1 );
1088     vSM2 = meshDS2->MeshElements( V2 );
1089     if ( !vSM1 || !vSM2 || vSM1->NbNodes() != 1 || vSM2->NbNodes() != 1 )
1090       RETURN_BAD_RESULT("Bad node submesh");
1091     vNode1 = vSM1->GetNodes()->next();
1092     vNode2 = vSM2->GetNodes()->next();
1093     node1To2Map.insert( make_pair( vNode1, vNode2 ));
1094   }
1095   
1096   return true;
1097 }
1098
1099 //================================================================================
1100 /*!
1101  * \brief Check if the first and last vertices of an edge are the same
1102  * \param anEdge - the edge to check
1103  * \retval bool - true if same
1104  */
1105 //================================================================================
1106
1107 bool StdMeshers_ProjectionUtils::IsClosedEdge( const TopoDS_Edge& anEdge )
1108 {
1109   return TopExp::FirstVertex( anEdge ).IsSame( TopExp::LastVertex( anEdge ));
1110 }
1111
1112 //================================================================================
1113   /*!
1114    * \brief Return any subshape of a face belonging to the outer wire
1115     * \param face - the face
1116     * \param type - type of subshape to return
1117     * \retval TopoDS_Shape - the found subshape
1118    */
1119 //================================================================================
1120
1121 TopoDS_Shape StdMeshers_ProjectionUtils::OuterShape( const TopoDS_Face& face,
1122                                                      TopAbs_ShapeEnum   type)
1123 {
1124   TopExp_Explorer exp( BRepTools::OuterWire( face ), type );
1125   if ( exp.More() )
1126     return exp.Current();
1127   return TopoDS_Shape();
1128 }
1129
1130 //================================================================================
1131   /*!
1132    * \brief Check that submesh is computed and try to compute it if is not
1133     * \param sm - submesh to compute
1134     * \param iterationNb - int used to stop infinite recursive call
1135     * \retval bool - true if computed
1136    */
1137 //================================================================================
1138
1139 bool StdMeshers_ProjectionUtils::MakeComputed(SMESH_subMesh * sm, const int iterationNb)
1140 {
1141   if ( iterationNb > 10 )
1142     RETURN_BAD_RESULT("Infinite recursive projection");
1143   if ( !sm )
1144     RETURN_BAD_RESULT("NULL submesh");
1145   if ( sm->IsMeshComputed() )
1146     return true;
1147
1148   SMESH_Mesh* mesh = sm->GetFather();
1149   SMESH_Gen* gen   = mesh->GetGen();
1150   SMESH_Algo* algo = gen->GetAlgo( *mesh, sm->GetSubShape() );
1151   if ( !algo )
1152     RETURN_BAD_RESULT("No algo assigned to submesh " << sm->GetId());
1153
1154   string algoType = algo->GetName();
1155   if ( algoType.substr(0, 11) != "Projection_")
1156     return gen->Compute( *mesh, sm->GetSubShape() );
1157
1158   // try to compute source mesh
1159
1160   const list <const SMESHDS_Hypothesis *> & hyps =
1161     algo->GetUsedHypothesis( *mesh, sm->GetSubShape() );
1162
1163   TopoDS_Shape srcShape;
1164   SMESH_Mesh* srcMesh = 0;
1165   list <const SMESHDS_Hypothesis*>::const_iterator hIt = hyps.begin();
1166   for ( ; srcShape.IsNull() && hIt != hyps.end(); ++hIt ) {
1167     string hypName = (*hIt)->GetName();
1168     if ( hypName == "ProjectionSource1D" ) {
1169       const StdMeshers_ProjectionSource1D * hyp =
1170         static_cast<const StdMeshers_ProjectionSource1D*>( *hIt );
1171       srcShape = hyp->GetSourceEdge();
1172       srcMesh = hyp->GetSourceMesh();
1173     }
1174     else if ( hypName == "ProjectionSource2D" ) {
1175       const StdMeshers_ProjectionSource2D * hyp =
1176         static_cast<const StdMeshers_ProjectionSource2D*>( *hIt );
1177       srcShape = hyp->GetSourceFace();
1178       srcMesh = hyp->GetSourceMesh();
1179     }
1180     else if ( hypName == "ProjectionSource3D" ) {
1181       const StdMeshers_ProjectionSource3D * hyp =
1182         static_cast<const StdMeshers_ProjectionSource3D*>( *hIt );
1183       srcShape = hyp->GetSource3DShape();
1184       srcMesh = hyp->GetSourceMesh();
1185     }
1186   }
1187   if ( srcShape.IsNull() ) // no projection source defined
1188     return gen->Compute( *mesh, sm->GetSubShape() );
1189
1190   if ( srcShape.IsSame( sm->GetSubShape() ))
1191     RETURN_BAD_RESULT("Projection from self");
1192     
1193   if ( !srcMesh )
1194     srcMesh = mesh;
1195
1196   return MakeComputed( srcMesh->GetSubMesh( srcShape ), iterationNb + 1 );
1197 }
1198
1199 //================================================================================
1200   /*!
1201    * \brief Count nb of subshapes
1202     * \param shape - the shape
1203     * \param type - the type of subshapes to count
1204     * \retval int - the calculated number
1205    */
1206 //================================================================================
1207
1208 int StdMeshers_ProjectionUtils::Count(const TopoDS_Shape&    shape,
1209                                       const TopAbs_ShapeEnum type,
1210                                       const bool             ignoreSame)
1211 {
1212   if ( ignoreSame ) {
1213     TopTools_IndexedMapOfShape map;
1214     TopExp::MapShapes( shape, type, map );
1215     return map.Extent();
1216   }
1217   else {
1218     int nb = 0;
1219     for ( TopExp_Explorer exp( shape, type ); exp.More(); exp.Next() )
1220       ++nb;
1221     return nb;
1222   }
1223 }
1224
1225 namespace {
1226
1227   SMESH_subMeshEventListener* GetSrcSubMeshListener();
1228
1229   //================================================================================
1230   /*!
1231    * \brief Listener that resets an event listener on source submesh when 
1232    * "ProjectionSource*D" hypothesis is modified
1233    */
1234   //================================================================================
1235
1236   struct HypModifWaiter: SMESH_subMeshEventListener
1237   {
1238     HypModifWaiter():SMESH_subMeshEventListener(0){} // won't be deleted by submesh
1239
1240     void ProcessEvent(const int event, const int eventType, SMESH_subMesh* subMesh,
1241                       EventListenerData*, const SMESH_Hypothesis*)
1242     {
1243       if ( event     == SMESH_subMesh::MODIF_HYP &&
1244            eventType == SMESH_subMesh::ALGO_EVENT)
1245       {
1246         // delete current source listener
1247         subMesh->DeleteEventListener( GetSrcSubMeshListener() );
1248         // let algo set a new one
1249         SMESH_Gen* gen = subMesh->GetFather()->GetGen();
1250         if ( SMESH_Algo* algo = gen->GetAlgo( *subMesh->GetFather(),
1251                                               subMesh->GetSubShape() ))
1252           algo->SetEventListener( subMesh );
1253       }
1254     }
1255   };
1256   //================================================================================
1257   /*!
1258    * \brief return static HypModifWaiter
1259    */
1260   //================================================================================
1261
1262   SMESH_subMeshEventListener* GetHypModifWaiter() {
1263     static HypModifWaiter aHypModifWaiter;
1264     return &aHypModifWaiter;
1265   }
1266   //================================================================================
1267   /*!
1268    * \brief return static listener for source shape submeshes
1269    */
1270   //================================================================================
1271
1272   SMESH_subMeshEventListener* GetSrcSubMeshListener() {
1273     static SMESH_subMeshEventListener srcListener(0); // won't be deleted by submesh
1274     return &srcListener;
1275   }
1276 }
1277
1278 //================================================================================
1279 /*!
1280  * \brief Set event listeners to submesh with projection algo
1281  * \param subMesh - submesh with projection algo
1282  * \param srcShape - source shape
1283  * \param srcMesh - source mesh
1284  */
1285 //================================================================================
1286
1287 void StdMeshers_ProjectionUtils::SetEventListener(SMESH_subMesh* subMesh,
1288                                                   TopoDS_Shape   srcShape,
1289                                                   SMESH_Mesh*    srcMesh)
1290 {
1291   // Set listener that resets an event listener on source submesh when
1292   // "ProjectionSource*D" hypothesis is modified
1293   subMesh->SetEventListener( GetHypModifWaiter(),0,subMesh);
1294
1295   // Set an event listener to submesh of the source shape
1296   if ( !srcShape.IsNull() )
1297   {
1298     if ( !srcMesh )
1299       srcMesh = subMesh->GetFather();
1300
1301     SMESH_subMesh* srcShapeSM = srcMesh->GetSubMesh( srcShape );
1302
1303     if ( srcShapeSM != subMesh )
1304       subMesh->SetEventListener( GetSrcSubMeshListener(),
1305                                  SMESH_subMeshEventListenerData::MakeData( subMesh ),
1306                                  srcShapeSM );
1307   }
1308 }