Salome HOME
Update of CheckDone
[modules/smesh.git] / src / StdMeshers / StdMeshers_Import_1D.cxx
1 // Copyright (C) 2007-2022  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 : implementation 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_MeshEditor.hxx"
40 #include "SMESH_MesherHelper.hxx"
41 #include "SMESH_Octree.hxx"
42 #include "SMESH_subMesh.hxx"
43 #include "SMESH_subMeshEventListener.hxx"
44
45 #include "Utils_SALOME_Exception.hxx"
46 #include "utilities.h"
47
48 #include <BRepAdaptor_Curve.hxx>
49 #include <BRep_Builder.hxx>
50 #include <BRep_Tool.hxx>
51 #include <BndLib_Add3dCurve.hxx>
52 #include <GCPnts_TangentialDeflection.hxx>
53 #include <ShapeAnalysis_Curve.hxx>
54 #include <TopExp.hxx>
55 #include <TopExp_Explorer.hxx>
56 #include <TopoDS.hxx>
57 #include <TopoDS_Compound.hxx>
58 #include <TopoDS_Edge.hxx>
59 #include <TopoDS_Vertex.hxx>
60
61 using namespace std;
62
63 //================================================================================
64 namespace // INTERNAL STUFF
65 //================================================================================
66 {
67   /*!
68    * \brief Compute point position on a curve. Use octree to fast reject far points
69    */
70   class CurveProjector : public SMESH_Octree
71   {
72   public:
73     CurveProjector( const TopoDS_Edge& edge, double enlarge );
74
75     bool IsOnCurve( const gp_XYZ& point, double & distance2, double & u );
76
77     bool IsOut( const gp_XYZ& point ) const { return getBox()->IsOut( point ); }
78
79   protected:
80     CurveProjector() {}
81     SMESH_Octree* newChild() const { return new CurveProjector; }
82     void          buildChildrenData();
83     Bnd_B3d*      buildRootBox();
84
85   private:
86     struct CurveSegment : public Bnd_B3d
87     {
88       double _chord, _chord2, _length2;
89       gp_Pnt _pFirst, _pLast;
90       gp_Lin _line;
91       Handle(Geom_Curve) _curve;
92
93       CurveSegment() {}
94       void Init( const gp_Pnt& pf, const gp_Pnt& pl,
95                  double uf, double ul, double tol, Handle(Geom_Curve)& curve );
96       bool IsOn( const gp_XYZ& point, double & distance2, double & u );
97       bool IsInContact( const Bnd_B3d& bb );
98     };
99     std::vector< CurveSegment > _segments;
100   };
101
102   //===============================================================================
103   /*!
104    * \brief Create an octree of curve segments
105    */
106   //================================================================================
107
108   CurveProjector::CurveProjector( const TopoDS_Edge& edge, double enlarge )
109     :SMESH_Octree( 0 )
110   {
111     double f,l;
112     Handle(Geom_Curve) curve = BRep_Tool::Curve( edge, f, l );
113     double curDeflect = 0.3; // Curvature deflection
114     double angDeflect = 1e+100; // Angular deflection - don't control chordal error
115     GCPnts_TangentialDeflection div( BRepAdaptor_Curve( edge ), angDeflect, curDeflect );
116     _segments.resize( div.NbPoints() - 1 );
117     for ( int i = 1; i < div.NbPoints(); ++i )
118       try {
119         _segments[ i - 1 ].Init( div.Value( i ),     div.Value( i+1 ),
120                                  div.Parameter( i ), div.Parameter( i+1 ),
121                                  enlarge, curve );
122       }
123       catch ( Standard_Failure ) {
124         _segments.resize( _segments.size() - 1 );
125         --i;
126       }
127     if ( _segments.size() < 3 )
128       myIsLeaf = true;
129
130     compute();
131
132     if ( _segments.size() == 1 )
133       myBox->Enlarge( enlarge );
134   }
135
136   //================================================================================
137   /*!
138    * \brief Return the maximal box
139    */
140   //================================================================================
141
142   Bnd_B3d* CurveProjector::buildRootBox()
143   {
144     Bnd_B3d* box = new Bnd_B3d;
145     for ( size_t i = 0; i < _segments.size(); ++i )
146       box->Add( _segments[i] );
147     return box;
148   }
149
150   //================================================================================
151   /*!
152    * \brief Redistribute segments among children
153    */
154   //================================================================================
155
156   void CurveProjector::buildChildrenData()
157   {
158     bool allIn = true;
159     for ( size_t i = 0; i < _segments.size(); ++i )
160     {
161       for (int j = 0; j < 8; j++)
162       {
163         if ( _segments[i].IsInContact( *myChildren[j]->getBox() ))
164           ((CurveProjector*)myChildren[j])->_segments.push_back( _segments[i]);
165         else
166           allIn = false;
167       }
168     }
169     if ( allIn && _segments.size() < 3 )
170     {
171       myIsLeaf = true;
172       for (int j = 0; j < 8; j++)
173         static_cast<CurveProjector*>( myChildren[j])->myIsLeaf = true;
174     }
175     else
176     {
177       SMESHUtils::FreeVector( _segments ); // = _segments.clear() + free memory
178
179       for (int j = 0; j < 8; j++)
180       {
181         CurveProjector* child = static_cast<CurveProjector*>( myChildren[j]);
182         if ( child->_segments.size() < 3 )
183           child->myIsLeaf = true;
184       }
185     }
186   }
187
188   //================================================================================
189   /*!
190    * \brief Return true if a point is close to the curve
191    *  \param [in] point - the point
192    *  \param [out] distance2 - distance to the curve
193    *  \param [out] u - parameter on the curve
194    *  \return bool - is the point is close to the curve
195    */
196   //================================================================================
197
198   bool CurveProjector::IsOnCurve( const gp_XYZ& point, double & distance2, double & u )
199   {
200     if ( getBox()->IsOut( point ))
201       return false;
202
203     bool ok = false;
204     double dist2, param;
205     distance2 = Precision::Infinite();
206
207     if ( isLeaf() )
208     {
209       for ( size_t i = 0; i < _segments.size(); ++i )
210         if ( !_segments[i].IsOut( point ) &&
211              _segments[i].IsOn( point, dist2, param ) &&
212              dist2 < distance2 )
213         {
214           distance2 = dist2;
215           u         = param;
216           ok        = true;
217         }
218       return ok;
219     }
220     else
221     {
222       for (int i = 0; i < 8; i++)
223         if (((CurveProjector*) myChildren[i])->IsOnCurve( point, dist2, param ) &&
224             dist2 < distance2 )
225         {
226           distance2 = dist2;
227           u         = param;
228           ok        = true;
229         }
230     }
231     return ok;
232   }
233
234   //================================================================================
235   /*!
236    * \brief Initialize
237    */
238   //================================================================================
239
240   void CurveProjector::CurveSegment::Init(const gp_Pnt&       pf,
241                                           const gp_Pnt&       pl,
242                                           const double        uf,
243                                           const double        ul,
244                                           const double        tol,
245                                           Handle(Geom_Curve)& curve )
246   {
247     _pFirst  = pf;
248     _pLast   = pl;
249     _curve   = curve;
250     _length2 = pf.SquareDistance( pl );
251     _line.SetLocation( pf );
252     _line.SetDirection( gp_Vec( pf, pl ));
253     _chord2  = Max( _line.     SquareDistance( curve->Value( uf + 0.25 * ( ul - uf ))),
254                     Max( _line.SquareDistance( curve->Value( uf + 0.5  * ( ul - uf ))),
255                          _line.SquareDistance( curve->Value( uf + 0.75 * ( ul - uf )))));
256     _chord2 *= ( 1.05 * 1.05 ); // +5%
257     _chord2  = Max( tol, _chord2 );
258     _chord   = Sqrt( _chord2 );
259
260     Bnd_Box bb;
261     BndLib_Add3dCurve::Add( GeomAdaptor_Curve( curve, uf, ul ), tol, bb );
262     Add( bb.CornerMin() );
263     Add( bb.CornerMax() );
264   }
265
266   //================================================================================
267   /*!
268    * \brief Return true if a point is close to the curve segment
269    *  \param [in] point - the point
270    *  \param [out] distance2 - distance to the curve
271    *  \param [out] u - parameter on the curve
272    *  \return bool - is the point is close to the curve segment
273    */
274   //================================================================================
275
276   bool CurveProjector::CurveSegment::IsOn( const gp_XYZ& point, double & distance2, double & u )
277   {
278     distance2 = _line.SquareDistance( point );
279     if ( distance2 > _chord2 )
280       return false;
281
282     // check if the point projection falls into the segment range
283     {
284       gp_Vec edge( _pFirst, _pLast );
285       gp_Vec n1p ( _pFirst, point  );
286       u = ( edge * n1p ) / _length2; // param [0,1] on the edge
287       if ( u < 0. )
288       {
289         if ( _pFirst.SquareDistance( point ) > _chord2 )
290           return false;
291       }
292       else if ( u > 1. )
293       {
294         if ( _pLast.SquareDistance( point ) > _chord2 )
295           return false;
296       }
297     }
298     gp_Pnt proj;
299     distance2 = ShapeAnalysis_Curve().Project( _curve, point, Precision::Confusion(),
300                                                proj, u, false );
301     distance2 *= distance2;
302     return true;
303   }
304
305   //================================================================================
306   /*!
307    * \brief Check if the segment is in contact with a box
308    */
309   //================================================================================
310
311   bool CurveProjector::CurveSegment::IsInContact( const Bnd_B3d& bb )
312   {
313     if ( bb.IsOut( _line.Position(), /*isRay=*/true, _chord ))
314       return false;
315
316     gp_Ax1 axRev = _line.Position().Reversed();
317     axRev.SetLocation( _pLast );
318     return !bb.IsOut( axRev, /*isRay=*/true, _chord );
319   }
320
321   //================================================================================
322   //================================================================================
323
324   int getSubmeshIDForCopiedMesh(const SMESHDS_Mesh* srcMeshDS, SMESH_Mesh* tgtMesh);
325
326   enum _ListenerDataType
327     {
328       WAIT_HYP_MODIF=1, // data indicating awaiting for valid parameters of src hyp
329       LISTEN_SRC_MESH, // data storing submesh depending on source mesh state
330       SRC_HYP // data storing ImportSource hyp
331     };
332   //================================================================================
333   /*!
334    * \brief _ListenerData holding ImportSource hyp holding in its turn
335    *  imported groups
336    */
337   struct _ListenerData : public SMESH_subMeshEventListenerData
338   {
339     const StdMeshers_ImportSource1D* _srcHyp;
340     _ListenerData(const StdMeshers_ImportSource1D* h, _ListenerDataType type=SRC_HYP):
341       SMESH_subMeshEventListenerData(/*isDeletable=*/true), _srcHyp(h)
342     {
343       myType = type;
344     }
345   };
346   //================================================================================
347   /*!
348    * \brief Comparator of sub-meshes
349    */
350   struct _SubLess
351   {
352     bool operator()(const SMESH_subMesh* sm1, const SMESH_subMesh* sm2 ) const
353     {
354       if ( sm1 == sm2 ) return false;
355       if ( !sm1 || !sm2 ) return sm1 < sm2;
356       const TopoDS_Shape& s1 = sm1->GetSubShape();
357       const TopoDS_Shape& s2 = sm2->GetSubShape();
358       TopAbs_ShapeEnum t1 = s1.IsNull() ? TopAbs_SHAPE : s1.ShapeType();
359       TopAbs_ShapeEnum t2 = s2.IsNull() ? TopAbs_SHAPE : s2.ShapeType();
360       if ( t1 == t2)
361         return (sm1 < sm2);
362       return t1 < t2; // to have: face < edge
363     }
364   };
365   //================================================================================
366   /*!
367    * \brief Container of data dedicated to one source mesh
368    */
369   struct _ImportData
370   {
371     const SMESH_Mesh* _srcMesh;
372     StdMeshers_Import_1D::TNodeNodeMap _n2n;
373     StdMeshers_Import_1D::TElemElemMap _e2e;
374
375     set< SMESH_subMesh*, _SubLess > _subM; // submeshes relating to this srcMesh
376     set< SMESH_subMesh*, _SubLess > _copyMeshSubM; // submeshes requesting mesh copying
377     set< SMESH_subMesh*, _SubLess > _copyGroupSubM; // submeshes requesting group copying
378     set< SMESH_subMesh*, _SubLess > _computedSubM;
379
380     SMESHDS_SubMesh*     _importMeshSubDS; // submesh storing a copy of _srcMesh
381     int                  _importMeshSubID; // id of _importMeshSubDS
382
383     _ImportData(const SMESH_Mesh* srcMesh=0):
384       _srcMesh(srcMesh), _importMeshSubDS(0),_importMeshSubID(-1) {}
385
386     void removeImportedMesh( SMESHDS_Mesh* meshDS )
387     {
388       if ( !_importMeshSubDS ) return;
389       SMDS_ElemIteratorPtr eIt = _importMeshSubDS->GetElements();
390       while ( eIt->more() )
391         meshDS->RemoveFreeElement( eIt->next(), 0, /*fromGroups=*/false );
392       SMDS_NodeIteratorPtr nIt = _importMeshSubDS->GetNodes();
393       while ( nIt->more() )
394         meshDS->RemoveFreeNode( nIt->next(), 0, /*fromGroups=*/false );
395       _importMeshSubDS->Clear();
396       _n2n.clear();
397       _e2e.clear();
398     }
399     void removeGroups( SMESH_subMesh* subM, const StdMeshers_ImportSource1D* srcHyp )
400     {
401       if ( !srcHyp ) return;
402       SMESH_Mesh*           tgtMesh = subM->GetFather();
403       const SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS();
404       const SMESHDS_Mesh* srcMeshDS = _srcMesh->GetMeshDS();
405       vector<SMESH_Group*>*  groups =
406         const_cast<StdMeshers_ImportSource1D*>(srcHyp)->GetResultGroups(*srcMeshDS,*tgtMeshDS);
407       if ( groups )
408       {
409         for ( unsigned i = 0; i < groups->size(); ++i )
410           tgtMesh->RemoveGroup( groups->at(i)->GetGroupDS()->GetID() );
411         groups->clear();
412       }
413     }
414     void trackHypParams( SMESH_subMesh* sm, const StdMeshers_ImportSource1D* srcHyp )
415     {
416       if ( !srcHyp ) return;
417       bool toCopyMesh, toCopyGroups;
418       srcHyp->GetCopySourceMesh(toCopyMesh, toCopyGroups);
419
420       if ( toCopyMesh )_copyMeshSubM.insert( sm );
421       else             _copyMeshSubM.erase( sm );
422
423       if ( toCopyGroups ) _copyGroupSubM.insert( sm );
424       else                _copyGroupSubM.erase( sm );
425     }
426     void addComputed( SMESH_subMesh* sm )
427     {
428       SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true,
429                                                                /*complexShapeFirst=*/true);
430       while ( smIt->more() )
431       {
432         sm = smIt->next();
433         switch ( sm->GetSubShape().ShapeType() )
434         {
435         case TopAbs_EDGE:
436           if ( SMESH_Algo::isDegenerated( TopoDS::Edge( sm->GetSubShape() )))
437             continue;
438           // fall through
439         case TopAbs_FACE:
440           _subM.insert( sm );
441           if ( !sm->IsEmpty() )
442             _computedSubM.insert( sm );
443         case TopAbs_VERTEX:
444           break;
445         default:;
446         }
447       }
448     }
449   };
450   //================================================================================
451   /*!
452    * Listener notified on events relating to imported submesh
453    */
454   class _Listener : public SMESH_subMeshEventListener
455   {
456     typedef map< SMESH_Mesh*, list< _ImportData > > TMesh2ImpData;
457     TMesh2ImpData _tgtMesh2ImportData;
458
459     _Listener():SMESH_subMeshEventListener(/*isDeletable=*/false,
460                                            "StdMeshers_Import_1D::_Listener") {}
461
462   public:
463     // return pointer to a static listener
464     static _Listener* get() { static _Listener theListener; return &theListener; }
465
466     static _ImportData* getImportData(const SMESH_Mesh* srcMesh, SMESH_Mesh* tgtMesh);
467
468     static void storeImportSubmesh(SMESH_subMesh*                   importSub,
469                                    const SMESH_Mesh*                srcMesh,
470                                    const StdMeshers_ImportSource1D* srcHyp);
471
472     virtual void ProcessEvent(const int                       event,
473                               const int                       eventType,
474                               SMESH_subMesh*                  subMesh,
475                               SMESH_subMeshEventListenerData* data,
476                               const SMESH_Hypothesis*         hyp);
477     void removeSubmesh( SMESH_subMesh* sm, _ListenerData* data );
478     void clearSubmesh ( SMESH_subMesh* sm, _ListenerData* data, bool clearAllSub );
479     void clearN2N     ( SMESH_Mesh* tgtMesh );
480
481     // mark sm as missing src hyp with valid groups
482     static void waitHypModification(SMESH_subMesh* sm)
483     {
484       sm->SetEventListener
485         (get(), SMESH_subMeshEventListenerData::MakeData( sm, WAIT_HYP_MODIF ), sm);
486     }
487   };
488   //--------------------------------------------------------------------------------
489   /*!
490    * \brief Find or create ImportData for given meshes
491    */
492   _ImportData* _Listener::getImportData(const SMESH_Mesh* srcMesh,
493                                         SMESH_Mesh*       tgtMesh)
494   {
495     list< _ImportData >& dList = get()->_tgtMesh2ImportData[tgtMesh];
496     list< _ImportData >::iterator d = dList.begin();
497     for ( ; d != dList.end(); ++d )
498       if ( d->_srcMesh == srcMesh )
499         return &*d;
500     dList.push_back(_ImportData(srcMesh));
501     return &dList.back();
502   }
503
504   //--------------------------------------------------------------------------------
505   /*!
506    * \brief Remember an imported sub-mesh and set needed even listeners
507    *  \param importSub - submesh computed by Import algo
508    *  \param srcMesh - source mesh
509    *  \param srcHyp - ImportSource hypothesis
510    */
511   void _Listener::storeImportSubmesh(SMESH_subMesh*                   importSub,
512                                      const SMESH_Mesh*                srcMesh,
513                                      const StdMeshers_ImportSource1D* srcHyp)
514   {
515     // set listener to hear events of the submesh computed by "Import" algo
516     importSub->SetEventListener( get(), new _ListenerData(srcHyp), importSub );
517
518     // set listeners to hear events of the source mesh
519     SMESH_subMesh* smToNotify = importSub;
520     vector<SMESH_subMesh*> smToListen = srcHyp->GetSourceSubMeshes( srcMesh );
521     for ( size_t i = 0; i < smToListen.size(); ++i )
522     {
523       SMESH_subMeshEventListenerData* data = new _ListenerData(srcHyp, LISTEN_SRC_MESH);
524       data->mySubMeshes.push_back( smToNotify );
525       importSub->SetEventListener( get(), data, smToListen[i] );
526     }
527     // remember the submesh importSub and its sub-submeshes
528     _ImportData* iData = _Listener::getImportData( srcMesh, importSub->GetFather());
529     iData->trackHypParams( importSub, srcHyp );
530     iData->addComputed( importSub );
531     if ( !iData->_copyMeshSubM.empty() && iData->_importMeshSubID < 1 )
532     {
533       SMESH_Mesh* tgtMesh = importSub->GetFather();
534       iData->_importMeshSubID = getSubmeshIDForCopiedMesh( srcMesh->GetMeshDS(),tgtMesh);
535       iData->_importMeshSubDS = tgtMesh->GetMeshDS()->NewSubMesh( iData->_importMeshSubID );
536     }
537   }
538   //--------------------------------------------------------------------------------
539   /*!
540    * \brief Remove imported mesh and/or groups if needed
541    *  \param sm - submesh losing Import algo
542    *  \param data - data holding imported groups
543    */
544   void _Listener::removeSubmesh( SMESH_subMesh* sm, _ListenerData* data )
545   {
546     list< _ImportData > &  dList = _tgtMesh2ImportData[ sm->GetFather() ];
547     list< _ImportData >::iterator d = dList.begin();
548     for ( ; d != dList.end(); ++d )
549       if ( (*d)._subM.erase( sm ))
550       {
551         d->_computedSubM.erase( sm );
552         bool rmMesh   = d->_copyMeshSubM.erase( sm ) && d->_copyMeshSubM.empty();
553         bool rmGroups = (d->_copyGroupSubM.erase( sm ) && d->_copyGroupSubM.empty()) || rmMesh;
554         if ( rmMesh )
555           d->removeImportedMesh( sm->GetFather()->GetMeshDS() );
556         if ( rmGroups && data && data->myType == SRC_HYP )
557           d->removeGroups( sm, data->_srcHyp );
558       }
559   }
560   //--------------------------------------------------------------------------------
561   /*!
562    * \brief Clear _ImportData::_n2n.
563    *        _n2n is useful within one mesh.Compute() only
564    */
565   void _Listener::clearN2N( SMESH_Mesh* tgtMesh )
566   {
567     list< _ImportData >& dList = get()->_tgtMesh2ImportData[tgtMesh];
568     list< _ImportData >::iterator d = dList.begin();
569     for ( ; d != dList.end(); ++d )
570       d->_n2n.clear();
571   }
572   //--------------------------------------------------------------------------------
573   /*!
574    * \brief Clear submeshes and remove imported mesh and/or groups if necessary
575    *  \param sm - cleared submesh
576    *  \param data - data holding imported groups
577    */
578   void _Listener::clearSubmesh(SMESH_subMesh* sm, _ListenerData* data, bool clearAllSub)
579   {
580     list< _ImportData > &  dList = _tgtMesh2ImportData[ sm->GetFather() ];
581     list< _ImportData >::iterator d = dList.begin();
582     for ( ; d != dList.end(); ++d )
583     {
584       if ( !d->_subM.count( sm )) continue;
585       if ( (*d)._computedSubM.erase( sm ) )
586       {
587         bool copyMesh = !d->_copyMeshSubM.empty();
588         if ( copyMesh || clearAllSub )
589         {
590           // remove imported mesh and groups
591           d->removeImportedMesh( sm->GetFather()->GetMeshDS() );
592
593           if ( data && data->myType == SRC_HYP )
594             d->removeGroups( sm, data->_srcHyp );
595
596           // clear the rest submeshes
597           if ( !d->_computedSubM.empty() )
598           {
599             d->_computedSubM.clear();
600             set< SMESH_subMesh*, _SubLess>::iterator sub = d->_subM.begin();
601             for ( ; sub != d->_subM.end(); ++sub )
602             {
603               SMESH_subMesh* subM = *sub;
604               _ListenerData* hypData = (_ListenerData*) subM->GetEventListenerData( get() );
605               if ( hypData && hypData->myType == SRC_HYP )
606                 d->removeGroups( sm, hypData->_srcHyp );
607
608               subM->ComputeStateEngine( SMESH_subMesh::CLEAN );
609               if ( subM->GetSubShape().ShapeType() == TopAbs_FACE )
610                 subM->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN );
611             }
612           }
613         }
614         sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
615         if ( sm->GetSubShape().ShapeType() == TopAbs_FACE )
616           sm->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN );
617       }
618       if ( data && data->myType == SRC_HYP )
619         d->trackHypParams( sm, data->_srcHyp );
620       d->_n2n.clear();
621       d->_e2e.clear();
622     }
623   }
624   //--------------------------------------------------------------------------------
625   /*!
626    * \brief Remove imported mesh and/or groups
627    */
628   void _Listener::ProcessEvent(const int                       event,
629                                const int                       eventType,
630                                SMESH_subMesh*                  subMesh,
631                                SMESH_subMeshEventListenerData* data,
632                                const SMESH_Hypothesis*         /*hyp*/)
633   {
634     if ( data && data->myType == WAIT_HYP_MODIF )
635     {
636       // event of Import submesh
637       if ( SMESH_subMesh::MODIF_HYP  == event &&
638            SMESH_subMesh::ALGO_EVENT == eventType )
639       {
640         // re-call SetEventListener() to take into account valid parameters
641         // of ImportSource hypothesis
642         if ( SMESH_Algo* algo = subMesh->GetAlgo() )
643           algo->SetEventListener( subMesh );
644       }
645     }
646     else if ( data && data->myType == LISTEN_SRC_MESH )
647     {
648       // event of source mesh
649       if ( SMESH_subMesh::COMPUTE_EVENT == eventType )
650       {
651         switch ( event ) {
652         case SMESH_subMesh::CLEAN:
653           // source mesh cleaned -> clean target mesh
654           clearSubmesh( data->mySubMeshes.front(), (_ListenerData*) data, /*all=*/true );
655           break;
656         case SMESH_subMesh::SUBMESH_COMPUTED: {
657           // source mesh computed -> reset FAILED state of Import submeshes to
658           // READY_TO_COMPUTE
659           SMESH_Mesh* srcMesh = subMesh->GetFather();
660           if ( srcMesh->NbEdges() > 0 || srcMesh->NbFaces() > 0 )
661           {
662             SMESH_Mesh* m = data->mySubMeshes.front()->GetFather();
663             if ( SMESH_subMesh* sm1 = m->GetSubMeshContaining(1))
664             {
665               sm1->ComputeStateEngine(SMESH_subMesh::SUBMESH_COMPUTED );
666               sm1->ComputeSubMeshStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
667             }
668           }
669           break;
670         }
671         default:;
672         }
673       }
674       if ( !data->mySubMeshes.empty() )
675         clearN2N( data->mySubMeshes.front()->GetFather() );
676     }
677     else // event of Import submesh
678     {
679       // find out what happens: import hyp modified or removed
680       bool removeImport = false, modifHyp = false;
681       if ( SMESH_subMesh::ALGO_EVENT == eventType )
682         modifHyp = true;
683       if ( subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK )
684       {
685         removeImport = true;
686       }
687       else if (( SMESH_subMesh::REMOVE_ALGO == event ||
688                  SMESH_subMesh::REMOVE_FATHER_ALGO == event ) &&
689                SMESH_subMesh::ALGO_EVENT == eventType )
690       {
691         SMESH_Algo* algo = subMesh->GetAlgo();
692         removeImport = ( strncmp( "Import", algo->GetName(), 6 ) != 0 );
693       }
694
695       if ( removeImport )
696       {
697         // treat removal of Import algo from subMesh
698         removeSubmesh( subMesh, (_ListenerData*) data );
699       }
700       else if ( modifHyp ||
701                 ( SMESH_subMesh::CLEAN         == event &&
702                   SMESH_subMesh::COMPUTE_EVENT == eventType))
703       {
704         // treat modification of ImportSource hypothesis
705         clearSubmesh( subMesh, (_ListenerData*) data, /*all=*/false );
706       }
707       else if ( SMESH_subMesh::CHECK_COMPUTE_STATE == event &&
708                 SMESH_subMesh::COMPUTE_EVENT       == eventType )
709       {
710         // check compute state of all submeshes impoting from same src mesh;
711         // this is to take into account 1D computed submeshes hidden by 2D import algo;
712         // else source mesh is not copied as _subM.size != _computedSubM.size()
713         list< _ImportData > &  dList = _tgtMesh2ImportData[ subMesh->GetFather() ];
714         list< _ImportData >::iterator d = dList.begin();
715         for ( ; d != dList.end(); ++d )
716           if ( d->_subM.count( subMesh ))
717           {
718             set<SMESH_subMesh*,_SubLess>::iterator smIt = d->_subM.begin();
719             for( ; smIt != d->_subM.end(); ++smIt )
720               if ( (*smIt)->IsMeshComputed() )
721                 d->_computedSubM.insert( *smIt);
722           }
723       }
724       // Clear _ImportData::_n2n if it isn't useful anymore, i.e. when
725       // the event is not within mesh.Compute()
726       if ( SMESH_subMesh::ALGO_EVENT == eventType )
727         clearN2N( subMesh->GetFather() );
728     }
729   }
730
731   //================================================================================
732   /*!
733    * \brief Return an ID of submesh to store nodes and elements of a copied mesh
734    */
735   //================================================================================
736
737   int getSubmeshIDForCopiedMesh(const SMESHDS_Mesh* srcMeshDS,
738                                 SMESH_Mesh*         tgtMesh)
739   {
740     // To get SMESH_subMesh corresponding to srcMeshDS we need to have a shape
741     // for which SMESHDS_Mesh::IsGroupOfSubShapes() returns true.
742     // And this shape must be different from sub-shapes of the main shape.
743     // So we create a compound containing
744     // 1) some sub-shapes of SMESH_Mesh::PseudoShape() corresponding to
745     //    srcMeshDS->GetPersistentId()
746     // 2) the 1-st vertex of the main shape to assure
747     //    SMESHDS_Mesh::IsGroupOfSubShapes(shape)==true
748     TopoDS_Shape shapeForSrcMesh;
749     TopTools_IndexedMapOfShape pseudoSubShapes;
750     TopExp::MapShapes( SMESH_Mesh::PseudoShape(), pseudoSubShapes );
751
752     // index of pseudoSubShapes corresponding to srcMeshDS
753     int    subIndex = 1 + srcMeshDS->GetPersistentId() % pseudoSubShapes.Extent();
754     int nbSubShapes = 1 + srcMeshDS->GetPersistentId() / pseudoSubShapes.Extent();
755
756     // try to find already present shapeForSrcMesh
757     SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS();
758     for ( int i = tgtMeshDS->MaxShapeIndex(); i > 0 && shapeForSrcMesh.IsNull(); --i )
759     {
760       const TopoDS_Shape& s = tgtMeshDS->IndexToShape(i);
761       if ( s.ShapeType() != TopAbs_COMPOUND ) break;
762       TopoDS_Iterator sSubIt( s );
763       for ( int iSub = 0; iSub < nbSubShapes && sSubIt.More(); ++iSub, sSubIt.Next() )
764         if ( pseudoSubShapes( subIndex+iSub ).IsSame( sSubIt.Value()))
765           if ( iSub+1 == nbSubShapes )
766           {
767             shapeForSrcMesh = s;
768             break;
769           }
770     }
771     if ( shapeForSrcMesh.IsNull() )
772     {
773       // make a new shapeForSrcMesh
774       BRep_Builder aBuilder;
775       TopoDS_Compound comp;
776       aBuilder.MakeCompound( comp );
777       shapeForSrcMesh = comp;
778       for ( int iSub = 0; iSub < nbSubShapes; ++iSub )
779         if ( subIndex+iSub <= pseudoSubShapes.Extent() )
780           aBuilder.Add( comp, pseudoSubShapes( subIndex+iSub ));
781       TopExp_Explorer vExp( tgtMeshDS->ShapeToMesh(), TopAbs_VERTEX );
782       aBuilder.Add( comp, vExp.Current() );
783     }
784     SMESH_subMesh* sm = tgtMesh->GetSubMesh( shapeForSrcMesh );
785     SMESHDS_SubMesh* smDS = sm->GetSubMeshDS();
786     if ( !smDS )
787       smDS = tgtMeshDS->NewSubMesh( sm->GetId() );
788
789     // make ordinary submesh from a complex one
790     if ( smDS->IsComplexSubmesh() )
791     {
792       list< const SMESHDS_SubMesh* > subSM;
793       SMESHDS_SubMeshIteratorPtr smIt = smDS->GetSubMeshIterator();
794       while ( smIt->more() ) subSM.push_back( smIt->next() );
795       list< const SMESHDS_SubMesh* >::iterator sub = subSM.begin();
796       for ( ; sub != subSM.end(); ++sub)
797         smDS->RemoveSubMesh( *sub );
798     }
799     return sm->GetId();
800   }
801
802   //================================================================================
803   /*!
804    * \brief Return a submesh to store nodes and elements of a copied mesh
805    * and set event listeners in order to clear
806    * imported mesh and groups as soon as submesh state requires it
807    */
808   //================================================================================
809
810   SMESHDS_SubMesh* getSubmeshForCopiedMesh(const SMESH_Mesh*                    srcMesh,
811                                            SMESH_Mesh*                          tgtMesh,
812                                            const TopoDS_Shape&                  tgtShape,
813                                            StdMeshers_Import_1D::TNodeNodeMap*& n2n,
814                                            StdMeshers_Import_1D::TElemElemMap*& e2e,
815                                            bool &                               toCopyGroups)
816   {
817     StdMeshers_Import_1D::getMaps( srcMesh, tgtMesh, n2n,e2e );
818
819     _ImportData* iData = _Listener::getImportData(srcMesh,tgtMesh);
820
821     SMESH_subMesh* importedSM = tgtMesh->GetSubMesh( tgtShape );
822     iData->addComputed( importedSM );
823     if ( iData->_computedSubM.size() != iData->_subM.size() )
824       return 0; // not all submeshes computed yet
825
826     toCopyGroups = !iData->_copyGroupSubM.empty();
827
828     if ( !iData->_copyMeshSubM.empty())
829     {
830       // make submesh to store a copied mesh
831       int smID = getSubmeshIDForCopiedMesh( srcMesh->GetMeshDS(), tgtMesh );
832       SMESHDS_SubMesh* subDS = tgtMesh->GetMeshDS()->NewSubMesh( smID );
833
834       iData->_importMeshSubID = smID;
835       iData->_importMeshSubDS = subDS;
836       return subDS;
837     }
838     return 0;
839   }
840
841   //================================================================================
842   /*!
843    * \brief Return minimal square length of edges of 1D and 2D elements sharing the node
844    */
845   //================================================================================
846
847   double getMinEdgeLength2( const SMDS_MeshNode* n )
848   {
849     SMESH_NodeXYZ p = n;
850     double minLen2 = Precision::Infinite();
851     for ( SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator(); eIt->more();  )
852     {
853       const SMDS_MeshElement*      e = eIt->next();
854       const SMDSAbs_ElementType type = e->GetType();
855       if ( type != SMDSAbs_Edge && type != SMDSAbs_Face )
856         continue;
857       int i = e->GetNodeIndex( n );
858       int iNext = SMESH_MesherHelper::WrapIndex( i + 1, e->NbCornerNodes() );
859       minLen2 = Min( minLen2, p.SquareDistance( e->GetNode( iNext )));
860       if ( type != SMDSAbs_Face )
861         continue;
862       int iPrev = SMESH_MesherHelper::WrapIndex( i - 1, e->NbCornerNodes() );
863       minLen2 = Min( minLen2, p.SquareDistance( e->GetNode( iPrev )));
864     }
865     return minLen2;
866   }
867
868 } // namespace
869
870 //=============================================================================
871 /*!
872  * Creates StdMeshers_Import_1D
873  */
874 //=============================================================================
875
876 StdMeshers_Import_1D::StdMeshers_Import_1D(int hypId, SMESH_Gen * gen)
877   :SMESH_1D_Algo(hypId, gen), _sourceHyp(0)
878 {
879   _name = "Import_1D";
880   _shapeType = (1 << TopAbs_EDGE);
881
882   _compatibleHypothesis.push_back("ImportSource1D");
883 }
884
885 //=============================================================================
886 /*!
887  * Check presence of a hypothesis
888  */
889 //=============================================================================
890
891 bool StdMeshers_Import_1D::CheckHypothesis
892                          (SMESH_Mesh&                          aMesh,
893                           const TopoDS_Shape&                  aShape,
894                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
895 {
896   _sourceHyp = 0;
897
898   const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape);
899   if ( hyps.size() == 0 )
900   {
901     aStatus = SMESH_Hypothesis::HYP_MISSING;
902     return false;  // can't work with no hypothesis
903   }
904
905   if ( hyps.size() > 1 )
906   {
907     aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST;
908     return false;
909   }
910
911   const SMESHDS_Hypothesis *theHyp = hyps.front();
912
913   string hypName = theHyp->GetName();
914
915   if (hypName == _compatibleHypothesis.front())
916   {
917     _sourceHyp = (StdMeshers_ImportSource1D *)theHyp;
918     aStatus = _sourceHyp->GetGroups().empty() ? HYP_BAD_PARAMETER : HYP_OK;
919     if ( aStatus == HYP_BAD_PARAMETER )
920       _Listener::waitHypModification( aMesh.GetSubMesh( aShape ));
921     return aStatus == HYP_OK;
922   }
923
924   aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
925   return false;
926 }
927
928 //=============================================================================
929 /*!
930  * Import elements from the other mesh
931  */
932 //=============================================================================
933
934 bool StdMeshers_Import_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & theShape)
935 {
936   if ( !_sourceHyp ) return false;
937
938   //MESSAGE("---------> StdMeshers_Import_1D::Compute");
939   const vector<SMESH_Group*>& srcGroups = _sourceHyp->GetGroups(/*loaded=*/true);
940   if ( srcGroups.empty() )
941     return error("Invalid source groups");
942
943   SMESH_MesherHelper helper(theMesh);
944   helper.SetSubShape(theShape);
945   SMESHDS_Mesh* tgtMesh = theMesh.GetMeshDS();
946
947   const TopoDS_Edge& geomEdge = TopoDS::Edge( theShape );
948   const double        edgeTol = helper.MaxTolerance( geomEdge );
949   const int           shapeID = tgtMesh->ShapeToIndex( geomEdge );
950
951
952   double geomTol = Precision::Confusion();
953   for ( size_t iG = 0; iG < srcGroups.size(); ++iG )
954   {
955     const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS();
956     for ( SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements(); srcElems->more(); )
957     {
958       const SMDS_MeshElement* edge = srcElems->next();
959       geomTol = Sqrt( 0.5 * ( getMinEdgeLength2( edge->GetNode(0) ) +
960                               getMinEdgeLength2( edge->GetNode(1) ))) / 25;
961       iG = srcGroups.size();
962       break;
963     }
964   }
965   CurveProjector curveProjector( geomEdge, geomTol );
966
967   // get nodes on vertices
968   set<int> vertexIDs;
969   list < SMESH_TNodeXYZ > vertexNodes;
970   list < SMESH_TNodeXYZ >::iterator vNIt;
971   TopExp_Explorer vExp( theShape, TopAbs_VERTEX );
972   for ( ; vExp.More(); vExp.Next() )
973   {
974     const TopoDS_Vertex& v = TopoDS::Vertex( vExp.Current() );
975     if ( !vertexIDs.insert( tgtMesh->ShapeToIndex( v )).second )
976       continue; // closed edge
977     const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, tgtMesh );
978     if ( !n )
979     {
980       _gen->Compute(theMesh,v,/*anUpward=*/true);
981       n = SMESH_Algo::VertexNode( v, tgtMesh );
982       //MESSAGE("_gen->Compute " << n);
983       if ( !n ) return false; // very strange
984     }
985     vertexNodes.push_back( SMESH_TNodeXYZ( n ));
986     //MESSAGE("SMESH_Algo::VertexNode " << n->GetID() << " " << n->X() << " " << n->Y() << " " << n->Z() );
987   }
988
989   // import edges from groups
990   TNodeNodeMap* n2n;
991   TElemElemMap* e2e;
992   for ( size_t iG = 0; iG < srcGroups.size(); ++iG )
993   {
994     const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS();
995
996     const int meshID = srcGroup->GetMesh()->GetPersistentId();
997     const SMESH_Mesh* srcMesh = GetMeshByPersistentID( meshID );
998     if ( !srcMesh ) continue;
999     getMaps( srcMesh, &theMesh, n2n, e2e );
1000
1001     SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements();
1002     vector<const SMDS_MeshNode*> newNodes;
1003     while ( srcElems->more() ) // loop on group contents
1004     {
1005       const SMDS_MeshElement* edge = srcElems->next();
1006       gp_XYZ middle = 0.5 * ( SMESH_NodeXYZ( edge->GetNode(0)) +
1007                               SMESH_NodeXYZ( edge->GetNode(1)));
1008       if ( curveProjector.IsOut( middle ))
1009         continue;
1010
1011       // find or create nodes of a new edge
1012       newNodes.resize( edge->NbNodes() );
1013       newNodes.back() = 0;
1014       int nbNodesOnVertex = 0;
1015       SMDS_MeshElement::iterator node = edge->begin_nodes();
1016       for ( size_t i = 0; i < newNodes.size(); ++i, ++node )
1017       {
1018         TNodeNodeMap::iterator n2nIt = n2n->insert( make_pair( *node, nullptr )).first;
1019         if ( n2nIt->second )
1020         {
1021           int sId = n2nIt->second->getshapeId();
1022           if ( sId != shapeID )
1023           {
1024             if ( vertexIDs.count( sId ))
1025               ++nbNodesOnVertex;
1026             else
1027               break;
1028           }
1029         }
1030         else if ( !vertexNodes.empty() )
1031         {
1032           // find an existing vertex node
1033           double checktol = max(1.E-10, 10*edgeTol*edgeTol);
1034           for ( vNIt = vertexNodes.begin(); vNIt != vertexNodes.end(); ++vNIt)
1035             if ( vNIt->SquareDistance( *node ) < checktol)
1036             {
1037               (*n2nIt).second = vNIt->_node;
1038               vertexNodes.erase( vNIt );
1039               ++nbNodesOnVertex;
1040               break;
1041             }
1042         }
1043         if ( !n2nIt->second )
1044         {
1045           // find out if the node lies on theShape
1046           SMESH_NodeXYZ xyz = *node;
1047           double dist2, u;
1048           if ( curveProjector.IsOnCurve( xyz, dist2, u ))
1049           {
1050             // tolerance relative to the length of surrounding edges
1051             double mytol2 = getMinEdgeLength2( *node ) / 25 / 25;
1052             if ( dist2 < mytol2 )
1053             {
1054               SMDS_MeshNode* newNode = tgtMesh->AddNode( xyz.X(), xyz.Y(), xyz.Z() );
1055               n2nIt->second = newNode;
1056               tgtMesh->SetNodeOnEdge( newNode, shapeID, u );
1057             }
1058           }
1059         }
1060         if ( !(newNodes[i] = n2nIt->second ))
1061           break;
1062       }
1063       if ( !newNodes.back() )
1064       {
1065         //MESSAGE("not all nodes of edge lie on theShape");
1066         continue; // not all nodes of edge lie on theShape
1067       }
1068
1069       // make a new edge
1070       SMDS_MeshElement * newEdge;
1071       if ( newNodes.size() == 3 )
1072         newEdge = tgtMesh->AddEdge( newNodes[0], newNodes[1], newNodes[2] );
1073       else
1074         newEdge = tgtMesh->AddEdge( newNodes[0], newNodes[1]);
1075       tgtMesh->SetMeshElementOnShape( newEdge, shapeID );
1076       e2e->insert( make_pair( edge, newEdge ));
1077
1078       if ( nbNodesOnVertex >= 2 ) // EDGE is meshed by a sole segment
1079       {
1080         iG = srcGroups.size(); // stop looingp on groups
1081         break;
1082       }
1083     }  // loop on group contents
1084   } // loop on groups
1085
1086   if ( n2n->empty())
1087     return error("Source groups are empty or mismatching geometry");
1088
1089   // check if the whole geom edge is covered by imported segments;
1090   // the check consist in passing by segments from one vetrex node to another
1091   bool isEdgeMeshed = false;
1092   if ( SMESHDS_SubMesh* tgtSM = tgtMesh->MeshElements( theShape ))
1093   {
1094     const TopoDS_Vertex& v = ( vExp.ReInit(), TopoDS::Vertex( vExp.Current() ));
1095     const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, tgtMesh );
1096     const SMDS_MeshElement* seg = 0;
1097     SMDS_ElemIteratorPtr segIt = n->GetInverseElementIterator(SMDSAbs_Edge);
1098     while ( segIt->more() && !seg )
1099       if ( !tgtSM->Contains( seg = segIt->next()))
1100         seg = 0;
1101     int nbPassedSegs = 0;
1102     while ( seg )
1103     {
1104       ++nbPassedSegs;
1105       const SMDS_MeshNode* n2 = seg->GetNode(0);
1106       n = ( n2 == n ? seg->GetNode(1) : n2 );
1107       if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
1108         break;
1109       const SMDS_MeshElement* seg2 = 0;
1110       segIt = n->GetInverseElementIterator(SMDSAbs_Edge);
1111       while ( segIt->more() && !seg2 )
1112         if ( seg == ( seg2 = segIt->next()))
1113           seg2 = 0;
1114       seg = seg2;
1115     }
1116     if (nbPassedSegs > 0 && tgtSM->NbElements() > nbPassedSegs )
1117       return error( "Source elements overlap one another");
1118
1119     isEdgeMeshed = ( tgtSM->NbElements() == nbPassedSegs &&
1120                      n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX );
1121   }
1122   if ( !isEdgeMeshed )
1123     return error( "Source elements don't cover totally the geometrical edge" );
1124
1125   // copy meshes
1126   vector<SMESH_Mesh*> srcMeshes = _sourceHyp->GetSourceMeshes();
1127   for ( size_t i = 0; i < srcMeshes.size(); ++i )
1128     importMesh( srcMeshes[i], theMesh, _sourceHyp, theShape );
1129
1130   return true;
1131 }
1132
1133 //================================================================================
1134 /*!
1135  * \brief Copy mesh and groups
1136  */
1137 //================================================================================
1138
1139 void StdMeshers_Import_1D::importMesh(const SMESH_Mesh*          srcMesh,
1140                                       SMESH_Mesh &               tgtMesh,
1141                                       StdMeshers_ImportSource1D* srcHyp,
1142                                       const TopoDS_Shape&        tgtShape)
1143 {
1144   // get submesh to store the imported mesh
1145   TNodeNodeMap* n2n;
1146   TElemElemMap* e2e;
1147   bool toCopyGroups;
1148   SMESHDS_SubMesh* tgtSubMesh =
1149     getSubmeshForCopiedMesh( srcMesh, &tgtMesh, tgtShape, n2n, e2e, toCopyGroups );
1150   if ( !tgtSubMesh || tgtSubMesh->NbNodes() + tgtSubMesh->NbElements() > 0 )
1151     return; // not to copy srcMeshDS twice
1152
1153   SMESHDS_Mesh* tgtMeshDS = tgtMesh.GetMeshDS();
1154   SMESH_MeshEditor additor( &tgtMesh );
1155
1156   // 1. Copy mesh
1157
1158   SMESH_MeshEditor::ElemFeatures elemType;
1159   vector<const SMDS_MeshNode*> newNodes;
1160   const SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
1161   SMDS_ElemIteratorPtr eIt = srcMeshDS->elementsIterator();
1162   while ( eIt->more() )
1163   {
1164     const SMDS_MeshElement* elem = eIt->next();
1165     TElemElemMap::iterator e2eIt = e2e->insert( make_pair( elem, (SMDS_MeshElement*)0 )).first;
1166     if ( e2eIt->second ) continue; // already copied by Compute()
1167     newNodes.resize( elem->NbNodes() );
1168     SMDS_MeshElement::iterator node = elem->begin_nodes();
1169     for ( unsigned i = 0; i < newNodes.size(); ++i, ++node )
1170     {
1171       TNodeNodeMap::iterator n2nIt = n2n->insert( make_pair( *node, (SMDS_MeshNode*)0 )).first;
1172       if ( !n2nIt->second )
1173       {
1174         (*n2nIt).second = tgtMeshDS->AddNode( (*node)->X(), (*node)->Y(), (*node)->Z());
1175         tgtSubMesh->AddNode( n2nIt->second );
1176       }
1177       newNodes[i] = n2nIt->second;
1178     }
1179     const SMDS_MeshElement* newElem =
1180       tgtMeshDS->FindElement( newNodes, elem->GetType(), /*noMedium=*/false );
1181     if ( !newElem )
1182     {
1183       newElem = additor.AddElement( newNodes, elemType.Init( elem, /*basicOnly=*/false ));
1184       tgtSubMesh->AddElement( newElem );
1185     }
1186     if ( toCopyGroups )
1187       (*e2eIt).second = newElem;
1188   }
1189   // copy free nodes
1190   if ( srcMeshDS->NbNodes() > (int) n2n->size() )
1191   {
1192     SMDS_NodeIteratorPtr nIt = srcMeshDS->nodesIterator();
1193     while( nIt->more() )
1194     {
1195       const SMDS_MeshNode* node = nIt->next();
1196       if ( node->NbInverseElements() == 0 )
1197       {
1198         const SMDS_MeshNode* newNode = tgtMeshDS->AddNode( node->X(), node->Y(), node->Z());
1199         n2n->insert( make_pair( node, newNode ));
1200         tgtSubMesh->AddNode( newNode );
1201       }
1202     }
1203   }
1204
1205   // 2. Copy groups
1206
1207   vector<SMESH_Group*> resultGroups;
1208   if ( toCopyGroups )
1209   {
1210     // collect names of existing groups to assure uniqueness of group names within a type
1211     map< SMDSAbs_ElementType, set<string> > namesByType;
1212     SMESH_Mesh::GroupIteratorPtr groupIt = tgtMesh.GetGroups();
1213     while ( groupIt->more() )
1214     {
1215       SMESH_Group* tgtGroup = groupIt->next();
1216       namesByType[ tgtGroup->GetGroupDS()->GetType() ].insert( tgtGroup->GetName() );
1217     }
1218     if (srcMesh)
1219     {
1220       SMESH_Mesh::GroupIteratorPtr groupIt = srcMesh->GetGroups();
1221       while ( groupIt->more() )
1222       {
1223         SMESH_Group* srcGroup = groupIt->next();
1224         SMESHDS_GroupBase* srcGroupDS = srcGroup->GetGroupDS();
1225         string name = srcGroup->GetName();
1226         int nb = 1;
1227         while ( !namesByType[ srcGroupDS->GetType() ].insert( name ).second )
1228           name = SMESH_Comment(srcGroup->GetName()) << "_imported_" << nb++;
1229         SMESH_Group* newGroup = tgtMesh.AddGroup( srcGroupDS->GetType(), name.c_str() );
1230         SMESHDS_Group* newGroupDS = (SMESHDS_Group*)newGroup->GetGroupDS();
1231         resultGroups.push_back( newGroup );
1232
1233         eIt = srcGroupDS->GetElements();
1234         if ( srcGroupDS->GetType() == SMDSAbs_Node )
1235           while (eIt->more())
1236           {
1237             TNodeNodeMap::iterator n2nIt = n2n->find((const SMDS_MeshNode*) eIt->next() );
1238             if ( n2nIt != n2n->end() && n2nIt->second )
1239               newGroupDS->SMDSGroup().Add((*n2nIt).second );
1240           }
1241         else
1242           while (eIt->more())
1243           {
1244             TElemElemMap::iterator e2eIt = e2e->find( eIt->next() );
1245             if ( e2eIt != e2e->end() && e2eIt->second )
1246               newGroupDS->SMDSGroup().Add((*e2eIt).second );
1247           }
1248       }
1249     }
1250   }
1251   n2n->clear();
1252   e2e->clear();
1253
1254   // Remember created groups in order to remove them as soon as the srcHyp is
1255   // modified or something other similar happens. This imformation must be persistent,
1256   // for that store them in a hypothesis as it stores its values in the file anyway
1257   srcHyp->StoreResultGroups( resultGroups, *srcMeshDS, *tgtMeshDS );
1258 }
1259
1260 //=============================================================================
1261 /*!
1262  * \brief Set needed event listeners and create a submesh for a copied mesh
1263  *
1264  * This method is called only if a submesh has HYP_OK algo_state.
1265  */
1266 //=============================================================================
1267
1268 void StdMeshers_Import_1D::setEventListener(SMESH_subMesh*             subMesh,
1269                                             StdMeshers_ImportSource1D* sourceHyp)
1270 {
1271   if ( sourceHyp )
1272   {
1273     vector<SMESH_Mesh*> srcMeshes = sourceHyp->GetSourceMeshes();
1274     if ( srcMeshes.empty() )
1275       _Listener::waitHypModification( subMesh );
1276     for ( unsigned i = 0; i < srcMeshes.size(); ++i )
1277       // set a listener to remove the imported mesh and groups
1278       _Listener::storeImportSubmesh( subMesh, srcMeshes[i], sourceHyp );
1279   }
1280 }
1281 void StdMeshers_Import_1D::SetEventListener(SMESH_subMesh* subMesh)
1282 {
1283   if ( !_sourceHyp )
1284   {
1285     const TopoDS_Shape& tgtShape = subMesh->GetSubShape();
1286     SMESH_Mesh*         tgtMesh  = subMesh->GetFather();
1287     Hypothesis_Status aStatus;
1288     CheckHypothesis( *tgtMesh, tgtShape, aStatus );
1289   }
1290   setEventListener( subMesh, _sourceHyp );
1291 }
1292
1293 void StdMeshers_Import_1D::SubmeshRestored(SMESH_subMesh* subMesh)
1294 {
1295   SetEventListener(subMesh);
1296 }
1297
1298 //=============================================================================
1299 /*!
1300  * Predict nb of mesh entities created by Compute()
1301  */
1302 //=============================================================================
1303
1304 bool StdMeshers_Import_1D::Evaluate(SMESH_Mesh &         theMesh,
1305                                     const TopoDS_Shape & theShape,
1306                                     MapShapeNbElems&     aResMap)
1307 {
1308   if ( !_sourceHyp ) return false;
1309
1310   const vector<SMESH_Group*>& srcGroups = _sourceHyp->GetGroups();
1311   if ( srcGroups.empty() )
1312     return error("Invalid source groups");
1313
1314   vector<smIdType> aVec(SMDSEntity_Last,0);
1315
1316   bool toCopyMesh, toCopyGroups;
1317   _sourceHyp->GetCopySourceMesh(toCopyMesh, toCopyGroups);
1318   if ( toCopyMesh ) // the whole mesh is copied
1319   {
1320     vector<SMESH_Mesh*> srcMeshes = _sourceHyp->GetSourceMeshes();
1321     for ( unsigned i = 0; i < srcMeshes.size(); ++i )
1322     {
1323       SMESH_subMesh* sm = getSubMeshOfCopiedMesh( theMesh, *srcMeshes[i]);
1324       if ( !sm || aResMap.count( sm )) continue; // already counted
1325       aVec.assign( SMDSEntity_Last, 0);
1326       const SMDS_MeshInfo& aMeshInfo = srcMeshes[i]->GetMeshDS()->GetMeshInfo();
1327       for (int i = 0; i < SMDSEntity_Last; i++)
1328         aVec[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i);
1329     }
1330   }
1331   else
1332   {
1333     SMESH_MesherHelper helper(theMesh);
1334
1335     const TopoDS_Edge& geomEdge = TopoDS::Edge( theShape );
1336     const double edgeTol = helper.MaxTolerance( geomEdge );
1337
1338     // take into account nodes on vertices
1339     TopExp_Explorer vExp( theShape, TopAbs_VERTEX );
1340     for ( ; vExp.More(); vExp.Next() )
1341       theMesh.GetSubMesh( vExp.Current())->Evaluate( aResMap );
1342
1343     // count edges imported from groups
1344     int nbEdges = 0, nbQuadEdges = 0;
1345     for ( size_t iG = 0; iG < srcGroups.size(); ++iG )
1346     {
1347       const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS();
1348       SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements();
1349       SMDS_MeshNode *tmpNode = helper.AddNode(0,0,0);
1350       while ( srcElems->more() ) // loop on group contents
1351       {
1352         const SMDS_MeshElement* edge = srcElems->next();
1353         // find out if edge is located on geomEdge by projecting
1354         // a middle of edge to geomEdge
1355         SMESH_TNodeXYZ p1( edge->GetNode(0));
1356         SMESH_TNodeXYZ p2( edge->GetNode(1));
1357         gp_XYZ middle = ( p1 + p2 ) / 2.;
1358         tmpNode->setXYZ( middle.X(), middle.Y(), middle.Z());
1359         double u = 0;
1360         if ( helper.CheckNodeU( geomEdge, tmpNode, u, 10 * edgeTol, /*force=*/true ))
1361           ++( edge->IsQuadratic() ? nbQuadEdges : nbEdges);
1362       }
1363       helper.GetMeshDS()->RemoveNode(tmpNode);
1364     }
1365
1366     int nbNodes = nbEdges + 2 * nbQuadEdges - 1;
1367
1368     aVec[SMDSEntity_Node     ] = nbNodes;
1369     aVec[SMDSEntity_Edge     ] = nbEdges;
1370     aVec[SMDSEntity_Quad_Edge] = nbQuadEdges;
1371   }
1372
1373   SMESH_subMesh * sm = theMesh.GetSubMesh(theShape);
1374   aResMap.insert( make_pair( sm, aVec ));
1375
1376   return true;
1377 }
1378
1379 //================================================================================
1380 /*!
1381  * \brief Return node-node and element-element maps for import of geiven source mesh
1382  */
1383 //================================================================================
1384
1385 void StdMeshers_Import_1D::getMaps(const SMESH_Mesh* srcMesh,
1386                                    SMESH_Mesh*       tgtMesh,
1387                                    TNodeNodeMap*&    n2n,
1388                                    TElemElemMap*&    e2e)
1389 {
1390   _ImportData* iData = _Listener::getImportData(srcMesh,tgtMesh);
1391   n2n = &iData->_n2n;
1392   e2e = &iData->_e2e;
1393   if ( iData->_copyMeshSubM.empty() )
1394   {
1395     // n2n->clear(); -- for sharing nodes on EDGEs
1396     e2e->clear();
1397   }
1398 }
1399
1400 //================================================================================
1401 /*!
1402  * \brief Return submesh corresponding to the copied mesh
1403  */
1404 //================================================================================
1405
1406 SMESH_subMesh* StdMeshers_Import_1D::getSubMeshOfCopiedMesh( SMESH_Mesh& tgtMesh,
1407                                                              SMESH_Mesh& srcMesh )
1408 {
1409   _ImportData* iData = _Listener::getImportData(&srcMesh,&tgtMesh);
1410   if ( iData->_copyMeshSubM.empty() ) return 0;
1411   SMESH_subMesh* sm = tgtMesh.GetSubMeshContaining( iData->_importMeshSubID );
1412   return sm;
1413 }
1414