Salome HOME
0020918: EDF 1447 SMESH: Mesh common borders (stepbystep.py)
[modules/smesh.git] / src / StdMeshers / StdMeshers_Import_1D.cxx
1 // Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : implementaion of SMESH idl descriptions
24 //  File   : StdMeshers_Import_1D.cxx
25 //  Module : SMESH
26 //
27 #include "StdMeshers_Import_1D.hxx"
28 #include "StdMeshers_ImportSource.hxx"
29
30 #include "SMDS_MeshElement.hxx"
31 #include "SMDS_MeshNode.hxx"
32 #include "SMESHDS_Group.hxx"
33 #include "SMESHDS_Mesh.hxx"
34 #include "SMESH_Comment.hxx"
35 #include "SMESH_Gen.hxx"
36 #include "SMESH_Group.hxx"
37 #include "SMESH_HypoFilter.hxx"
38 #include "SMESH_Mesh.hxx"
39 #include "SMESH_MesherHelper.hxx"
40 #include "SMESH_subMesh.hxx"
41 #include "SMESH_subMeshEventListener.hxx"
42
43 #include "Utils_SALOME_Exception.hxx"
44 #include "utilities.h"
45
46 #include <BRep_Builder.hxx>
47 #include <BRep_Tool.hxx>
48 #include <TopExp.hxx>
49 #include <TopExp_Explorer.hxx>
50 #include <TopoDS.hxx>
51 #include <TopoDS_Compound.hxx>
52 #include <TopoDS_Edge.hxx>
53 #include <TopoDS_Vertex.hxx>
54
55 using namespace std;
56
57 //=============================================================================
58 /*!
59  * Creates StdMeshers_Import_1D
60  */
61 //=============================================================================
62
63 StdMeshers_Import_1D::StdMeshers_Import_1D(int hypId, int studyId, SMESH_Gen * gen)
64   :SMESH_1D_Algo(hypId, studyId, gen), _sourceHyp(0)
65 {
66   MESSAGE("StdMeshers_Import_1D::StdMeshers_Import_1D");
67   _name = "Import_1D";
68   _shapeType = (1 << TopAbs_EDGE);
69
70   _compatibleHypothesis.push_back("ImportSource1D");
71 }
72
73 //=============================================================================
74 /*!
75  * Check presence of a hypothesis
76  */
77 //=============================================================================
78
79 bool StdMeshers_Import_1D::CheckHypothesis
80                          (SMESH_Mesh&                          aMesh,
81                           const TopoDS_Shape&                  aShape,
82                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
83 {
84   _sourceHyp = 0;
85
86   const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape);
87   if ( hyps.size() == 0 )
88   {
89     aStatus = SMESH_Hypothesis::HYP_MISSING;
90     return false;  // can't work with no hypothesis
91   }
92
93   if ( hyps.size() > 1 )
94   {
95     aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST;
96     return false;
97   }
98
99   const SMESHDS_Hypothesis *theHyp = hyps.front();
100
101   string hypName = theHyp->GetName();
102
103   if (hypName == _compatibleHypothesis.front())
104   {
105     _sourceHyp = (StdMeshers_ImportSource1D *)theHyp;
106     aStatus = SMESH_Hypothesis::HYP_OK;
107     return true;
108   }
109
110   aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
111   return true;
112 }
113
114 //================================================================================
115 namespace // INTERNAL STUFF
116 //================================================================================
117 {
118   int getSubmeshIDForCopiedMesh(const SMESHDS_Mesh* srcMeshDS, SMESH_Mesh* tgtMesh);
119
120   enum _ListenerDataType
121     {
122       WAIT_HYP_MODIF=1, // data indicating awaiting for valid parameters of src hyp
123       LISTEN_SRC_MESH, // data storing submesh depending on source mesh state
124       SRC_HYP // data storing ImportSource hyp
125     };
126   //================================================================================
127   /*!
128    * \brief _ListenerData holding ImportSource hyp holding in its turn
129    *  imported groups
130    */
131   struct _ListenerData : public SMESH_subMeshEventListenerData
132   {
133     const StdMeshers_ImportSource1D* _srcHyp;
134     _ListenerData(const StdMeshers_ImportSource1D* h, _ListenerDataType type=SRC_HYP):
135       SMESH_subMeshEventListenerData(/*isDeletable=*/true), _srcHyp(h)
136     {
137       myType = type; 
138     }
139   };
140   //================================================================================
141   /*!
142    * \brief Comparator of sub-meshes
143    */
144   struct _SubLess
145   {
146     bool operator()(const SMESH_subMesh* sm1, const SMESH_subMesh* sm2 ) const
147     {
148       if ( sm1 == sm2 ) return false;
149       if ( !sm1 || !sm2 ) return sm1 < sm2;
150       const TopoDS_Shape& s1 = sm1->GetSubShape();
151       const TopoDS_Shape& s2 = sm2->GetSubShape();
152       TopAbs_ShapeEnum t1 = s1.IsNull() ? TopAbs_SHAPE : s1.ShapeType();
153       TopAbs_ShapeEnum t2 = s2.IsNull() ? TopAbs_SHAPE : s2.ShapeType();
154       if ( t1 == t2)
155         return (sm1 < sm2);
156       return t1 < t2; // to have: face < edge
157     }
158   };
159   //================================================================================
160   /*!
161    * \brief Container of data dedicated to one source mesh
162    */
163   struct _ImportData
164   {
165     const SMESH_Mesh* _srcMesh;
166     StdMeshers_Import_1D::TNodeNodeMap _n2n;
167     StdMeshers_Import_1D::TElemElemMap _e2e;
168
169     set< SMESH_subMesh*, _SubLess > _subM; // submeshes relating to this srcMesh
170     set< SMESH_subMesh*, _SubLess > _copyMeshSubM; // submeshes requesting mesh copying
171     set< SMESH_subMesh*, _SubLess > _copyGroupSubM; // submeshes requesting group copying
172     set< SMESH_subMesh*, _SubLess > _computedSubM;
173
174     SMESHDS_SubMesh*     _importMeshSubDS; // submesh storing a copy of _srcMesh
175     int                  _importMeshSubID; // id of _importMeshSubDS
176
177     _ImportData(const SMESH_Mesh* srcMesh=0):
178       _srcMesh(srcMesh), _importMeshSubDS(0),_importMeshSubID(-1) {}
179
180     void removeImportedMesh( SMESHDS_Mesh* meshDS )
181     {
182       if ( !_importMeshSubDS ) return;
183       SMDS_ElemIteratorPtr eIt = _importMeshSubDS->GetElements();
184       while ( eIt->more() )
185         meshDS->RemoveFreeElement( eIt->next(), _importMeshSubDS, /*fromGroups=*/false );
186       SMDS_NodeIteratorPtr nIt = _importMeshSubDS->GetNodes();
187       while ( nIt->more() )
188         meshDS->RemoveFreeNode( nIt->next(), _importMeshSubDS, /*fromGroups=*/false );
189       _n2n.clear();
190       _e2e.clear();
191     }
192     void removeGroups( SMESH_subMesh* subM, const StdMeshers_ImportSource1D* srcHyp )
193     {
194       if ( !srcHyp ) return;
195       SMESH_Mesh*           tgtMesh = subM->GetFather();
196       const SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS();
197       const SMESHDS_Mesh* srcMeshDS = _srcMesh->GetMeshDS();
198       vector<SMESH_Group*>*  groups =
199         const_cast<StdMeshers_ImportSource1D*>(srcHyp)->GetResultGroups(*srcMeshDS,*tgtMeshDS);
200       if ( groups )
201       {
202         for ( unsigned i = 0; i < groups->size(); ++i )
203           tgtMesh->RemoveGroup( groups->at(i)->GetGroupDS()->GetID() );
204         groups->clear();
205       }
206     }
207     void trackHypParams( SMESH_subMesh* sm, const StdMeshers_ImportSource1D* srcHyp )
208     {
209       if ( !srcHyp ) return;
210       bool toCopyMesh, toCopyGroups;
211       srcHyp->GetCopySourceMesh(toCopyMesh, toCopyGroups);
212
213       if ( toCopyMesh )_copyMeshSubM.insert( sm );
214       else             _copyMeshSubM.erase( sm );
215
216       if ( toCopyGroups ) _copyGroupSubM.insert( sm );
217       else                _copyGroupSubM.erase( sm );
218     }
219     void addComputed( SMESH_subMesh* sm )
220     {
221       SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true,
222                                                                /*complexShapeFirst=*/true);
223       while ( smIt->more() )
224       {
225         sm = smIt->next();
226         switch ( sm->GetSubShape().ShapeType() )
227         {
228         case TopAbs_EDGE:
229         case TopAbs_FACE:
230           _subM.insert( sm );
231           if ( !sm->IsEmpty() )
232             _computedSubM.insert( sm );
233         case TopAbs_VERTEX:
234           break;
235         default:;
236         }
237       }
238     }
239   };
240   //================================================================================
241   /*!
242    * Listener notified on events relating to imported submesh
243    */
244   class _Listener : public SMESH_subMeshEventListener
245   {
246     typedef map< SMESH_Mesh*, list< _ImportData > > TMesh2ImpData;
247     TMesh2ImpData _tgtMesh2ImportData;
248
249     _Listener():SMESH_subMeshEventListener(/*isDeletable=*/false){}
250
251   public:
252     // return poiter to a static listener
253     static _Listener* get() { static _Listener theListener; return &theListener; }
254
255     static _ImportData* getImportData(const SMESH_Mesh* srcMesh, SMESH_Mesh* tgtMesh);
256
257     static void storeImportSubmesh(SMESH_subMesh*                   importSub,
258                                    const SMESH_Mesh*                srcMesh,
259                                    const StdMeshers_ImportSource1D* srcHyp);
260
261     virtual void ProcessEvent(const int                       event,
262                               const int                       eventType,
263                               SMESH_subMesh*                  subMesh,
264                               SMESH_subMeshEventListenerData* data,
265                               const SMESH_Hypothesis*         hyp);
266     void removeSubmesh( SMESH_subMesh* sm, _ListenerData* data );
267     void clearSubmesh ( SMESH_subMesh* sm, _ListenerData* data, bool clearAllSub );
268
269     // mark sm as missing src hyp with valid groups
270     static void waitHypModification(SMESH_subMesh* sm)
271     {
272       sm->SetEventListener
273         (get(), SMESH_subMeshEventListenerData::MakeData( sm, WAIT_HYP_MODIF ), sm);
274     }
275   };
276   //--------------------------------------------------------------------------------
277   /*!
278    * \brief Find or create ImportData for given meshes
279    */
280   _ImportData* _Listener::getImportData(const SMESH_Mesh* srcMesh,
281                                         SMESH_Mesh*       tgtMesh)
282   {
283     list< _ImportData >& dList = get()->_tgtMesh2ImportData[tgtMesh];
284     list< _ImportData >::iterator d = dList.begin();
285     for ( ; d != dList.end(); ++d )
286       if ( d->_srcMesh == srcMesh )
287         return &*d;
288     dList.push_back(_ImportData(srcMesh));
289     return &dList.back();
290   }
291
292   //--------------------------------------------------------------------------------
293   /*!
294    * \brief Remember an imported sub-mesh and set needed even listeners
295    *  \param importSub - submesh computed by Import algo
296    *  \param srcMesh - source mesh
297    *  \param srcHyp - ImportSource hypothesis
298    */
299   void _Listener::storeImportSubmesh(SMESH_subMesh*                   importSub,
300                                      const SMESH_Mesh*                srcMesh,
301                                      const StdMeshers_ImportSource1D* srcHyp)
302   {
303     // set listener to hear events of the submesh computed by "Import" algo
304     importSub->SetEventListener( get(), new _ListenerData(srcHyp), importSub );
305
306     // set a listener to hear events of the source mesh
307     SMESH_subMesh* smToNotify = importSub;
308     SMESH_subMesh* smToListen = srcMesh->GetSubMeshContaining(1);
309     SMESH_subMeshEventListenerData* data = new _ListenerData(srcHyp, LISTEN_SRC_MESH);
310     data->mySubMeshes.push_back( smToNotify );
311     importSub->SetEventListener( get(), data, smToListen );
312
313     // remeber the submesh importSub and its sub-submeshes
314     _ImportData* iData = _Listener::getImportData( srcMesh, importSub->GetFather());
315     iData->trackHypParams( importSub, srcHyp );
316     iData->addComputed( importSub );
317     if ( !iData->_copyMeshSubM.empty() && iData->_importMeshSubID < 1 )
318     {
319       SMESH_Mesh* tgtMesh = importSub->GetFather();
320       iData->_importMeshSubID = getSubmeshIDForCopiedMesh( srcMesh->GetMeshDS(),tgtMesh);
321       iData->_importMeshSubDS = tgtMesh->GetMeshDS()->NewSubMesh( iData->_importMeshSubID );
322     }
323   }
324   //--------------------------------------------------------------------------------
325   /*!
326    * \brief Remove imported mesh and/or groups if needed
327    *  \param sm - submesh loosing Import algo
328    *  \param data - data holding imported groups
329    */
330   void _Listener::removeSubmesh( SMESH_subMesh* sm, _ListenerData* data )
331   {
332     list< _ImportData > &  dList = _tgtMesh2ImportData[ sm->GetFather() ];
333     list< _ImportData >::iterator d = dList.begin();
334     for ( ; d != dList.end(); ++d )
335       if ( (*d)._subM.erase( sm ))
336       {
337         d->_computedSubM.erase( sm );
338         bool rmMesh   = d->_copyMeshSubM.erase( sm ) && d->_copyMeshSubM.empty();
339         bool rmGroups = (d->_copyGroupSubM.erase( sm ) && d->_copyGroupSubM.empty()) || rmMesh;
340         if ( rmMesh )
341           d->removeImportedMesh( sm->GetFather()->GetMeshDS() );
342         if ( rmGroups && data )
343           d->removeGroups( sm, data->_srcHyp );
344       }
345   }
346   //--------------------------------------------------------------------------------
347   /*!
348    * \brief Clear submeshes and remove imported mesh and/or groups if necessary
349    *  \param sm - cleared submesh
350    *  \param data - data holding imported groups
351    */
352   void _Listener::clearSubmesh(SMESH_subMesh* sm, _ListenerData* data, bool clearAllSub)
353   {
354     list< _ImportData > &  dList = _tgtMesh2ImportData[ sm->GetFather() ];
355     list< _ImportData >::iterator d = dList.begin();
356     for ( ; d != dList.end(); ++d )
357     {
358       if ( !d->_subM.count( sm )) continue;
359       if ( (*d)._computedSubM.erase( sm ) )
360       {
361         bool copyMesh = !d->_copyMeshSubM.empty();
362         if ( copyMesh || clearAllSub )
363         {
364           // remove imported mesh and groups
365           d->removeImportedMesh( sm->GetFather()->GetMeshDS() );
366
367           if ( data )
368             d->removeGroups( sm, data->_srcHyp );
369
370           // clear the rest submeshes
371           if ( !d->_computedSubM.empty() )
372           {
373             set< SMESH_subMesh*, _SubLess> subs;
374             subs.swap( d->_computedSubM ); // avoid recursion via events
375             while ( !subs.empty() )
376             {
377               SMESH_subMesh* subM = *subs.begin(); subs.erase( subs.begin() );
378               _ListenerData* hypData = (_ListenerData*) subM->GetEventListenerData( get() );
379               if ( hypData )
380                 d->removeGroups( sm, hypData->_srcHyp );
381
382               subM->ComputeStateEngine( SMESH_subMesh::CLEAN );
383               if ( subM->GetSubShape().ShapeType() == TopAbs_FACE )
384                 subM->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN );
385             }
386           }
387         }
388         sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
389         if ( sm->GetSubShape().ShapeType() == TopAbs_FACE )
390           sm->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN );
391       }
392       if ( data )
393         d->trackHypParams( sm, data->_srcHyp );
394       d->_n2n.clear();
395       d->_e2e.clear();
396     }
397   }
398   //--------------------------------------------------------------------------------
399   /*!
400    * \brief Remove imported mesh and/or groups
401    */
402   void _Listener::ProcessEvent(const int                       event,
403                                const int                       eventType,
404                                SMESH_subMesh*                  subMesh,
405                                SMESH_subMeshEventListenerData* data,
406                                const SMESH_Hypothesis*         /*hyp*/)
407   {
408     if ( data && data->myType == WAIT_HYP_MODIF )
409     {
410       // event of Import submesh
411       if ( SMESH_subMesh::MODIF_HYP  == event &&
412            SMESH_subMesh::ALGO_EVENT == eventType )
413       {
414         // re-call SetEventListener() to take into account valid parameters
415         // of ImportSource hypothesis
416         SMESH_Gen* gen = subMesh->GetFather()->GetGen();
417         if ( SMESH_Algo* algo = gen->GetAlgo(*subMesh->GetFather(), subMesh->GetSubShape()))
418           algo->SetEventListener( subMesh );
419       }
420     }
421     else if ( data && data->myType == LISTEN_SRC_MESH )
422     {
423       // event of source mesh
424       if ( SMESH_subMesh::COMPUTE_EVENT == eventType )
425       {
426         switch ( event ) {
427         case SMESH_subMesh::CLEAN:
428           // source mesh cleaned -> clean target mesh
429           clearSubmesh( data->mySubMeshes.front(), (_ListenerData*) data, /*all=*/true );
430           break;
431         case SMESH_subMesh::SUBMESH_COMPUTED: {
432           // source mesh computed -> reset FAILED state of Import submeshes to
433           // READY_TO_COMPUTE
434           SMESH_Mesh* srcMesh = subMesh->GetFather();
435           if ( srcMesh->NbEdges() > 0 || srcMesh->NbFaces() > 0 )
436           {
437             SMESH_Mesh* m = data->mySubMeshes.front()->GetFather();
438             if ( SMESH_subMesh* sm1 = m->GetSubMeshContaining(1))
439             {
440               sm1->ComputeStateEngine(SMESH_subMesh::SUBMESH_COMPUTED );
441               sm1->ComputeSubMeshStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
442             }
443           }
444           break;
445         }
446         default:;
447         }
448       }
449     }
450     else // event of Import submesh
451     {
452       // find out what happens: import hyp modified or removed
453       bool removeImport = false, modifHyp = false;
454       if ( SMESH_subMesh::ALGO_EVENT == eventType )
455         modifHyp = true;
456       if ( subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK )
457       {
458         removeImport = true;
459       }
460       else if (( SMESH_subMesh::REMOVE_ALGO == event ||
461                  SMESH_subMesh::REMOVE_FATHER_ALGO == event ) &&
462                SMESH_subMesh::ALGO_EVENT == eventType )
463       {
464         SMESH_Gen* gen = subMesh->GetFather()->GetGen();
465         SMESH_Algo* algo = gen->GetAlgo(*subMesh->GetFather(),subMesh->GetSubShape() );
466         removeImport = ( strncmp( "Import", algo->GetName(), 6 ) != 0 );
467       }
468
469       if ( removeImport )
470       {
471         // treate removal of Import algo from subMesh
472         removeSubmesh( subMesh, (_ListenerData*) data );
473       }
474       else if ( modifHyp ||
475                 ( SMESH_subMesh::CLEAN         == event &&
476                   SMESH_subMesh::COMPUTE_EVENT == eventType))
477       {
478         // treate modification of ImportSource hypothesis
479         clearSubmesh( subMesh, (_ListenerData*) data, /*all=*/false );
480       }
481       else if ( SMESH_subMesh::CHECK_COMPUTE_STATE == event &&
482                 SMESH_subMesh::COMPUTE_EVENT       == eventType )
483       {
484         // check compute state of all submeshes impoting from same src mesh;
485         // this is to take into account 1D computed submeshes hidden by 2D import algo;
486         // else source mesh is not copied as _subM.size != _computedSubM.size()
487         list< _ImportData > &  dList = _tgtMesh2ImportData[ subMesh->GetFather() ];
488         list< _ImportData >::iterator d = dList.begin();
489         for ( ; d != dList.end(); ++d )
490           if ( d->_subM.count( subMesh ))
491           {
492             set<SMESH_subMesh*,_SubLess>::iterator smIt = d->_subM.begin();
493             for( ; smIt != d->_subM.end(); ++smIt )
494               if ( (*smIt)->IsMeshComputed() )
495                 d->_computedSubM.insert( *smIt);
496           }
497       }
498     }
499   }
500
501   //================================================================================
502   /*!
503    * \brief Return an ID of submesh to store nodes and elements of a copied mesh
504    */
505   //================================================================================
506
507   int getSubmeshIDForCopiedMesh(const SMESHDS_Mesh* srcMeshDS,
508                                 SMESH_Mesh*         tgtMesh)
509   {
510     // To get SMESH_subMesh corresponding to srcMeshDS we need to have a shape
511     // for which SMESHDS_Mesh::IsGroupOfSubShapes() returns true.
512     // And this shape must be different from subshapes of the main shape.
513     // So we create a compound containing
514     // 1) some sub-shapes of SMESH_Mesh::PseudoShape() corresponding to
515     //    srcMeshDS->GetPersistentId()
516     // 2) the 1-st vertex of the main shape to assure
517     //    SMESHDS_Mesh::IsGroupOfSubShapes(shape)==true
518     TopoDS_Shape shapeForSrcMesh;
519     TopTools_IndexedMapOfShape pseudoSubShapes;
520     TopExp::MapShapes( SMESH_Mesh::PseudoShape(), pseudoSubShapes );
521
522     // index of pseudoSubShapes corresponding to srcMeshDS
523     int subIndex = srcMeshDS->GetPersistentId() % pseudoSubShapes.Extent();
524     int nbSubShapes = 1 + srcMeshDS->GetPersistentId() / pseudoSubShapes.Extent();
525
526     // try to find already present shapeForSrcMesh
527     SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS();
528     for ( int i = tgtMeshDS->MaxShapeIndex(); i > 0 && shapeForSrcMesh.IsNull(); --i )
529     {
530       const TopoDS_Shape& s = tgtMeshDS->IndexToShape(i);
531       if ( s.ShapeType() != TopAbs_COMPOUND ) break;
532       TopoDS_Iterator sSubIt( s );
533       for ( int iSub = 0; iSub < nbSubShapes && sSubIt.More(); ++iSub, sSubIt.Next() )
534         if ( pseudoSubShapes( subIndex+iSub ).IsSame( sSubIt.Value()))
535           if ( iSub+1 == nbSubShapes )
536           {
537             shapeForSrcMesh = s;
538             break;
539           }
540     }
541     if ( shapeForSrcMesh.IsNull() )
542     {
543       // make a new shapeForSrcMesh
544       BRep_Builder aBuilder;
545       TopoDS_Compound comp;
546       aBuilder.MakeCompound( comp );
547       shapeForSrcMesh = comp;
548       for ( int iSub = 0; iSub < nbSubShapes; ++iSub )
549         aBuilder.Add( comp, pseudoSubShapes( subIndex+iSub ));
550       TopExp_Explorer vExp( tgtMeshDS->ShapeToMesh(), TopAbs_VERTEX );
551       aBuilder.Add( comp, vExp.Current() );
552     }
553     SMESH_subMesh* sm = tgtMesh->GetSubMesh( shapeForSrcMesh );
554     SMESHDS_SubMesh* smDS = sm->GetSubMeshDS();
555     if ( !smDS )
556       smDS = tgtMeshDS->NewSubMesh( sm->GetId() );
557
558     // make ordinary submesh from a complex one
559     if ( smDS->IsComplexSubmesh() )
560     {
561       list< const SMESHDS_SubMesh* > subSM;
562       SMESHDS_SubMeshIteratorPtr smIt = smDS->GetSubMeshIterator();
563       while ( smIt->more() ) subSM.push_back( smIt->next() );
564       list< const SMESHDS_SubMesh* >::iterator sub = subSM.begin();
565       for ( ; sub != subSM.end(); ++sub)
566         smDS->RemoveSubMesh( *sub );
567     }
568     return sm->GetId();
569   }
570
571   //================================================================================
572   /*!
573    * \brief Return a submesh to store nodes and elements of a copied mesh
574    * and set event listeners in order to clear
575    * imported mesh and groups as soon as submesh state requires it
576    */
577   //================================================================================
578
579   SMESHDS_SubMesh* getSubmeshForCopiedMesh(const SMESH_Mesh*                    srcMesh,
580                                            SMESH_Mesh*                          tgtMesh,
581                                            const TopoDS_Shape&                  tgtShape,
582                                            StdMeshers_Import_1D::TNodeNodeMap*& n2n,
583                                            StdMeshers_Import_1D::TElemElemMap*& e2e,
584                                            bool &                               toCopyGroups)
585   {
586     StdMeshers_Import_1D::getMaps( srcMesh, tgtMesh, n2n,e2e );
587
588     _ImportData* iData = _Listener::getImportData(srcMesh,tgtMesh);
589
590     SMESH_subMesh* importedSM = tgtMesh->GetSubMesh( tgtShape );
591     iData->addComputed( importedSM );
592     if ( iData->_computedSubM.size() != iData->_subM.size() )
593       return 0; // not all submeshes computed yet
594
595     toCopyGroups = !iData->_copyGroupSubM.empty();
596
597     if ( !iData->_copyMeshSubM.empty())
598     {
599       // make submesh to store a copied mesh
600       int smID = getSubmeshIDForCopiedMesh( srcMesh->GetMeshDS(), tgtMesh );
601       SMESHDS_SubMesh* subDS = tgtMesh->GetMeshDS()->NewSubMesh( smID );
602
603       iData->_importMeshSubID = smID;
604       iData->_importMeshSubDS = subDS;
605       return subDS;
606     }
607     return 0;
608   }
609
610 } // namespace
611
612
613 //=============================================================================
614 /*!
615  * Import elements from the other mesh 
616  */
617 //=============================================================================
618
619 bool StdMeshers_Import_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & theShape)
620 {
621   if ( !_sourceHyp ) return false;
622
623   const vector<SMESH_Group*>& srcGroups = _sourceHyp->GetGroups();
624   if ( srcGroups.empty() )
625     return error("Invalid source groups");
626
627   SMESH_MesherHelper helper(theMesh);
628   helper.SetSubShape(theShape);
629   SMESHDS_Mesh* tgtMesh = theMesh.GetMeshDS();
630
631   const TopoDS_Edge& geomEdge = TopoDS::Edge( theShape );
632   const double edgeTol = BRep_Tool::Tolerance( geomEdge );
633   const int shapeID = tgtMesh->ShapeToIndex( geomEdge );
634
635   set<int> subShapeIDs;
636   subShapeIDs.insert( shapeID );
637
638   // get nodes on vertices
639   list < SMESH_TNodeXYZ > vertexNodes; 
640  list < SMESH_TNodeXYZ >::iterator vNIt;
641   TopExp_Explorer vExp( theShape, TopAbs_VERTEX );
642   for ( ; vExp.More(); vExp.Next() )
643   {
644     const TopoDS_Vertex& v = TopoDS::Vertex( vExp.Current() );
645     if ( !subShapeIDs.insert( tgtMesh->ShapeToIndex( v )).second )
646       continue; // closed edge
647     const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, tgtMesh );
648     if ( !n )
649     {
650       _gen->Compute(theMesh,v,/*anUpward=*/true);
651       n = SMESH_Algo::VertexNode( v, tgtMesh );
652       if ( !n ) return false; // very strange
653     }
654     vertexNodes.push_back( SMESH_TNodeXYZ( n ));
655   }
656
657   // import edges from groups
658   TNodeNodeMap* n2n;
659   TElemElemMap* e2e;
660   for ( int iG = 0; iG < srcGroups.size(); ++iG )
661   {
662     const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS();
663
664     const int meshID = srcGroup->GetMesh()->GetPersistentId();
665     const SMESH_Mesh* srcMesh = GetMeshByPersistentID( meshID );
666     if ( !srcMesh ) continue;
667     getMaps( srcMesh, &theMesh, n2n, e2e );
668
669     SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements();
670     vector<const SMDS_MeshNode*> newNodes;
671     SMDS_MeshNode *tmpNode = helper.AddNode(0,0,0);
672     double u;
673     while ( srcElems->more() ) // loop on group contents
674     {
675       const SMDS_MeshElement* edge = srcElems->next();
676       // find or create nodes of a new edge
677       newNodes.resize( edge->NbNodes() );
678       newNodes.back() = 0;
679       SMDS_MeshElement::iterator node = edge->begin_nodes();
680       for ( unsigned i = 0; i < newNodes.size(); ++i, ++node )
681       {
682         TNodeNodeMap::iterator n2nIt = n2n->insert( make_pair( *node, (SMDS_MeshNode*)0 )).first;
683         if ( n2nIt->second )
684         {
685           if ( !subShapeIDs.count( n2nIt->second->getshapeId() ))
686             break;
687         }
688         else
689         {
690           // find an existing vertex node
691           for ( vNIt = vertexNodes.begin(); vNIt != vertexNodes.end(); ++vNIt)
692             if ( vNIt->SquareDistance( *node ) < 10 * edgeTol * edgeTol)
693             {
694               (*n2nIt).second = vNIt->_node;
695               vertexNodes.erase( vNIt );
696               break;
697             }
698         }
699         if ( !n2nIt->second )
700         {
701           // find out if node lies on theShape
702           tmpNode->setXYZ( (*node)->X(), (*node)->Y(), (*node)->Z());
703           if ( helper.CheckNodeU( geomEdge, tmpNode, u, 10 * edgeTol, /*force=*/true ))
704           {
705             SMDS_MeshNode* newNode = tgtMesh->AddNode( (*node)->X(), (*node)->Y(), (*node)->Z());
706             n2nIt->second = newNode;
707             tgtMesh->SetNodeOnEdge( newNode, shapeID, u );
708           }
709         }
710         if ( !(newNodes[i] = n2nIt->second ))
711           break;
712       }
713       if ( !newNodes.back() )
714         continue; // not all nodes of edge lie on theShape
715
716       // make a new edge
717       SMDS_MeshElement * newEdge;
718       if ( newNodes.size() == 3 )
719         newEdge = tgtMesh->AddEdge( newNodes[0], newNodes[1], newNodes[2] );
720       else
721         newEdge = tgtMesh->AddEdge( newNodes[0], newNodes[1]);
722       tgtMesh->SetMeshElementOnShape( newEdge, shapeID );
723       e2e->insert( make_pair( edge, newEdge ));
724     }
725     helper.GetMeshDS()->RemoveNode(tmpNode);
726   }
727   if ( n2n->empty())
728     return error("Empty source groups");
729
730   // check if the whole geom edge is covered by imported segments;
731   // the check consist in passing by segments from one vetrex node to another
732   bool isEdgeMeshed = false;
733   if ( SMESHDS_SubMesh* tgtSM = tgtMesh->MeshElements( theShape ))
734   {
735     const TopoDS_Vertex& v = ( vExp.ReInit(), TopoDS::Vertex( vExp.Current() ));
736     const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, tgtMesh );
737     const SMDS_MeshElement* seg = 0;
738     SMDS_ElemIteratorPtr segIt = n->GetInverseElementIterator(SMDSAbs_Edge);
739     while ( segIt->more() && !seg )
740       if ( !tgtSM->Contains( seg = segIt->next()))
741         seg = 0;
742     int nbPassedSegs = 0;
743     while ( seg )
744     {
745       ++nbPassedSegs;
746       const SMDS_MeshNode* n2 = seg->GetNode(0);
747       n = ( n2 == n ? seg->GetNode(1) : n2 );
748       if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
749         break;
750       const SMDS_MeshElement* seg2 = 0;
751       segIt = n->GetInverseElementIterator(SMDSAbs_Edge);
752       while ( segIt->more() && !seg2 )
753         if ( seg == ( seg2 = segIt->next()))
754           seg2 = 0;
755       seg = seg2;
756     }
757     if (nbPassedSegs > 0 && tgtSM->NbElements() > nbPassedSegs )
758       return error( "Source elements overlap one another");
759
760     isEdgeMeshed = ( tgtSM->NbElements() == nbPassedSegs &&
761                      n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX );
762   }
763   if ( !isEdgeMeshed )
764     return error( "Source elements don't cover totally the geometrical edge" );
765
766   // copy meshes
767   vector<SMESH_Mesh*> srcMeshes = _sourceHyp->GetSourceMeshes();
768   for ( unsigned i = 0; i < srcMeshes.size(); ++i )
769     importMesh( srcMeshes[i], theMesh, _sourceHyp, theShape );
770
771   return true;
772 }
773
774 //================================================================================
775 /*!
776  * \brief Copy mesh and groups
777  */
778 //================================================================================
779
780 void StdMeshers_Import_1D::importMesh(const SMESH_Mesh*          srcMesh,
781                                       SMESH_Mesh &               tgtMesh,
782                                       StdMeshers_ImportSource1D* srcHyp,
783                                       const TopoDS_Shape&        tgtShape)
784 {
785   // get submesh to store the imported mesh
786   TNodeNodeMap* n2n;
787   TElemElemMap* e2e;
788   bool toCopyGroups;
789   SMESHDS_SubMesh* tgtSubMesh =
790     getSubmeshForCopiedMesh( srcMesh, &tgtMesh, tgtShape, n2n, e2e, toCopyGroups );
791   if ( !tgtSubMesh || tgtSubMesh->NbNodes() + tgtSubMesh->NbElements() > 0 )
792     return; // not to copy srcMeshDS twice
793
794   SMESHDS_Mesh* tgtMeshDS = tgtMesh.GetMeshDS();
795   SMESH_MeshEditor additor( &tgtMesh );
796
797   // 1. Copy mesh
798
799   vector<const SMDS_MeshNode*> newNodes;
800   const SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
801   SMDS_ElemIteratorPtr eIt = srcMeshDS->elementsIterator();
802   while ( eIt->more() )
803   {
804     const SMDS_MeshElement* elem = eIt->next();
805     TElemElemMap::iterator e2eIt = e2e->insert( make_pair( elem, (SMDS_MeshElement*)0 )).first;
806     if ( e2eIt->second ) continue; // already copied by Compute()
807     newNodes.resize( elem->NbNodes() );
808     SMDS_MeshElement::iterator node = elem->begin_nodes();
809     for ( unsigned i = 0; i < newNodes.size(); ++i, ++node )
810     {
811       TNodeNodeMap::iterator n2nIt = n2n->insert( make_pair( *node, (SMDS_MeshNode*)0 )).first;
812       if ( !n2nIt->second )
813       {
814         (*n2nIt).second = tgtMeshDS->AddNode( (*node)->X(), (*node)->Y(), (*node)->Z());
815         tgtSubMesh->AddNode( n2nIt->second );
816       }
817       newNodes[i] = n2nIt->second;
818     }
819     const SMDS_MeshElement* newElem =
820       tgtMeshDS->FindElement( newNodes, elem->GetType(), /*noMedium=*/false );
821     if ( !newElem )
822     {
823       newElem = additor.AddElement( newNodes, elem->GetType(), elem->IsPoly());
824       tgtSubMesh->AddElement( newElem );
825     }
826     if ( toCopyGroups )
827       (*e2eIt).second = newElem;
828   }
829   // copy free nodes
830   if ( srcMeshDS->NbNodes() > n2n->size() )
831   {
832     SMDS_NodeIteratorPtr nIt = srcMeshDS->nodesIterator();
833     while( nIt->more() )
834     {
835       const SMDS_MeshNode* node = nIt->next();
836       if ( node->NbInverseElements() == 0 )
837       {
838         const SMDS_MeshNode* newNode = tgtMeshDS->AddNode( node->X(), node->Y(), node->Z());
839         n2n->insert( make_pair( node, newNode ));
840         tgtSubMesh->AddNode( newNode );
841       }
842     }
843   }
844
845   // 2. Copy groups
846
847   vector<SMESH_Group*> resultGroups;
848   if ( toCopyGroups )
849   {
850     // collect names of existing groups to assure uniqueness of group names within a type
851     map< SMDSAbs_ElementType, set<string> > namesByType;
852     SMESH_Mesh::GroupIteratorPtr groupIt = tgtMesh.GetGroups();
853     while ( groupIt->more() )
854     {
855       SMESH_Group* tgtGroup = groupIt->next();
856       namesByType[ tgtGroup->GetGroupDS()->GetType() ].insert( tgtGroup->GetName() );
857     }
858     if (srcMesh)
859     {
860       SMESH_Mesh::GroupIteratorPtr groupIt = srcMesh->GetGroups();
861       while ( groupIt->more() )
862       {
863         SMESH_Group* srcGroup = groupIt->next();
864         SMESHDS_GroupBase* srcGroupDS = srcGroup->GetGroupDS();
865         string name = srcGroup->GetName();
866         int nb = 1;
867         while ( !namesByType[ srcGroupDS->GetType() ].insert( name ).second )
868           name = SMESH_Comment(srcGroup->GetName()) << "_imported_" << nb++;
869         SMESH_Group* newGroup = tgtMesh.AddGroup( srcGroupDS->GetType(), name.c_str(), nb );
870         SMESHDS_Group* newGroupDS = (SMESHDS_Group*)newGroup->GetGroupDS();
871         resultGroups.push_back( newGroup );
872
873         eIt = srcGroupDS->GetElements();
874         if ( srcGroupDS->GetType() == SMDSAbs_Node )
875           while (eIt->more())
876           {
877             TNodeNodeMap::iterator n2nIt = n2n->find((const SMDS_MeshNode*) eIt->next() );
878             if ( n2nIt != n2n->end() && n2nIt->second )
879               newGroupDS->SMDSGroup().Add((*n2nIt).second );
880           }
881         else
882           while (eIt->more())
883           {
884             TElemElemMap::iterator e2eIt = e2e->find( eIt->next() );
885             if ( e2eIt != e2e->end() && e2eIt->second )
886               newGroupDS->SMDSGroup().Add((*e2eIt).second );
887           }
888       }
889     }
890   }
891   n2n->clear();
892   e2e->clear();
893
894   // Remember created groups in order to remove them as soon as the srcHyp is
895   // modified or something other similar happens. This imformation must be persistent,
896   // for that store them in a hypothesis as it stores its values in the file anyway
897   srcHyp->StoreResultGroups( resultGroups, *srcMeshDS, *tgtMeshDS );
898 }
899
900 //=============================================================================
901 /*!
902  * \brief Set needed event listeners and create a submesh for a copied mesh
903  *
904  * This method is called only if a submesh has HYP_OK algo_state.
905  */
906 //=============================================================================
907
908 void StdMeshers_Import_1D::setEventListener(SMESH_subMesh*             subMesh, 
909                                             StdMeshers_ImportSource1D* sourceHyp)
910 {
911   if ( sourceHyp )
912   {
913     vector<SMESH_Mesh*> srcMeshes = sourceHyp->GetSourceMeshes();
914     if ( srcMeshes.empty() )
915       _Listener::waitHypModification( subMesh );
916     for ( unsigned i = 0; i < srcMeshes.size(); ++i )
917       // set a listener to remove the imported mesh and groups
918       _Listener::storeImportSubmesh( subMesh, srcMeshes[i], sourceHyp );
919   }
920 }
921 void StdMeshers_Import_1D::SetEventListener(SMESH_subMesh* subMesh)
922 {
923   if ( !_sourceHyp )
924   {
925     const TopoDS_Shape& tgtShape = subMesh->GetSubShape();
926     SMESH_Mesh*         tgtMesh  = subMesh->GetFather();
927     Hypothesis_Status aStatus;
928     CheckHypothesis( *tgtMesh, tgtShape, aStatus );
929   }
930   setEventListener( subMesh, _sourceHyp );
931 }
932
933 void StdMeshers_Import_1D::SubmeshRestored(SMESH_subMesh* subMesh)
934 {
935   SetEventListener(subMesh);
936 }
937
938 //=============================================================================
939 /*!
940  * Predict nb of mesh entities created by Compute()
941  */
942 //=============================================================================
943
944 bool StdMeshers_Import_1D::Evaluate(SMESH_Mesh &         theMesh,
945                                     const TopoDS_Shape & theShape,
946                                     MapShapeNbElems&     aResMap)
947 {
948   if ( !_sourceHyp ) return false;
949
950   const vector<SMESH_Group*>& srcGroups = _sourceHyp->GetGroups();
951   if ( srcGroups.empty() )
952     return error("Invalid source groups");
953
954   vector<int> aVec(SMDSEntity_Last,0);
955
956   bool toCopyMesh, toCopyGroups;
957   _sourceHyp->GetCopySourceMesh(toCopyMesh, toCopyGroups);
958   if ( toCopyMesh ) // the whole mesh is copied
959   {
960     vector<SMESH_Mesh*> srcMeshes = _sourceHyp->GetSourceMeshes();
961     for ( unsigned i = 0; i < srcMeshes.size(); ++i )
962     {
963       SMESH_subMesh* sm = getSubMeshOfCopiedMesh( theMesh, *srcMeshes[i]);
964       if ( !sm || aResMap.count( sm )) continue; // already counted
965       aVec.assign( SMDSEntity_Last, 0);
966       const SMDS_MeshInfo& aMeshInfo = srcMeshes[i]->GetMeshDS()->GetMeshInfo();
967       for (int i = 0; i < SMDSEntity_Last; i++)
968         aVec[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i);
969     }
970   }
971   else
972   {
973     SMESH_MesherHelper helper(theMesh);
974
975     const TopoDS_Edge& geomEdge = TopoDS::Edge( theShape );
976     const double edgeTol = helper.MaxTolerance( geomEdge );
977
978     // take into account nodes on vertices
979     TopExp_Explorer vExp( theShape, TopAbs_VERTEX );
980     for ( ; vExp.More(); vExp.Next() )
981       theMesh.GetSubMesh( vExp.Current())->Evaluate( aResMap );
982
983     // count edges imported from groups
984     int nbEdges = 0, nbQuadEdges = 0;
985     for ( int iG = 0; iG < srcGroups.size(); ++iG )
986     {
987       const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS();
988       SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements();
989       SMDS_MeshNode *tmpNode = helper.AddNode(0,0,0);
990       while ( srcElems->more() ) // loop on group contents
991       {
992         const SMDS_MeshElement* edge = srcElems->next();
993         // find out if edge is located on geomEdge by projecting
994         // a middle of edge to geomEdge
995         SMESH_TNodeXYZ p1( edge->GetNode(0));
996         SMESH_TNodeXYZ p2( edge->GetNode(1));
997         gp_XYZ middle = ( p1 + p2 ) / 2.;
998         tmpNode->setXYZ( middle.X(), middle.Y(), middle.Z());
999         double u = 0;
1000         if ( helper.CheckNodeU( geomEdge, tmpNode, u, 10 * edgeTol, /*force=*/true ))
1001           ++( edge->IsQuadratic() ? nbQuadEdges : nbEdges);
1002       }
1003       helper.GetMeshDS()->RemoveNode(tmpNode);
1004     }
1005
1006     int nbNodes = nbEdges + 2 * nbQuadEdges - 1;
1007
1008     aVec[SMDSEntity_Node     ] = nbNodes;
1009     aVec[SMDSEntity_Edge     ] = nbEdges;
1010     aVec[SMDSEntity_Quad_Edge] = nbQuadEdges;
1011   }
1012
1013   SMESH_subMesh * sm = theMesh.GetSubMesh(theShape);
1014   aResMap.insert(make_pair(sm,aVec));
1015
1016   return true;
1017 }
1018
1019 //================================================================================
1020 /*!
1021  * \brief Return node-node and element-element maps for import of geiven source mesh
1022  */
1023 //================================================================================
1024
1025 void StdMeshers_Import_1D::getMaps(const SMESH_Mesh* srcMesh,
1026                                    SMESH_Mesh*       tgtMesh,
1027                                    TNodeNodeMap*&    n2n,
1028                                    TElemElemMap*&    e2e)
1029 {
1030   _ImportData* iData = _Listener::getImportData(srcMesh,tgtMesh);
1031   n2n = &iData->_n2n;
1032   e2e = &iData->_e2e;
1033   if ( iData->_copyMeshSubM.empty() )
1034   {
1035     n2n->clear();
1036     e2e->clear();
1037   }
1038 }
1039
1040 //================================================================================
1041 /*!
1042  * \brief Return submesh corresponding to the copied mesh
1043  */
1044 //================================================================================
1045
1046 SMESH_subMesh* StdMeshers_Import_1D::getSubMeshOfCopiedMesh( SMESH_Mesh& tgtMesh,
1047                                                              SMESH_Mesh& srcMesh )
1048 {
1049   _ImportData* iData = _Listener::getImportData(&srcMesh,&tgtMesh);
1050   if ( iData->_copyMeshSubM.empty() ) return 0;
1051   SMESH_subMesh* sm = tgtMesh.GetSubMeshContaining( iData->_importMeshSubID );
1052   return sm;
1053 }
1054