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