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