Salome HOME
Regression of SALOME_TESTS/Grids/smesh/imps_09/K2
[modules/smesh.git] / src / StdMeshers / StdMeshers_Import_1D.cxx
1 // Copyright (C) 2007-2014  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, or (at your option) any later version.
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(), 0, /*fromGroups=*/false );
186       SMDS_NodeIteratorPtr nIt = _importMeshSubDS->GetNodes();
187       while ( nIt->more() )
188         meshDS->RemoveFreeNode( nIt->next(), 0, /*fromGroups=*/false );
189       _importMeshSubDS->Clear();
190       _n2n.clear();
191       _e2e.clear();
192     }
193     void removeGroups( SMESH_subMesh* subM, const StdMeshers_ImportSource1D* srcHyp )
194     {
195       if ( !srcHyp ) return;
196       SMESH_Mesh*           tgtMesh = subM->GetFather();
197       const SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS();
198       const SMESHDS_Mesh* srcMeshDS = _srcMesh->GetMeshDS();
199       vector<SMESH_Group*>*  groups =
200         const_cast<StdMeshers_ImportSource1D*>(srcHyp)->GetResultGroups(*srcMeshDS,*tgtMeshDS);
201       if ( groups )
202       {
203         for ( unsigned i = 0; i < groups->size(); ++i )
204           tgtMesh->RemoveGroup( groups->at(i)->GetGroupDS()->GetID() );
205         groups->clear();
206       }
207     }
208     void trackHypParams( SMESH_subMesh* sm, const StdMeshers_ImportSource1D* srcHyp )
209     {
210       if ( !srcHyp ) return;
211       bool toCopyMesh, toCopyGroups;
212       srcHyp->GetCopySourceMesh(toCopyMesh, toCopyGroups);
213
214       if ( toCopyMesh )_copyMeshSubM.insert( sm );
215       else             _copyMeshSubM.erase( sm );
216
217       if ( toCopyGroups ) _copyGroupSubM.insert( sm );
218       else                _copyGroupSubM.erase( sm );
219     }
220     void addComputed( SMESH_subMesh* sm )
221     {
222       SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true,
223                                                                /*complexShapeFirst=*/true);
224       while ( smIt->more() )
225       {
226         sm = smIt->next();
227         switch ( sm->GetSubShape().ShapeType() )
228         {
229         case TopAbs_EDGE:
230           if ( SMESH_Algo::isDegenerated( TopoDS::Edge( sm->GetSubShape() )))
231             continue;
232         case TopAbs_FACE:
233           _subM.insert( sm );
234           if ( !sm->IsEmpty() )
235             _computedSubM.insert( sm );
236         case TopAbs_VERTEX:
237           break;
238         default:;
239         }
240       }
241     }
242   };
243   //================================================================================
244   /*!
245    * Listener notified on events relating to imported submesh
246    */
247   class _Listener : public SMESH_subMeshEventListener
248   {
249     typedef map< SMESH_Mesh*, list< _ImportData > > TMesh2ImpData;
250     TMesh2ImpData _tgtMesh2ImportData;
251
252     _Listener():SMESH_subMeshEventListener(/*isDeletable=*/false,
253                                            "StdMeshers_Import_1D::_Listener") {}
254
255   public:
256     // return poiter to a static listener
257     static _Listener* get() { static _Listener theListener; return &theListener; }
258
259     static _ImportData* getImportData(const SMESH_Mesh* srcMesh, SMESH_Mesh* tgtMesh);
260
261     static void storeImportSubmesh(SMESH_subMesh*                   importSub,
262                                    const SMESH_Mesh*                srcMesh,
263                                    const StdMeshers_ImportSource1D* srcHyp);
264
265     virtual void ProcessEvent(const int                       event,
266                               const int                       eventType,
267                               SMESH_subMesh*                  subMesh,
268                               SMESH_subMeshEventListenerData* data,
269                               const SMESH_Hypothesis*         hyp);
270     void removeSubmesh( SMESH_subMesh* sm, _ListenerData* data );
271     void clearSubmesh ( SMESH_subMesh* sm, _ListenerData* data, bool clearAllSub );
272     void clearN2N     ( SMESH_Mesh* tgtMesh );
273
274     // mark sm as missing src hyp with valid groups
275     static void waitHypModification(SMESH_subMesh* sm)
276     {
277       sm->SetEventListener
278         (get(), SMESH_subMeshEventListenerData::MakeData( sm, WAIT_HYP_MODIF ), sm);
279     }
280   };
281   //--------------------------------------------------------------------------------
282   /*!
283    * \brief Find or create ImportData for given meshes
284    */
285   _ImportData* _Listener::getImportData(const SMESH_Mesh* srcMesh,
286                                         SMESH_Mesh*       tgtMesh)
287   {
288     list< _ImportData >& dList = get()->_tgtMesh2ImportData[tgtMesh];
289     list< _ImportData >::iterator d = dList.begin();
290     for ( ; d != dList.end(); ++d )
291       if ( d->_srcMesh == srcMesh )
292         return &*d;
293     dList.push_back(_ImportData(srcMesh));
294     return &dList.back();
295   }
296
297   //--------------------------------------------------------------------------------
298   /*!
299    * \brief Remember an imported sub-mesh and set needed even listeners
300    *  \param importSub - submesh computed by Import algo
301    *  \param srcMesh - source mesh
302    *  \param srcHyp - ImportSource hypothesis
303    */
304   void _Listener::storeImportSubmesh(SMESH_subMesh*                   importSub,
305                                      const SMESH_Mesh*                srcMesh,
306                                      const StdMeshers_ImportSource1D* srcHyp)
307   {
308     // set listener to hear events of the submesh computed by "Import" algo
309     importSub->SetEventListener( get(), new _ListenerData(srcHyp), importSub );
310
311     // set listeners to hear events of the source mesh
312     SMESH_subMesh* smToNotify = importSub;
313     vector<SMESH_subMesh*> smToListen = srcHyp->GetSourceSubMeshes( srcMesh );
314     for ( size_t i = 0; i < smToListen.size(); ++i )
315     {
316       SMESH_subMeshEventListenerData* data = new _ListenerData(srcHyp, LISTEN_SRC_MESH);
317       data->mySubMeshes.push_back( smToNotify );
318       importSub->SetEventListener( get(), data, smToListen[i] );
319     }
320     // remember the submesh importSub and its sub-submeshes
321     _ImportData* iData = _Listener::getImportData( srcMesh, importSub->GetFather());
322     iData->trackHypParams( importSub, srcHyp );
323     iData->addComputed( importSub );
324     if ( !iData->_copyMeshSubM.empty() && iData->_importMeshSubID < 1 )
325     {
326       SMESH_Mesh* tgtMesh = importSub->GetFather();
327       iData->_importMeshSubID = getSubmeshIDForCopiedMesh( srcMesh->GetMeshDS(),tgtMesh);
328       iData->_importMeshSubDS = tgtMesh->GetMeshDS()->NewSubMesh( iData->_importMeshSubID );
329     }
330   }
331   //--------------------------------------------------------------------------------
332   /*!
333    * \brief Remove imported mesh and/or groups if needed
334    *  \param sm - submesh loosing Import algo
335    *  \param data - data holding imported groups
336    */
337   void _Listener::removeSubmesh( SMESH_subMesh* sm, _ListenerData* data )
338   {
339     list< _ImportData > &  dList = _tgtMesh2ImportData[ sm->GetFather() ];
340     list< _ImportData >::iterator d = dList.begin();
341     for ( ; d != dList.end(); ++d )
342       if ( (*d)._subM.erase( sm ))
343       {
344         d->_computedSubM.erase( sm );
345         bool rmMesh   = d->_copyMeshSubM.erase( sm ) && d->_copyMeshSubM.empty();
346         bool rmGroups = (d->_copyGroupSubM.erase( sm ) && d->_copyGroupSubM.empty()) || rmMesh;
347         if ( rmMesh )
348           d->removeImportedMesh( sm->GetFather()->GetMeshDS() );
349         if ( rmGroups && data )
350           d->removeGroups( sm, data->_srcHyp );
351       }
352   }
353   //--------------------------------------------------------------------------------
354   /*!
355    * \brief Clear _ImportData::_n2n.
356    *        _n2n is usefull within one mesh.Compute() only
357    */
358   void _Listener::clearN2N( SMESH_Mesh* tgtMesh )
359   {
360     list< _ImportData >& dList = get()->_tgtMesh2ImportData[tgtMesh];
361     list< _ImportData >::iterator d = dList.begin();
362     for ( ; d != dList.end(); ++d )
363       d->_n2n.clear();
364   }
365   //--------------------------------------------------------------------------------
366   /*!
367    * \brief Clear submeshes and remove imported mesh and/or groups if necessary
368    *  \param sm - cleared submesh
369    *  \param data - data holding imported groups
370    */
371   void _Listener::clearSubmesh(SMESH_subMesh* sm, _ListenerData* data, bool clearAllSub)
372   {
373     list< _ImportData > &  dList = _tgtMesh2ImportData[ sm->GetFather() ];
374     list< _ImportData >::iterator d = dList.begin();
375     for ( ; d != dList.end(); ++d )
376     {
377       if ( !d->_subM.count( sm )) continue;
378       if ( (*d)._computedSubM.erase( sm ) )
379       {
380         bool copyMesh = !d->_copyMeshSubM.empty();
381         if ( copyMesh || clearAllSub )
382         {
383           // remove imported mesh and groups
384           d->removeImportedMesh( sm->GetFather()->GetMeshDS() );
385
386           if ( data )
387             d->removeGroups( sm, data->_srcHyp );
388
389           // clear the rest submeshes
390           if ( !d->_computedSubM.empty() )
391           {
392             d->_computedSubM.clear();
393             set< SMESH_subMesh*, _SubLess>::iterator sub = d->_subM.begin();
394             for ( ; sub != d->_subM.end(); ++sub )
395             {
396               SMESH_subMesh* subM = *sub;
397               _ListenerData* hypData = (_ListenerData*) subM->GetEventListenerData( get() );
398               if ( hypData )
399                 d->removeGroups( sm, hypData->_srcHyp );
400
401               subM->ComputeStateEngine( SMESH_subMesh::CLEAN );
402               if ( subM->GetSubShape().ShapeType() == TopAbs_FACE )
403                 subM->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN );
404             }
405           }
406         }
407         sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
408         if ( sm->GetSubShape().ShapeType() == TopAbs_FACE )
409           sm->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN );
410       }
411       if ( data )
412         d->trackHypParams( sm, data->_srcHyp );
413       d->_n2n.clear();
414       d->_e2e.clear();
415     }
416   }
417   //--------------------------------------------------------------------------------
418   /*!
419    * \brief Remove imported mesh and/or groups
420    */
421   void _Listener::ProcessEvent(const int                       event,
422                                const int                       eventType,
423                                SMESH_subMesh*                  subMesh,
424                                SMESH_subMeshEventListenerData* data,
425                                const SMESH_Hypothesis*         /*hyp*/)
426   {
427     if ( data && data->myType == WAIT_HYP_MODIF )
428     {
429       // event of Import submesh
430       if ( SMESH_subMesh::MODIF_HYP  == event &&
431            SMESH_subMesh::ALGO_EVENT == eventType )
432       {
433         // re-call SetEventListener() to take into account valid parameters
434         // of ImportSource hypothesis
435         if ( SMESH_Algo* algo = subMesh->GetAlgo() )
436           algo->SetEventListener( subMesh );
437       }
438     }
439     else if ( data && data->myType == LISTEN_SRC_MESH )
440     {
441       // event of source mesh
442       if ( SMESH_subMesh::COMPUTE_EVENT == eventType )
443       {
444         switch ( event ) {
445         case SMESH_subMesh::CLEAN:
446           // source mesh cleaned -> clean target mesh
447           clearSubmesh( data->mySubMeshes.front(), (_ListenerData*) data, /*all=*/true );
448           break;
449         case SMESH_subMesh::SUBMESH_COMPUTED: {
450           // source mesh computed -> reset FAILED state of Import submeshes to
451           // READY_TO_COMPUTE
452           SMESH_Mesh* srcMesh = subMesh->GetFather();
453           if ( srcMesh->NbEdges() > 0 || srcMesh->NbFaces() > 0 )
454           {
455             SMESH_Mesh* m = data->mySubMeshes.front()->GetFather();
456             if ( SMESH_subMesh* sm1 = m->GetSubMeshContaining(1))
457             {
458               sm1->ComputeStateEngine(SMESH_subMesh::SUBMESH_COMPUTED );
459               sm1->ComputeSubMeshStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
460             }
461           }
462           break;
463         }
464         default:;
465         }
466       }
467       if ( !data->mySubMeshes.empty() )
468         clearN2N( data->mySubMeshes.front()->GetFather() );
469     }
470     else // event of Import submesh
471     {
472       // find out what happens: import hyp modified or removed
473       bool removeImport = false, modifHyp = false;
474       if ( SMESH_subMesh::ALGO_EVENT == eventType )
475         modifHyp = true;
476       if ( subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK )
477       {
478         removeImport = true;
479       }
480       else if (( SMESH_subMesh::REMOVE_ALGO == event ||
481                  SMESH_subMesh::REMOVE_FATHER_ALGO == event ) &&
482                SMESH_subMesh::ALGO_EVENT == eventType )
483       {
484         SMESH_Algo* algo = subMesh->GetAlgo();
485         removeImport = ( strncmp( "Import", algo->GetName(), 6 ) != 0 );
486       }
487
488       if ( removeImport )
489       {
490         // treate removal of Import algo from subMesh
491         removeSubmesh( subMesh, (_ListenerData*) data );
492       }
493       else if ( modifHyp ||
494                 ( SMESH_subMesh::CLEAN         == event &&
495                   SMESH_subMesh::COMPUTE_EVENT == eventType))
496       {
497         // treate modification of ImportSource hypothesis
498         clearSubmesh( subMesh, (_ListenerData*) data, /*all=*/false );
499       }
500       else if ( SMESH_subMesh::CHECK_COMPUTE_STATE == event &&
501                 SMESH_subMesh::COMPUTE_EVENT       == eventType )
502       {
503         // check compute state of all submeshes impoting from same src mesh;
504         // this is to take into account 1D computed submeshes hidden by 2D import algo;
505         // else source mesh is not copied as _subM.size != _computedSubM.size()
506         list< _ImportData > &  dList = _tgtMesh2ImportData[ subMesh->GetFather() ];
507         list< _ImportData >::iterator d = dList.begin();
508         for ( ; d != dList.end(); ++d )
509           if ( d->_subM.count( subMesh ))
510           {
511             set<SMESH_subMesh*,_SubLess>::iterator smIt = d->_subM.begin();
512             for( ; smIt != d->_subM.end(); ++smIt )
513               if ( (*smIt)->IsMeshComputed() )
514                 d->_computedSubM.insert( *smIt);
515           }
516       }
517       // Clear _ImportData::_n2n if it's no more useful, i.e. when
518       // the event is not within mesh.Compute()
519       if ( SMESH_subMesh::ALGO_EVENT == eventType )
520         clearN2N( subMesh->GetFather() );
521     }
522   }
523
524   //================================================================================
525   /*!
526    * \brief Return an ID of submesh to store nodes and elements of a copied mesh
527    */
528   //================================================================================
529
530   int getSubmeshIDForCopiedMesh(const SMESHDS_Mesh* srcMeshDS,
531                                 SMESH_Mesh*         tgtMesh)
532   {
533     // To get SMESH_subMesh corresponding to srcMeshDS we need to have a shape
534     // for which SMESHDS_Mesh::IsGroupOfSubShapes() returns true.
535     // And this shape must be different from sub-shapes of the main shape.
536     // So we create a compound containing
537     // 1) some sub-shapes of SMESH_Mesh::PseudoShape() corresponding to
538     //    srcMeshDS->GetPersistentId()
539     // 2) the 1-st vertex of the main shape to assure
540     //    SMESHDS_Mesh::IsGroupOfSubShapes(shape)==true
541     TopoDS_Shape shapeForSrcMesh;
542     TopTools_IndexedMapOfShape pseudoSubShapes;
543     TopExp::MapShapes( SMESH_Mesh::PseudoShape(), pseudoSubShapes );
544
545     // index of pseudoSubShapes corresponding to srcMeshDS
546     int    subIndex = 1 + srcMeshDS->GetPersistentId() % pseudoSubShapes.Extent();
547     int nbSubShapes = 1 + srcMeshDS->GetPersistentId() / pseudoSubShapes.Extent();
548
549     // try to find already present shapeForSrcMesh
550     SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS();
551     for ( int i = tgtMeshDS->MaxShapeIndex(); i > 0 && shapeForSrcMesh.IsNull(); --i )
552     {
553       const TopoDS_Shape& s = tgtMeshDS->IndexToShape(i);
554       if ( s.ShapeType() != TopAbs_COMPOUND ) break;
555       TopoDS_Iterator sSubIt( s );
556       for ( int iSub = 0; iSub < nbSubShapes && sSubIt.More(); ++iSub, sSubIt.Next() )
557         if ( pseudoSubShapes( subIndex+iSub ).IsSame( sSubIt.Value()))
558           if ( iSub+1 == nbSubShapes )
559           {
560             shapeForSrcMesh = s;
561             break;
562           }
563     }
564     if ( shapeForSrcMesh.IsNull() )
565     {
566       // make a new shapeForSrcMesh
567       BRep_Builder aBuilder;
568       TopoDS_Compound comp;
569       aBuilder.MakeCompound( comp );
570       shapeForSrcMesh = comp;
571       for ( int iSub = 0; iSub < nbSubShapes; ++iSub )
572         if ( subIndex+iSub <= pseudoSubShapes.Extent() )
573           aBuilder.Add( comp, pseudoSubShapes( subIndex+iSub ));
574       TopExp_Explorer vExp( tgtMeshDS->ShapeToMesh(), TopAbs_VERTEX );
575       aBuilder.Add( comp, vExp.Current() );
576     }
577     SMESH_subMesh* sm = tgtMesh->GetSubMesh( shapeForSrcMesh );
578     SMESHDS_SubMesh* smDS = sm->GetSubMeshDS();
579     if ( !smDS )
580       smDS = tgtMeshDS->NewSubMesh( sm->GetId() );
581
582     // make ordinary submesh from a complex one
583     if ( smDS->IsComplexSubmesh() )
584     {
585       list< const SMESHDS_SubMesh* > subSM;
586       SMESHDS_SubMeshIteratorPtr smIt = smDS->GetSubMeshIterator();
587       while ( smIt->more() ) subSM.push_back( smIt->next() );
588       list< const SMESHDS_SubMesh* >::iterator sub = subSM.begin();
589       for ( ; sub != subSM.end(); ++sub)
590         smDS->RemoveSubMesh( *sub );
591     }
592     return sm->GetId();
593   }
594
595   //================================================================================
596   /*!
597    * \brief Return a submesh to store nodes and elements of a copied mesh
598    * and set event listeners in order to clear
599    * imported mesh and groups as soon as submesh state requires it
600    */
601   //================================================================================
602
603   SMESHDS_SubMesh* getSubmeshForCopiedMesh(const SMESH_Mesh*                    srcMesh,
604                                            SMESH_Mesh*                          tgtMesh,
605                                            const TopoDS_Shape&                  tgtShape,
606                                            StdMeshers_Import_1D::TNodeNodeMap*& n2n,
607                                            StdMeshers_Import_1D::TElemElemMap*& e2e,
608                                            bool &                               toCopyGroups)
609   {
610     StdMeshers_Import_1D::getMaps( srcMesh, tgtMesh, n2n,e2e );
611
612     _ImportData* iData = _Listener::getImportData(srcMesh,tgtMesh);
613
614     SMESH_subMesh* importedSM = tgtMesh->GetSubMesh( tgtShape );
615     iData->addComputed( importedSM );
616     if ( iData->_computedSubM.size() != iData->_subM.size() )
617       return 0; // not all submeshes computed yet
618
619     toCopyGroups = !iData->_copyGroupSubM.empty();
620
621     if ( !iData->_copyMeshSubM.empty())
622     {
623       // make submesh to store a copied mesh
624       int smID = getSubmeshIDForCopiedMesh( srcMesh->GetMeshDS(), tgtMesh );
625       SMESHDS_SubMesh* subDS = tgtMesh->GetMeshDS()->NewSubMesh( smID );
626
627       iData->_importMeshSubID = smID;
628       iData->_importMeshSubDS = subDS;
629       return subDS;
630     }
631     return 0;
632   }
633
634 } // namespace
635
636
637 //=============================================================================
638 /*!
639  * Import elements from the other mesh
640  */
641 //=============================================================================
642
643 bool StdMeshers_Import_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & theShape)
644 {
645   if ( !_sourceHyp ) return false;
646
647   //MESSAGE("---------> StdMeshers_Import_1D::Compute");
648   const vector<SMESH_Group*>& srcGroups = _sourceHyp->GetGroups(/*loaded=*/true);
649   if ( srcGroups.empty() )
650     return error("Invalid source groups");
651
652   SMESH_MesherHelper helper(theMesh);
653   helper.SetSubShape(theShape);
654   SMESHDS_Mesh* tgtMesh = theMesh.GetMeshDS();
655
656   const TopoDS_Edge& geomEdge = TopoDS::Edge( theShape );
657   const double edgeTol = BRep_Tool::Tolerance( geomEdge );
658   const int shapeID = tgtMesh->ShapeToIndex( geomEdge );
659
660   set<int> subShapeIDs;
661   subShapeIDs.insert( shapeID );
662
663   // get nodes on vertices
664   list < SMESH_TNodeXYZ > vertexNodes;
665   list < SMESH_TNodeXYZ >::iterator vNIt;
666   TopExp_Explorer vExp( theShape, TopAbs_VERTEX );
667   for ( ; vExp.More(); vExp.Next() )
668   {
669     const TopoDS_Vertex& v = TopoDS::Vertex( vExp.Current() );
670     if ( !subShapeIDs.insert( tgtMesh->ShapeToIndex( v )).second )
671       continue; // closed edge
672     const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, tgtMesh );
673     if ( !n )
674     {
675       _gen->Compute(theMesh,v,/*anUpward=*/true);
676       n = SMESH_Algo::VertexNode( v, tgtMesh );
677       //MESSAGE("_gen->Compute " << n);
678       if ( !n ) return false; // very strange
679     }
680     vertexNodes.push_back( SMESH_TNodeXYZ( n ));
681     //MESSAGE("SMESH_Algo::VertexNode " << n->GetID() << " " << n->X() << " " << n->Y() << " " << n->Z() );
682   }
683
684   // import edges from groups
685   TNodeNodeMap* n2n;
686   TElemElemMap* e2e;
687   for ( int iG = 0; iG < srcGroups.size(); ++iG )
688   {
689     const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS();
690
691     const int meshID = srcGroup->GetMesh()->GetPersistentId();
692     const SMESH_Mesh* srcMesh = GetMeshByPersistentID( meshID );
693     if ( !srcMesh ) continue;
694     getMaps( srcMesh, &theMesh, n2n, e2e );
695
696     SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements();
697     vector<const SMDS_MeshNode*> newNodes;
698     SMDS_MeshNode *tmpNode = helper.AddNode(0,0,0);
699     double u = 0.314159; // "random" value between 0 and 1, avoid 0 and 1, false detection possible on edge restrictions
700     while ( srcElems->more() ) // loop on group contents
701     {
702       const SMDS_MeshElement* edge = srcElems->next();
703       // find or create nodes of a new edge
704       newNodes.resize( edge->NbNodes() );
705       //MESSAGE("edge->NbNodes " << edge->NbNodes());
706       newNodes.back() = 0;
707       SMDS_MeshElement::iterator node = edge->begin_nodes();
708       SMESH_TNodeXYZ a(edge->GetNode(0));
709       // --- define a tolerance relative to the length of an edge
710       double mytol = a.Distance(edge->GetNode(edge->NbNodes()-1))/25;
711       //mytol = max(1.E-5, 10*edgeTol); // too strict and not necessary
712       //MESSAGE("mytol = " << mytol);
713       for ( unsigned i = 0; i < newNodes.size(); ++i, ++node )
714       {
715         TNodeNodeMap::iterator n2nIt = n2n->insert( make_pair( *node, (SMDS_MeshNode*)0 )).first;
716         if ( n2nIt->second )
717         {
718           if ( !subShapeIDs.count( n2nIt->second->getshapeId() ))
719             break;
720         }
721         else
722         {
723           // find an existing vertex node
724           double checktol = max(1.E-10, 10*edgeTol*edgeTol);
725           for ( vNIt = vertexNodes.begin(); vNIt != vertexNodes.end(); ++vNIt)
726             if ( vNIt->SquareDistance( *node ) < checktol)
727             {
728               //MESSAGE("SquareDistance " << vNIt->SquareDistance( *node ) << " checktol " << checktol <<" "<<vNIt->X()<<" "<<vNIt->Y()<<" "<<vNIt->Z());
729               (*n2nIt).second = vNIt->_node;
730               vertexNodes.erase( vNIt );
731               break;
732             }
733             else if ( vNIt->SquareDistance( *node ) < 10*checktol)
734               MESSAGE("SquareDistance missed" << vNIt->SquareDistance( *node ) << " checktol " << checktol <<" "<<vNIt->X()<<" "<<vNIt->Y()<<" "<<vNIt->Z());
735         }
736         if ( !n2nIt->second )
737         {
738           // find out if node lies on theShape
739           //double dxyz[4];
740           tmpNode->setXYZ( (*node)->X(), (*node)->Y(), (*node)->Z());
741           if ( helper.CheckNodeU( geomEdge, tmpNode, u, mytol, /*force=*/true)) // , dxyz )) // dxyz used for debug purposes
742           {
743             SMDS_MeshNode* newNode = tgtMesh->AddNode( (*node)->X(), (*node)->Y(), (*node)->Z());
744             n2nIt->second = newNode;
745             tgtMesh->SetNodeOnEdge( newNode, shapeID, u );
746             //MESSAGE("u=" << u << " " << newNode->X()<< " " << newNode->Y()<< " " << newNode->Z());
747             //MESSAGE("d=" << dxyz[0] << " " << dxyz[1] << " " << dxyz[2] << " " << dxyz[3]);
748           }
749         }
750         if ( !(newNodes[i] = n2nIt->second ))
751           break;
752       }
753       if ( !newNodes.back() )
754       {
755         //MESSAGE("not all nodes of edge lie on theShape");
756         continue; // not all nodes of edge lie on theShape
757       }
758
759       // make a new edge
760       SMDS_MeshElement * newEdge;
761       if ( newNodes.size() == 3 )
762         newEdge = tgtMesh->AddEdge( newNodes[0], newNodes[1], newNodes[2] );
763       else
764         newEdge = tgtMesh->AddEdge( newNodes[0], newNodes[1]);
765       //MESSAGE("add Edge " << newNodes[0]->GetID() << " " << newNodes[1]->GetID());
766       tgtMesh->SetMeshElementOnShape( newEdge, shapeID );
767       e2e->insert( make_pair( edge, newEdge ));
768     }
769     helper.GetMeshDS()->RemoveNode(tmpNode);
770   }
771   if ( n2n->empty())
772     return error("Empty source groups");
773
774   // check if the whole geom edge is covered by imported segments;
775   // the check consist in passing by segments from one vetrex node to another
776   bool isEdgeMeshed = false;
777   if ( SMESHDS_SubMesh* tgtSM = tgtMesh->MeshElements( theShape ))
778   {
779     const TopoDS_Vertex& v = ( vExp.ReInit(), TopoDS::Vertex( vExp.Current() ));
780     const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, tgtMesh );
781     const SMDS_MeshElement* seg = 0;
782     SMDS_ElemIteratorPtr segIt = n->GetInverseElementIterator(SMDSAbs_Edge);
783     while ( segIt->more() && !seg )
784       if ( !tgtSM->Contains( seg = segIt->next()))
785         seg = 0;
786     int nbPassedSegs = 0;
787     while ( seg )
788     {
789       ++nbPassedSegs;
790       const SMDS_MeshNode* n2 = seg->GetNode(0);
791       n = ( n2 == n ? seg->GetNode(1) : n2 );
792       if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
793         break;
794       const SMDS_MeshElement* seg2 = 0;
795       segIt = n->GetInverseElementIterator(SMDSAbs_Edge);
796       while ( segIt->more() && !seg2 )
797         if ( seg == ( seg2 = segIt->next()))
798           seg2 = 0;
799       seg = seg2;
800     }
801     if (nbPassedSegs > 0 && tgtSM->NbElements() > nbPassedSegs )
802       return error( "Source elements overlap one another");
803
804     isEdgeMeshed = ( tgtSM->NbElements() == nbPassedSegs &&
805                      n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX );
806   }
807   if ( !isEdgeMeshed )
808     return error( "Source elements don't cover totally the geometrical edge" );
809
810   // copy meshes
811   vector<SMESH_Mesh*> srcMeshes = _sourceHyp->GetSourceMeshes();
812   for ( unsigned i = 0; i < srcMeshes.size(); ++i )
813     importMesh( srcMeshes[i], theMesh, _sourceHyp, theShape );
814
815   return true;
816 }
817
818 //================================================================================
819 /*!
820  * \brief Copy mesh and groups
821  */
822 //================================================================================
823
824 void StdMeshers_Import_1D::importMesh(const SMESH_Mesh*          srcMesh,
825                                       SMESH_Mesh &               tgtMesh,
826                                       StdMeshers_ImportSource1D* srcHyp,
827                                       const TopoDS_Shape&        tgtShape)
828 {
829   // get submesh to store the imported mesh
830   TNodeNodeMap* n2n;
831   TElemElemMap* e2e;
832   bool toCopyGroups;
833   SMESHDS_SubMesh* tgtSubMesh =
834     getSubmeshForCopiedMesh( srcMesh, &tgtMesh, tgtShape, n2n, e2e, toCopyGroups );
835   if ( !tgtSubMesh || tgtSubMesh->NbNodes() + tgtSubMesh->NbElements() > 0 )
836     return; // not to copy srcMeshDS twice
837
838   SMESHDS_Mesh* tgtMeshDS = tgtMesh.GetMeshDS();
839   SMESH_MeshEditor additor( &tgtMesh );
840
841   // 1. Copy mesh
842
843   vector<const SMDS_MeshNode*> newNodes;
844   const SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
845   SMDS_ElemIteratorPtr eIt = srcMeshDS->elementsIterator();
846   while ( eIt->more() )
847   {
848     const SMDS_MeshElement* elem = eIt->next();
849     TElemElemMap::iterator e2eIt = e2e->insert( make_pair( elem, (SMDS_MeshElement*)0 )).first;
850     if ( e2eIt->second ) continue; // already copied by Compute()
851     newNodes.resize( elem->NbNodes() );
852     SMDS_MeshElement::iterator node = elem->begin_nodes();
853     for ( unsigned i = 0; i < newNodes.size(); ++i, ++node )
854     {
855       TNodeNodeMap::iterator n2nIt = n2n->insert( make_pair( *node, (SMDS_MeshNode*)0 )).first;
856       if ( !n2nIt->second )
857       {
858         (*n2nIt).second = tgtMeshDS->AddNode( (*node)->X(), (*node)->Y(), (*node)->Z());
859         tgtSubMesh->AddNode( n2nIt->second );
860       }
861       newNodes[i] = n2nIt->second;
862     }
863     const SMDS_MeshElement* newElem =
864       tgtMeshDS->FindElement( newNodes, elem->GetType(), /*noMedium=*/false );
865     if ( !newElem )
866     {
867       newElem = additor.AddElement( newNodes, elem->GetType(), elem->IsPoly());
868       tgtSubMesh->AddElement( newElem );
869     }
870     if ( toCopyGroups )
871       (*e2eIt).second = newElem;
872   }
873   // copy free nodes
874   if ( srcMeshDS->NbNodes() > n2n->size() )
875   {
876     SMDS_NodeIteratorPtr nIt = srcMeshDS->nodesIterator();
877     while( nIt->more() )
878     {
879       const SMDS_MeshNode* node = nIt->next();
880       if ( node->NbInverseElements() == 0 )
881       {
882         const SMDS_MeshNode* newNode = tgtMeshDS->AddNode( node->X(), node->Y(), node->Z());
883         n2n->insert( make_pair( node, newNode ));
884         tgtSubMesh->AddNode( newNode );
885       }
886     }
887   }
888
889   // 2. Copy groups
890
891   vector<SMESH_Group*> resultGroups;
892   if ( toCopyGroups )
893   {
894     // collect names of existing groups to assure uniqueness of group names within a type
895     map< SMDSAbs_ElementType, set<string> > namesByType;
896     SMESH_Mesh::GroupIteratorPtr groupIt = tgtMesh.GetGroups();
897     while ( groupIt->more() )
898     {
899       SMESH_Group* tgtGroup = groupIt->next();
900       namesByType[ tgtGroup->GetGroupDS()->GetType() ].insert( tgtGroup->GetName() );
901     }
902     if (srcMesh)
903     {
904       SMESH_Mesh::GroupIteratorPtr groupIt = srcMesh->GetGroups();
905       while ( groupIt->more() )
906       {
907         SMESH_Group* srcGroup = groupIt->next();
908         SMESHDS_GroupBase* srcGroupDS = srcGroup->GetGroupDS();
909         string name = srcGroup->GetName();
910         int nb = 1;
911         while ( !namesByType[ srcGroupDS->GetType() ].insert( name ).second )
912           name = SMESH_Comment(srcGroup->GetName()) << "_imported_" << nb++;
913         SMESH_Group* newGroup = tgtMesh.AddGroup( srcGroupDS->GetType(), name.c_str(), nb );
914         SMESHDS_Group* newGroupDS = (SMESHDS_Group*)newGroup->GetGroupDS();
915         resultGroups.push_back( newGroup );
916
917         eIt = srcGroupDS->GetElements();
918         if ( srcGroupDS->GetType() == SMDSAbs_Node )
919           while (eIt->more())
920           {
921             TNodeNodeMap::iterator n2nIt = n2n->find((const SMDS_MeshNode*) eIt->next() );
922             if ( n2nIt != n2n->end() && n2nIt->second )
923               newGroupDS->SMDSGroup().Add((*n2nIt).second );
924           }
925         else
926           while (eIt->more())
927           {
928             TElemElemMap::iterator e2eIt = e2e->find( eIt->next() );
929             if ( e2eIt != e2e->end() && e2eIt->second )
930               newGroupDS->SMDSGroup().Add((*e2eIt).second );
931           }
932       }
933     }
934   }
935   n2n->clear();
936   e2e->clear();
937
938   // Remember created groups in order to remove them as soon as the srcHyp is
939   // modified or something other similar happens. This imformation must be persistent,
940   // for that store them in a hypothesis as it stores its values in the file anyway
941   srcHyp->StoreResultGroups( resultGroups, *srcMeshDS, *tgtMeshDS );
942 }
943
944 //=============================================================================
945 /*!
946  * \brief Set needed event listeners and create a submesh for a copied mesh
947  *
948  * This method is called only if a submesh has HYP_OK algo_state.
949  */
950 //=============================================================================
951
952 void StdMeshers_Import_1D::setEventListener(SMESH_subMesh*             subMesh,
953                                             StdMeshers_ImportSource1D* sourceHyp)
954 {
955   if ( sourceHyp )
956   {
957     vector<SMESH_Mesh*> srcMeshes = sourceHyp->GetSourceMeshes();
958     if ( srcMeshes.empty() )
959       _Listener::waitHypModification( subMesh );
960     for ( unsigned i = 0; i < srcMeshes.size(); ++i )
961       // set a listener to remove the imported mesh and groups
962       _Listener::storeImportSubmesh( subMesh, srcMeshes[i], sourceHyp );
963   }
964 }
965 void StdMeshers_Import_1D::SetEventListener(SMESH_subMesh* subMesh)
966 {
967   if ( !_sourceHyp )
968   {
969     const TopoDS_Shape& tgtShape = subMesh->GetSubShape();
970     SMESH_Mesh*         tgtMesh  = subMesh->GetFather();
971     Hypothesis_Status aStatus;
972     CheckHypothesis( *tgtMesh, tgtShape, aStatus );
973   }
974   setEventListener( subMesh, _sourceHyp );
975 }
976
977 void StdMeshers_Import_1D::SubmeshRestored(SMESH_subMesh* subMesh)
978 {
979   SetEventListener(subMesh);
980 }
981
982 //=============================================================================
983 /*!
984  * Predict nb of mesh entities created by Compute()
985  */
986 //=============================================================================
987
988 bool StdMeshers_Import_1D::Evaluate(SMESH_Mesh &         theMesh,
989                                     const TopoDS_Shape & theShape,
990                                     MapShapeNbElems&     aResMap)
991 {
992   if ( !_sourceHyp ) return false;
993
994   const vector<SMESH_Group*>& srcGroups = _sourceHyp->GetGroups();
995   if ( srcGroups.empty() )
996     return error("Invalid source groups");
997
998   vector<int> aVec(SMDSEntity_Last,0);
999
1000   bool toCopyMesh, toCopyGroups;
1001   _sourceHyp->GetCopySourceMesh(toCopyMesh, toCopyGroups);
1002   if ( toCopyMesh ) // the whole mesh is copied
1003   {
1004     vector<SMESH_Mesh*> srcMeshes = _sourceHyp->GetSourceMeshes();
1005     for ( unsigned i = 0; i < srcMeshes.size(); ++i )
1006     {
1007       SMESH_subMesh* sm = getSubMeshOfCopiedMesh( theMesh, *srcMeshes[i]);
1008       if ( !sm || aResMap.count( sm )) continue; // already counted
1009       aVec.assign( SMDSEntity_Last, 0);
1010       const SMDS_MeshInfo& aMeshInfo = srcMeshes[i]->GetMeshDS()->GetMeshInfo();
1011       for (int i = 0; i < SMDSEntity_Last; i++)
1012         aVec[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i);
1013     }
1014   }
1015   else
1016   {
1017     SMESH_MesherHelper helper(theMesh);
1018
1019     const TopoDS_Edge& geomEdge = TopoDS::Edge( theShape );
1020     const double edgeTol = helper.MaxTolerance( geomEdge );
1021
1022     // take into account nodes on vertices
1023     TopExp_Explorer vExp( theShape, TopAbs_VERTEX );
1024     for ( ; vExp.More(); vExp.Next() )
1025       theMesh.GetSubMesh( vExp.Current())->Evaluate( aResMap );
1026
1027     // count edges imported from groups
1028     int nbEdges = 0, nbQuadEdges = 0;
1029     for ( int iG = 0; iG < srcGroups.size(); ++iG )
1030     {
1031       const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS();
1032       SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements();
1033       SMDS_MeshNode *tmpNode = helper.AddNode(0,0,0);
1034       while ( srcElems->more() ) // loop on group contents
1035       {
1036         const SMDS_MeshElement* edge = srcElems->next();
1037         // find out if edge is located on geomEdge by projecting
1038         // a middle of edge to geomEdge
1039         SMESH_TNodeXYZ p1( edge->GetNode(0));
1040         SMESH_TNodeXYZ p2( edge->GetNode(1));
1041         gp_XYZ middle = ( p1 + p2 ) / 2.;
1042         tmpNode->setXYZ( middle.X(), middle.Y(), middle.Z());
1043         double u = 0;
1044         if ( helper.CheckNodeU( geomEdge, tmpNode, u, 10 * edgeTol, /*force=*/true ))
1045           ++( edge->IsQuadratic() ? nbQuadEdges : nbEdges);
1046       }
1047       helper.GetMeshDS()->RemoveNode(tmpNode);
1048     }
1049
1050     int nbNodes = nbEdges + 2 * nbQuadEdges - 1;
1051
1052     aVec[SMDSEntity_Node     ] = nbNodes;
1053     aVec[SMDSEntity_Edge     ] = nbEdges;
1054     aVec[SMDSEntity_Quad_Edge] = nbQuadEdges;
1055   }
1056
1057   SMESH_subMesh * sm = theMesh.GetSubMesh(theShape);
1058   aResMap.insert(make_pair(sm,aVec));
1059
1060   return true;
1061 }
1062
1063 //================================================================================
1064 /*!
1065  * \brief Return node-node and element-element maps for import of geiven source mesh
1066  */
1067 //================================================================================
1068
1069 void StdMeshers_Import_1D::getMaps(const SMESH_Mesh* srcMesh,
1070                                    SMESH_Mesh*       tgtMesh,
1071                                    TNodeNodeMap*&    n2n,
1072                                    TElemElemMap*&    e2e)
1073 {
1074   _ImportData* iData = _Listener::getImportData(srcMesh,tgtMesh);
1075   n2n = &iData->_n2n;
1076   e2e = &iData->_e2e;
1077   if ( iData->_copyMeshSubM.empty() )
1078   {
1079     // n2n->clear(); -- for sharing nodes on EDGEs
1080     e2e->clear();
1081   }
1082 }
1083
1084 //================================================================================
1085 /*!
1086  * \brief Return submesh corresponding to the copied mesh
1087  */
1088 //================================================================================
1089
1090 SMESH_subMesh* StdMeshers_Import_1D::getSubMeshOfCopiedMesh( SMESH_Mesh& tgtMesh,
1091                                                              SMESH_Mesh& srcMesh )
1092 {
1093   _ImportData* iData = _Listener::getImportData(&srcMesh,&tgtMesh);
1094   if ( iData->_copyMeshSubM.empty() ) return 0;
1095   SMESH_subMesh* sm = tgtMesh.GetSubMeshContaining( iData->_importMeshSubID );
1096   return sm;
1097 }
1098