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