1 // Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SMESH SMESH : implementation of SMESH idl descriptions
24 // File : StdMeshers_Import_1D.cxx
27 #include "StdMeshers_Import_1D.hxx"
28 #include "StdMeshers_ImportSource.hxx"
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_subMesh.hxx"
42 #include "SMESH_subMeshEventListener.hxx"
44 #include "Utils_SALOME_Exception.hxx"
45 #include "utilities.h"
47 #include <BRep_Builder.hxx>
48 #include <BRep_Tool.hxx>
50 #include <TopExp_Explorer.hxx>
52 #include <TopoDS_Compound.hxx>
53 #include <TopoDS_Edge.hxx>
54 #include <TopoDS_Vertex.hxx>
58 //=============================================================================
60 * Creates StdMeshers_Import_1D
62 //=============================================================================
64 StdMeshers_Import_1D::StdMeshers_Import_1D(int hypId, SMESH_Gen * gen)
65 :SMESH_1D_Algo(hypId, gen), _sourceHyp(0)
68 _shapeType = (1 << TopAbs_EDGE);
70 _compatibleHypothesis.push_back("ImportSource1D");
73 //================================================================================
74 namespace // INTERNAL STUFF
75 //================================================================================
77 int getSubmeshIDForCopiedMesh(const SMESHDS_Mesh* srcMeshDS, SMESH_Mesh* tgtMesh);
79 enum _ListenerDataType
81 WAIT_HYP_MODIF=1, // data indicating awaiting for valid parameters of src hyp
82 LISTEN_SRC_MESH, // data storing submesh depending on source mesh state
83 SRC_HYP // data storing ImportSource hyp
85 //================================================================================
87 * \brief _ListenerData holding ImportSource hyp holding in its turn
90 struct _ListenerData : public SMESH_subMeshEventListenerData
92 const StdMeshers_ImportSource1D* _srcHyp;
93 _ListenerData(const StdMeshers_ImportSource1D* h, _ListenerDataType type=SRC_HYP):
94 SMESH_subMeshEventListenerData(/*isDeletable=*/true), _srcHyp(h)
99 //================================================================================
101 * \brief Comparator of sub-meshes
105 bool operator()(const SMESH_subMesh* sm1, const SMESH_subMesh* sm2 ) const
107 if ( sm1 == sm2 ) return false;
108 if ( !sm1 || !sm2 ) return sm1 < sm2;
109 const TopoDS_Shape& s1 = sm1->GetSubShape();
110 const TopoDS_Shape& s2 = sm2->GetSubShape();
111 TopAbs_ShapeEnum t1 = s1.IsNull() ? TopAbs_SHAPE : s1.ShapeType();
112 TopAbs_ShapeEnum t2 = s2.IsNull() ? TopAbs_SHAPE : s2.ShapeType();
115 return t1 < t2; // to have: face < edge
118 //================================================================================
120 * \brief Container of data dedicated to one source mesh
124 const SMESH_Mesh* _srcMesh;
125 StdMeshers_Import_1D::TNodeNodeMap _n2n;
126 StdMeshers_Import_1D::TElemElemMap _e2e;
128 set< SMESH_subMesh*, _SubLess > _subM; // submeshes relating to this srcMesh
129 set< SMESH_subMesh*, _SubLess > _copyMeshSubM; // submeshes requesting mesh copying
130 set< SMESH_subMesh*, _SubLess > _copyGroupSubM; // submeshes requesting group copying
131 set< SMESH_subMesh*, _SubLess > _computedSubM;
133 SMESHDS_SubMesh* _importMeshSubDS; // submesh storing a copy of _srcMesh
134 int _importMeshSubID; // id of _importMeshSubDS
136 _ImportData(const SMESH_Mesh* srcMesh=0):
137 _srcMesh(srcMesh), _importMeshSubDS(0),_importMeshSubID(-1) {}
139 void removeImportedMesh( SMESHDS_Mesh* meshDS )
141 if ( !_importMeshSubDS ) return;
142 SMDS_ElemIteratorPtr eIt = _importMeshSubDS->GetElements();
143 while ( eIt->more() )
144 meshDS->RemoveFreeElement( eIt->next(), 0, /*fromGroups=*/false );
145 SMDS_NodeIteratorPtr nIt = _importMeshSubDS->GetNodes();
146 while ( nIt->more() )
147 meshDS->RemoveFreeNode( nIt->next(), 0, /*fromGroups=*/false );
148 _importMeshSubDS->Clear();
152 void removeGroups( SMESH_subMesh* subM, const StdMeshers_ImportSource1D* srcHyp )
154 if ( !srcHyp ) return;
155 SMESH_Mesh* tgtMesh = subM->GetFather();
156 const SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS();
157 const SMESHDS_Mesh* srcMeshDS = _srcMesh->GetMeshDS();
158 vector<SMESH_Group*>* groups =
159 const_cast<StdMeshers_ImportSource1D*>(srcHyp)->GetResultGroups(*srcMeshDS,*tgtMeshDS);
162 for ( unsigned i = 0; i < groups->size(); ++i )
163 tgtMesh->RemoveGroup( groups->at(i)->GetGroupDS()->GetID() );
167 void trackHypParams( SMESH_subMesh* sm, const StdMeshers_ImportSource1D* srcHyp )
169 if ( !srcHyp ) return;
170 bool toCopyMesh, toCopyGroups;
171 srcHyp->GetCopySourceMesh(toCopyMesh, toCopyGroups);
173 if ( toCopyMesh )_copyMeshSubM.insert( sm );
174 else _copyMeshSubM.erase( sm );
176 if ( toCopyGroups ) _copyGroupSubM.insert( sm );
177 else _copyGroupSubM.erase( sm );
179 void addComputed( SMESH_subMesh* sm )
181 SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true,
182 /*complexShapeFirst=*/true);
183 while ( smIt->more() )
186 switch ( sm->GetSubShape().ShapeType() )
189 if ( SMESH_Algo::isDegenerated( TopoDS::Edge( sm->GetSubShape() )))
193 if ( !sm->IsEmpty() )
194 _computedSubM.insert( sm );
202 //================================================================================
204 * Listener notified on events relating to imported submesh
206 class _Listener : public SMESH_subMeshEventListener
208 typedef map< SMESH_Mesh*, list< _ImportData > > TMesh2ImpData;
209 TMesh2ImpData _tgtMesh2ImportData;
211 _Listener():SMESH_subMeshEventListener(/*isDeletable=*/false,
212 "StdMeshers_Import_1D::_Listener") {}
215 // return pointer to a static listener
216 static _Listener* get() { static _Listener theListener; return &theListener; }
218 static _ImportData* getImportData(const SMESH_Mesh* srcMesh, SMESH_Mesh* tgtMesh);
220 static void storeImportSubmesh(SMESH_subMesh* importSub,
221 const SMESH_Mesh* srcMesh,
222 const StdMeshers_ImportSource1D* srcHyp);
224 virtual void ProcessEvent(const int event,
226 SMESH_subMesh* subMesh,
227 SMESH_subMeshEventListenerData* data,
228 const SMESH_Hypothesis* hyp);
229 void removeSubmesh( SMESH_subMesh* sm, _ListenerData* data );
230 void clearSubmesh ( SMESH_subMesh* sm, _ListenerData* data, bool clearAllSub );
231 void clearN2N ( SMESH_Mesh* tgtMesh );
233 // mark sm as missing src hyp with valid groups
234 static void waitHypModification(SMESH_subMesh* sm)
237 (get(), SMESH_subMeshEventListenerData::MakeData( sm, WAIT_HYP_MODIF ), sm);
240 //--------------------------------------------------------------------------------
242 * \brief Find or create ImportData for given meshes
244 _ImportData* _Listener::getImportData(const SMESH_Mesh* srcMesh,
247 list< _ImportData >& dList = get()->_tgtMesh2ImportData[tgtMesh];
248 list< _ImportData >::iterator d = dList.begin();
249 for ( ; d != dList.end(); ++d )
250 if ( d->_srcMesh == srcMesh )
252 dList.push_back(_ImportData(srcMesh));
253 return &dList.back();
256 //--------------------------------------------------------------------------------
258 * \brief Remember an imported sub-mesh and set needed even listeners
259 * \param importSub - submesh computed by Import algo
260 * \param srcMesh - source mesh
261 * \param srcHyp - ImportSource hypothesis
263 void _Listener::storeImportSubmesh(SMESH_subMesh* importSub,
264 const SMESH_Mesh* srcMesh,
265 const StdMeshers_ImportSource1D* srcHyp)
267 // set listener to hear events of the submesh computed by "Import" algo
268 importSub->SetEventListener( get(), new _ListenerData(srcHyp), importSub );
270 // set listeners to hear events of the source mesh
271 SMESH_subMesh* smToNotify = importSub;
272 vector<SMESH_subMesh*> smToListen = srcHyp->GetSourceSubMeshes( srcMesh );
273 for ( size_t i = 0; i < smToListen.size(); ++i )
275 SMESH_subMeshEventListenerData* data = new _ListenerData(srcHyp, LISTEN_SRC_MESH);
276 data->mySubMeshes.push_back( smToNotify );
277 importSub->SetEventListener( get(), data, smToListen[i] );
279 // remember the submesh importSub and its sub-submeshes
280 _ImportData* iData = _Listener::getImportData( srcMesh, importSub->GetFather());
281 iData->trackHypParams( importSub, srcHyp );
282 iData->addComputed( importSub );
283 if ( !iData->_copyMeshSubM.empty() && iData->_importMeshSubID < 1 )
285 SMESH_Mesh* tgtMesh = importSub->GetFather();
286 iData->_importMeshSubID = getSubmeshIDForCopiedMesh( srcMesh->GetMeshDS(),tgtMesh);
287 iData->_importMeshSubDS = tgtMesh->GetMeshDS()->NewSubMesh( iData->_importMeshSubID );
290 //--------------------------------------------------------------------------------
292 * \brief Remove imported mesh and/or groups if needed
293 * \param sm - submesh losing Import algo
294 * \param data - data holding imported groups
296 void _Listener::removeSubmesh( SMESH_subMesh* sm, _ListenerData* data )
298 list< _ImportData > & dList = _tgtMesh2ImportData[ sm->GetFather() ];
299 list< _ImportData >::iterator d = dList.begin();
300 for ( ; d != dList.end(); ++d )
301 if ( (*d)._subM.erase( sm ))
303 d->_computedSubM.erase( sm );
304 bool rmMesh = d->_copyMeshSubM.erase( sm ) && d->_copyMeshSubM.empty();
305 bool rmGroups = (d->_copyGroupSubM.erase( sm ) && d->_copyGroupSubM.empty()) || rmMesh;
307 d->removeImportedMesh( sm->GetFather()->GetMeshDS() );
308 if ( rmGroups && data && data->myType == SRC_HYP )
309 d->removeGroups( sm, data->_srcHyp );
312 //--------------------------------------------------------------------------------
314 * \brief Clear _ImportData::_n2n.
315 * _n2n is useful within one mesh.Compute() only
317 void _Listener::clearN2N( SMESH_Mesh* tgtMesh )
319 list< _ImportData >& dList = get()->_tgtMesh2ImportData[tgtMesh];
320 list< _ImportData >::iterator d = dList.begin();
321 for ( ; d != dList.end(); ++d )
324 //--------------------------------------------------------------------------------
326 * \brief Clear submeshes and remove imported mesh and/or groups if necessary
327 * \param sm - cleared submesh
328 * \param data - data holding imported groups
330 void _Listener::clearSubmesh(SMESH_subMesh* sm, _ListenerData* data, bool clearAllSub)
332 list< _ImportData > & dList = _tgtMesh2ImportData[ sm->GetFather() ];
333 list< _ImportData >::iterator d = dList.begin();
334 for ( ; d != dList.end(); ++d )
336 if ( !d->_subM.count( sm )) continue;
337 if ( (*d)._computedSubM.erase( sm ) )
339 bool copyMesh = !d->_copyMeshSubM.empty();
340 if ( copyMesh || clearAllSub )
342 // remove imported mesh and groups
343 d->removeImportedMesh( sm->GetFather()->GetMeshDS() );
345 if ( data && data->myType == SRC_HYP )
346 d->removeGroups( sm, data->_srcHyp );
348 // clear the rest submeshes
349 if ( !d->_computedSubM.empty() )
351 d->_computedSubM.clear();
352 set< SMESH_subMesh*, _SubLess>::iterator sub = d->_subM.begin();
353 for ( ; sub != d->_subM.end(); ++sub )
355 SMESH_subMesh* subM = *sub;
356 _ListenerData* hypData = (_ListenerData*) subM->GetEventListenerData( get() );
357 if ( hypData && hypData->myType == SRC_HYP )
358 d->removeGroups( sm, hypData->_srcHyp );
360 subM->ComputeStateEngine( SMESH_subMesh::CLEAN );
361 if ( subM->GetSubShape().ShapeType() == TopAbs_FACE )
362 subM->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN );
366 sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
367 if ( sm->GetSubShape().ShapeType() == TopAbs_FACE )
368 sm->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN );
370 if ( data && data->myType == SRC_HYP )
371 d->trackHypParams( sm, data->_srcHyp );
376 //--------------------------------------------------------------------------------
378 * \brief Remove imported mesh and/or groups
380 void _Listener::ProcessEvent(const int event,
382 SMESH_subMesh* subMesh,
383 SMESH_subMeshEventListenerData* data,
384 const SMESH_Hypothesis* /*hyp*/)
386 if ( data && data->myType == WAIT_HYP_MODIF )
388 // event of Import submesh
389 if ( SMESH_subMesh::MODIF_HYP == event &&
390 SMESH_subMesh::ALGO_EVENT == eventType )
392 // re-call SetEventListener() to take into account valid parameters
393 // of ImportSource hypothesis
394 if ( SMESH_Algo* algo = subMesh->GetAlgo() )
395 algo->SetEventListener( subMesh );
398 else if ( data && data->myType == LISTEN_SRC_MESH )
400 // event of source mesh
401 if ( SMESH_subMesh::COMPUTE_EVENT == eventType )
404 case SMESH_subMesh::CLEAN:
405 // source mesh cleaned -> clean target mesh
406 clearSubmesh( data->mySubMeshes.front(), (_ListenerData*) data, /*all=*/true );
408 case SMESH_subMesh::SUBMESH_COMPUTED: {
409 // source mesh computed -> reset FAILED state of Import submeshes to
411 SMESH_Mesh* srcMesh = subMesh->GetFather();
412 if ( srcMesh->NbEdges() > 0 || srcMesh->NbFaces() > 0 )
414 SMESH_Mesh* m = data->mySubMeshes.front()->GetFather();
415 if ( SMESH_subMesh* sm1 = m->GetSubMeshContaining(1))
417 sm1->ComputeStateEngine(SMESH_subMesh::SUBMESH_COMPUTED );
418 sm1->ComputeSubMeshStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
426 if ( !data->mySubMeshes.empty() )
427 clearN2N( data->mySubMeshes.front()->GetFather() );
429 else // event of Import submesh
431 // find out what happens: import hyp modified or removed
432 bool removeImport = false, modifHyp = false;
433 if ( SMESH_subMesh::ALGO_EVENT == eventType )
435 if ( subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK )
439 else if (( SMESH_subMesh::REMOVE_ALGO == event ||
440 SMESH_subMesh::REMOVE_FATHER_ALGO == event ) &&
441 SMESH_subMesh::ALGO_EVENT == eventType )
443 SMESH_Algo* algo = subMesh->GetAlgo();
444 removeImport = ( strncmp( "Import", algo->GetName(), 6 ) != 0 );
449 // treate removal of Import algo from subMesh
450 removeSubmesh( subMesh, (_ListenerData*) data );
452 else if ( modifHyp ||
453 ( SMESH_subMesh::CLEAN == event &&
454 SMESH_subMesh::COMPUTE_EVENT == eventType))
456 // treate modification of ImportSource hypothesis
457 clearSubmesh( subMesh, (_ListenerData*) data, /*all=*/false );
459 else if ( SMESH_subMesh::CHECK_COMPUTE_STATE == event &&
460 SMESH_subMesh::COMPUTE_EVENT == eventType )
462 // check compute state of all submeshes impoting from same src mesh;
463 // this is to take into account 1D computed submeshes hidden by 2D import algo;
464 // else source mesh is not copied as _subM.size != _computedSubM.size()
465 list< _ImportData > & dList = _tgtMesh2ImportData[ subMesh->GetFather() ];
466 list< _ImportData >::iterator d = dList.begin();
467 for ( ; d != dList.end(); ++d )
468 if ( d->_subM.count( subMesh ))
470 set<SMESH_subMesh*,_SubLess>::iterator smIt = d->_subM.begin();
471 for( ; smIt != d->_subM.end(); ++smIt )
472 if ( (*smIt)->IsMeshComputed() )
473 d->_computedSubM.insert( *smIt);
476 // Clear _ImportData::_n2n if it's no more useful, i.e. when
477 // the event is not within mesh.Compute()
478 if ( SMESH_subMesh::ALGO_EVENT == eventType )
479 clearN2N( subMesh->GetFather() );
483 //================================================================================
485 * \brief Return an ID of submesh to store nodes and elements of a copied mesh
487 //================================================================================
489 int getSubmeshIDForCopiedMesh(const SMESHDS_Mesh* srcMeshDS,
492 // To get SMESH_subMesh corresponding to srcMeshDS we need to have a shape
493 // for which SMESHDS_Mesh::IsGroupOfSubShapes() returns true.
494 // And this shape must be different from sub-shapes of the main shape.
495 // So we create a compound containing
496 // 1) some sub-shapes of SMESH_Mesh::PseudoShape() corresponding to
497 // srcMeshDS->GetPersistentId()
498 // 2) the 1-st vertex of the main shape to assure
499 // SMESHDS_Mesh::IsGroupOfSubShapes(shape)==true
500 TopoDS_Shape shapeForSrcMesh;
501 TopTools_IndexedMapOfShape pseudoSubShapes;
502 TopExp::MapShapes( SMESH_Mesh::PseudoShape(), pseudoSubShapes );
504 // index of pseudoSubShapes corresponding to srcMeshDS
505 int subIndex = 1 + srcMeshDS->GetPersistentId() % pseudoSubShapes.Extent();
506 int nbSubShapes = 1 + srcMeshDS->GetPersistentId() / pseudoSubShapes.Extent();
508 // try to find already present shapeForSrcMesh
509 SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS();
510 for ( int i = tgtMeshDS->MaxShapeIndex(); i > 0 && shapeForSrcMesh.IsNull(); --i )
512 const TopoDS_Shape& s = tgtMeshDS->IndexToShape(i);
513 if ( s.ShapeType() != TopAbs_COMPOUND ) break;
514 TopoDS_Iterator sSubIt( s );
515 for ( int iSub = 0; iSub < nbSubShapes && sSubIt.More(); ++iSub, sSubIt.Next() )
516 if ( pseudoSubShapes( subIndex+iSub ).IsSame( sSubIt.Value()))
517 if ( iSub+1 == nbSubShapes )
523 if ( shapeForSrcMesh.IsNull() )
525 // make a new shapeForSrcMesh
526 BRep_Builder aBuilder;
527 TopoDS_Compound comp;
528 aBuilder.MakeCompound( comp );
529 shapeForSrcMesh = comp;
530 for ( int iSub = 0; iSub < nbSubShapes; ++iSub )
531 if ( subIndex+iSub <= pseudoSubShapes.Extent() )
532 aBuilder.Add( comp, pseudoSubShapes( subIndex+iSub ));
533 TopExp_Explorer vExp( tgtMeshDS->ShapeToMesh(), TopAbs_VERTEX );
534 aBuilder.Add( comp, vExp.Current() );
536 SMESH_subMesh* sm = tgtMesh->GetSubMesh( shapeForSrcMesh );
537 SMESHDS_SubMesh* smDS = sm->GetSubMeshDS();
539 smDS = tgtMeshDS->NewSubMesh( sm->GetId() );
541 // make ordinary submesh from a complex one
542 if ( smDS->IsComplexSubmesh() )
544 list< const SMESHDS_SubMesh* > subSM;
545 SMESHDS_SubMeshIteratorPtr smIt = smDS->GetSubMeshIterator();
546 while ( smIt->more() ) subSM.push_back( smIt->next() );
547 list< const SMESHDS_SubMesh* >::iterator sub = subSM.begin();
548 for ( ; sub != subSM.end(); ++sub)
549 smDS->RemoveSubMesh( *sub );
554 //================================================================================
556 * \brief Return a submesh to store nodes and elements of a copied mesh
557 * and set event listeners in order to clear
558 * imported mesh and groups as soon as submesh state requires it
560 //================================================================================
562 SMESHDS_SubMesh* getSubmeshForCopiedMesh(const SMESH_Mesh* srcMesh,
564 const TopoDS_Shape& tgtShape,
565 StdMeshers_Import_1D::TNodeNodeMap*& n2n,
566 StdMeshers_Import_1D::TElemElemMap*& e2e,
569 StdMeshers_Import_1D::getMaps( srcMesh, tgtMesh, n2n,e2e );
571 _ImportData* iData = _Listener::getImportData(srcMesh,tgtMesh);
573 SMESH_subMesh* importedSM = tgtMesh->GetSubMesh( tgtShape );
574 iData->addComputed( importedSM );
575 if ( iData->_computedSubM.size() != iData->_subM.size() )
576 return 0; // not all submeshes computed yet
578 toCopyGroups = !iData->_copyGroupSubM.empty();
580 if ( !iData->_copyMeshSubM.empty())
582 // make submesh to store a copied mesh
583 int smID = getSubmeshIDForCopiedMesh( srcMesh->GetMeshDS(), tgtMesh );
584 SMESHDS_SubMesh* subDS = tgtMesh->GetMeshDS()->NewSubMesh( smID );
586 iData->_importMeshSubID = smID;
587 iData->_importMeshSubDS = subDS;
595 //=============================================================================
597 * Check presence of a hypothesis
599 //=============================================================================
601 bool StdMeshers_Import_1D::CheckHypothesis
603 const TopoDS_Shape& aShape,
604 SMESH_Hypothesis::Hypothesis_Status& aStatus)
608 const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape);
609 if ( hyps.size() == 0 )
611 aStatus = SMESH_Hypothesis::HYP_MISSING;
612 return false; // can't work with no hypothesis
615 if ( hyps.size() > 1 )
617 aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST;
621 const SMESHDS_Hypothesis *theHyp = hyps.front();
623 string hypName = theHyp->GetName();
625 if (hypName == _compatibleHypothesis.front())
627 _sourceHyp = (StdMeshers_ImportSource1D *)theHyp;
628 aStatus = _sourceHyp->GetGroups().empty() ? HYP_BAD_PARAMETER : HYP_OK;
629 if ( aStatus == HYP_BAD_PARAMETER )
630 _Listener::waitHypModification( aMesh.GetSubMesh( aShape ));
631 return aStatus == HYP_OK;
634 aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
638 //=============================================================================
640 * Import elements from the other mesh
642 //=============================================================================
644 bool StdMeshers_Import_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & theShape)
646 if ( !_sourceHyp ) return false;
648 //MESSAGE("---------> StdMeshers_Import_1D::Compute");
649 const vector<SMESH_Group*>& srcGroups = _sourceHyp->GetGroups(/*loaded=*/true);
650 if ( srcGroups.empty() )
651 return error("Invalid source groups");
653 SMESH_MesherHelper helper(theMesh);
654 helper.SetSubShape(theShape);
655 SMESHDS_Mesh* tgtMesh = theMesh.GetMeshDS();
657 const TopoDS_Edge& geomEdge = TopoDS::Edge( theShape );
658 const double edgeTol = BRep_Tool::Tolerance( geomEdge );
659 const int shapeID = tgtMesh->ShapeToIndex( geomEdge );
661 set<int> subShapeIDs;
662 subShapeIDs.insert( shapeID );
664 // get nodes on vertices
665 list < SMESH_TNodeXYZ > vertexNodes;
666 list < SMESH_TNodeXYZ >::iterator vNIt;
667 TopExp_Explorer vExp( theShape, TopAbs_VERTEX );
668 for ( ; vExp.More(); vExp.Next() )
670 const TopoDS_Vertex& v = TopoDS::Vertex( vExp.Current() );
671 if ( !subShapeIDs.insert( tgtMesh->ShapeToIndex( v )).second )
672 continue; // closed edge
673 const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, tgtMesh );
676 _gen->Compute(theMesh,v,/*anUpward=*/true);
677 n = SMESH_Algo::VertexNode( v, tgtMesh );
678 //MESSAGE("_gen->Compute " << n);
679 if ( !n ) return false; // very strange
681 vertexNodes.push_back( SMESH_TNodeXYZ( n ));
682 //MESSAGE("SMESH_Algo::VertexNode " << n->GetID() << " " << n->X() << " " << n->Y() << " " << n->Z() );
685 // import edges from groups
688 for ( size_t iG = 0; iG < srcGroups.size(); ++iG )
690 const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS();
692 const int meshID = srcGroup->GetMesh()->GetPersistentId();
693 const SMESH_Mesh* srcMesh = GetMeshByPersistentID( meshID );
694 if ( !srcMesh ) continue;
695 getMaps( srcMesh, &theMesh, n2n, e2e );
697 SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements();
698 vector<const SMDS_MeshNode*> newNodes;
699 SMDS_MeshNode *tmpNode = helper.AddNode(0,0,0);
700 double u = 0.314159; // "random" value between 0 and 1, avoid 0 and 1, false detection possible on edge restrictions
701 while ( srcElems->more() ) // loop on group contents
703 const SMDS_MeshElement* edge = srcElems->next();
704 // find or create nodes of a new edge
705 newNodes.resize( edge->NbNodes() );
706 //MESSAGE("edge->NbNodes " << edge->NbNodes());
708 SMDS_MeshElement::iterator node = edge->begin_nodes();
709 SMESH_TNodeXYZ a(edge->GetNode(0));
710 // --- define a tolerance relative to the length of an edge
711 double mytol = a.Distance(edge->GetNode(edge->NbNodes()-1))/25;
712 //mytol = max(1.E-5, 10*edgeTol); // too strict and not necessary
713 //MESSAGE("mytol = " << mytol);
714 for ( size_t i = 0; i < newNodes.size(); ++i, ++node )
716 TNodeNodeMap::iterator n2nIt = n2n->insert( make_pair( *node, (SMDS_MeshNode*)0 )).first;
719 if ( !subShapeIDs.count( n2nIt->second->getshapeId() ))
724 // find an existing vertex node
725 double checktol = max(1.E-10, 10*edgeTol*edgeTol);
726 for ( vNIt = vertexNodes.begin(); vNIt != vertexNodes.end(); ++vNIt)
727 if ( vNIt->SquareDistance( *node ) < checktol)
729 //MESSAGE("SquareDistance " << vNIt->SquareDistance( *node ) << " checktol " << checktol <<" "<<vNIt->X()<<" "<<vNIt->Y()<<" "<<vNIt->Z());
730 (*n2nIt).second = vNIt->_node;
731 vertexNodes.erase( vNIt );
734 else if ( vNIt->SquareDistance( *node ) < 10*checktol)
735 MESSAGE("SquareDistance missed" << vNIt->SquareDistance( *node ) << " checktol " << checktol <<" "<<vNIt->X()<<" "<<vNIt->Y()<<" "<<vNIt->Z());
737 if ( !n2nIt->second )
739 // find out if node lies on theShape
741 tmpNode->setXYZ( (*node)->X(), (*node)->Y(), (*node)->Z());
742 if ( helper.CheckNodeU( geomEdge, tmpNode, u, mytol, /*force=*/true)) // , dxyz )) // dxyz used for debug purposes
744 SMDS_MeshNode* newNode = tgtMesh->AddNode( (*node)->X(), (*node)->Y(), (*node)->Z());
745 n2nIt->second = newNode;
746 tgtMesh->SetNodeOnEdge( newNode, shapeID, u );
747 //MESSAGE("u=" << u << " " << newNode->X()<< " " << newNode->Y()<< " " << newNode->Z());
748 //MESSAGE("d=" << dxyz[0] << " " << dxyz[1] << " " << dxyz[2] << " " << dxyz[3]);
751 if ( !(newNodes[i] = n2nIt->second ))
754 if ( !newNodes.back() )
756 //MESSAGE("not all nodes of edge lie on theShape");
757 continue; // not all nodes of edge lie on theShape
761 SMDS_MeshElement * newEdge;
762 if ( newNodes.size() == 3 )
763 newEdge = tgtMesh->AddEdge( newNodes[0], newNodes[1], newNodes[2] );
765 newEdge = tgtMesh->AddEdge( newNodes[0], newNodes[1]);
766 //MESSAGE("add Edge " << newNodes[0]->GetID() << " " << newNodes[1]->GetID());
767 tgtMesh->SetMeshElementOnShape( newEdge, shapeID );
768 e2e->insert( make_pair( edge, newEdge ));
770 helper.GetMeshDS()->RemoveNode(tmpNode);
773 return error("Empty source groups");
775 // check if the whole geom edge is covered by imported segments;
776 // the check consist in passing by segments from one vetrex node to another
777 bool isEdgeMeshed = false;
778 if ( SMESHDS_SubMesh* tgtSM = tgtMesh->MeshElements( theShape ))
780 const TopoDS_Vertex& v = ( vExp.ReInit(), TopoDS::Vertex( vExp.Current() ));
781 const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, tgtMesh );
782 const SMDS_MeshElement* seg = 0;
783 SMDS_ElemIteratorPtr segIt = n->GetInverseElementIterator(SMDSAbs_Edge);
784 while ( segIt->more() && !seg )
785 if ( !tgtSM->Contains( seg = segIt->next()))
787 int nbPassedSegs = 0;
791 const SMDS_MeshNode* n2 = seg->GetNode(0);
792 n = ( n2 == n ? seg->GetNode(1) : n2 );
793 if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
795 const SMDS_MeshElement* seg2 = 0;
796 segIt = n->GetInverseElementIterator(SMDSAbs_Edge);
797 while ( segIt->more() && !seg2 )
798 if ( seg == ( seg2 = segIt->next()))
802 if (nbPassedSegs > 0 && tgtSM->NbElements() > nbPassedSegs )
803 return error( "Source elements overlap one another");
805 isEdgeMeshed = ( tgtSM->NbElements() == nbPassedSegs &&
806 n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX );
809 return error( "Source elements don't cover totally the geometrical edge" );
812 vector<SMESH_Mesh*> srcMeshes = _sourceHyp->GetSourceMeshes();
813 for ( size_t i = 0; i < srcMeshes.size(); ++i )
814 importMesh( srcMeshes[i], theMesh, _sourceHyp, theShape );
819 //================================================================================
821 * \brief Copy mesh and groups
823 //================================================================================
825 void StdMeshers_Import_1D::importMesh(const SMESH_Mesh* srcMesh,
826 SMESH_Mesh & tgtMesh,
827 StdMeshers_ImportSource1D* srcHyp,
828 const TopoDS_Shape& tgtShape)
830 // get submesh to store the imported mesh
834 SMESHDS_SubMesh* tgtSubMesh =
835 getSubmeshForCopiedMesh( srcMesh, &tgtMesh, tgtShape, n2n, e2e, toCopyGroups );
836 if ( !tgtSubMesh || tgtSubMesh->NbNodes() + tgtSubMesh->NbElements() > 0 )
837 return; // not to copy srcMeshDS twice
839 SMESHDS_Mesh* tgtMeshDS = tgtMesh.GetMeshDS();
840 SMESH_MeshEditor additor( &tgtMesh );
844 SMESH_MeshEditor::ElemFeatures elemType;
845 vector<const SMDS_MeshNode*> newNodes;
846 const SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
847 SMDS_ElemIteratorPtr eIt = srcMeshDS->elementsIterator();
848 while ( eIt->more() )
850 const SMDS_MeshElement* elem = eIt->next();
851 TElemElemMap::iterator e2eIt = e2e->insert( make_pair( elem, (SMDS_MeshElement*)0 )).first;
852 if ( e2eIt->second ) continue; // already copied by Compute()
853 newNodes.resize( elem->NbNodes() );
854 SMDS_MeshElement::iterator node = elem->begin_nodes();
855 for ( unsigned i = 0; i < newNodes.size(); ++i, ++node )
857 TNodeNodeMap::iterator n2nIt = n2n->insert( make_pair( *node, (SMDS_MeshNode*)0 )).first;
858 if ( !n2nIt->second )
860 (*n2nIt).second = tgtMeshDS->AddNode( (*node)->X(), (*node)->Y(), (*node)->Z());
861 tgtSubMesh->AddNode( n2nIt->second );
863 newNodes[i] = n2nIt->second;
865 const SMDS_MeshElement* newElem =
866 tgtMeshDS->FindElement( newNodes, elem->GetType(), /*noMedium=*/false );
869 newElem = additor.AddElement( newNodes, elemType.Init( elem, /*basicOnly=*/false ));
870 tgtSubMesh->AddElement( newElem );
873 (*e2eIt).second = newElem;
876 if ( srcMeshDS->NbNodes() > (int) n2n->size() )
878 SMDS_NodeIteratorPtr nIt = srcMeshDS->nodesIterator();
881 const SMDS_MeshNode* node = nIt->next();
882 if ( node->NbInverseElements() == 0 )
884 const SMDS_MeshNode* newNode = tgtMeshDS->AddNode( node->X(), node->Y(), node->Z());
885 n2n->insert( make_pair( node, newNode ));
886 tgtSubMesh->AddNode( newNode );
893 vector<SMESH_Group*> resultGroups;
896 // collect names of existing groups to assure uniqueness of group names within a type
897 map< SMDSAbs_ElementType, set<string> > namesByType;
898 SMESH_Mesh::GroupIteratorPtr groupIt = tgtMesh.GetGroups();
899 while ( groupIt->more() )
901 SMESH_Group* tgtGroup = groupIt->next();
902 namesByType[ tgtGroup->GetGroupDS()->GetType() ].insert( tgtGroup->GetName() );
906 SMESH_Mesh::GroupIteratorPtr groupIt = srcMesh->GetGroups();
907 while ( groupIt->more() )
909 SMESH_Group* srcGroup = groupIt->next();
910 SMESHDS_GroupBase* srcGroupDS = srcGroup->GetGroupDS();
911 string name = srcGroup->GetName();
913 while ( !namesByType[ srcGroupDS->GetType() ].insert( name ).second )
914 name = SMESH_Comment(srcGroup->GetName()) << "_imported_" << nb++;
915 SMESH_Group* newGroup = tgtMesh.AddGroup( srcGroupDS->GetType(), name.c_str() );
916 SMESHDS_Group* newGroupDS = (SMESHDS_Group*)newGroup->GetGroupDS();
917 resultGroups.push_back( newGroup );
919 eIt = srcGroupDS->GetElements();
920 if ( srcGroupDS->GetType() == SMDSAbs_Node )
923 TNodeNodeMap::iterator n2nIt = n2n->find((const SMDS_MeshNode*) eIt->next() );
924 if ( n2nIt != n2n->end() && n2nIt->second )
925 newGroupDS->SMDSGroup().Add((*n2nIt).second );
930 TElemElemMap::iterator e2eIt = e2e->find( eIt->next() );
931 if ( e2eIt != e2e->end() && e2eIt->second )
932 newGroupDS->SMDSGroup().Add((*e2eIt).second );
940 // Remember created groups in order to remove them as soon as the srcHyp is
941 // modified or something other similar happens. This imformation must be persistent,
942 // for that store them in a hypothesis as it stores its values in the file anyway
943 srcHyp->StoreResultGroups( resultGroups, *srcMeshDS, *tgtMeshDS );
946 //=============================================================================
948 * \brief Set needed event listeners and create a submesh for a copied mesh
950 * This method is called only if a submesh has HYP_OK algo_state.
952 //=============================================================================
954 void StdMeshers_Import_1D::setEventListener(SMESH_subMesh* subMesh,
955 StdMeshers_ImportSource1D* sourceHyp)
959 vector<SMESH_Mesh*> srcMeshes = sourceHyp->GetSourceMeshes();
960 if ( srcMeshes.empty() )
961 _Listener::waitHypModification( subMesh );
962 for ( unsigned i = 0; i < srcMeshes.size(); ++i )
963 // set a listener to remove the imported mesh and groups
964 _Listener::storeImportSubmesh( subMesh, srcMeshes[i], sourceHyp );
967 void StdMeshers_Import_1D::SetEventListener(SMESH_subMesh* subMesh)
971 const TopoDS_Shape& tgtShape = subMesh->GetSubShape();
972 SMESH_Mesh* tgtMesh = subMesh->GetFather();
973 Hypothesis_Status aStatus;
974 CheckHypothesis( *tgtMesh, tgtShape, aStatus );
976 setEventListener( subMesh, _sourceHyp );
979 void StdMeshers_Import_1D::SubmeshRestored(SMESH_subMesh* subMesh)
981 SetEventListener(subMesh);
984 //=============================================================================
986 * Predict nb of mesh entities created by Compute()
988 //=============================================================================
990 bool StdMeshers_Import_1D::Evaluate(SMESH_Mesh & theMesh,
991 const TopoDS_Shape & theShape,
992 MapShapeNbElems& aResMap)
994 if ( !_sourceHyp ) return false;
996 const vector<SMESH_Group*>& srcGroups = _sourceHyp->GetGroups();
997 if ( srcGroups.empty() )
998 return error("Invalid source groups");
1000 vector<int> aVec(SMDSEntity_Last,0);
1002 bool toCopyMesh, toCopyGroups;
1003 _sourceHyp->GetCopySourceMesh(toCopyMesh, toCopyGroups);
1004 if ( toCopyMesh ) // the whole mesh is copied
1006 vector<SMESH_Mesh*> srcMeshes = _sourceHyp->GetSourceMeshes();
1007 for ( unsigned i = 0; i < srcMeshes.size(); ++i )
1009 SMESH_subMesh* sm = getSubMeshOfCopiedMesh( theMesh, *srcMeshes[i]);
1010 if ( !sm || aResMap.count( sm )) continue; // already counted
1011 aVec.assign( SMDSEntity_Last, 0);
1012 const SMDS_MeshInfo& aMeshInfo = srcMeshes[i]->GetMeshDS()->GetMeshInfo();
1013 for (int i = 0; i < SMDSEntity_Last; i++)
1014 aVec[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i);
1019 SMESH_MesherHelper helper(theMesh);
1021 const TopoDS_Edge& geomEdge = TopoDS::Edge( theShape );
1022 const double edgeTol = helper.MaxTolerance( geomEdge );
1024 // take into account nodes on vertices
1025 TopExp_Explorer vExp( theShape, TopAbs_VERTEX );
1026 for ( ; vExp.More(); vExp.Next() )
1027 theMesh.GetSubMesh( vExp.Current())->Evaluate( aResMap );
1029 // count edges imported from groups
1030 int nbEdges = 0, nbQuadEdges = 0;
1031 for ( size_t iG = 0; iG < srcGroups.size(); ++iG )
1033 const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS();
1034 SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements();
1035 SMDS_MeshNode *tmpNode = helper.AddNode(0,0,0);
1036 while ( srcElems->more() ) // loop on group contents
1038 const SMDS_MeshElement* edge = srcElems->next();
1039 // find out if edge is located on geomEdge by projecting
1040 // a middle of edge to geomEdge
1041 SMESH_TNodeXYZ p1( edge->GetNode(0));
1042 SMESH_TNodeXYZ p2( edge->GetNode(1));
1043 gp_XYZ middle = ( p1 + p2 ) / 2.;
1044 tmpNode->setXYZ( middle.X(), middle.Y(), middle.Z());
1046 if ( helper.CheckNodeU( geomEdge, tmpNode, u, 10 * edgeTol, /*force=*/true ))
1047 ++( edge->IsQuadratic() ? nbQuadEdges : nbEdges);
1049 helper.GetMeshDS()->RemoveNode(tmpNode);
1052 int nbNodes = nbEdges + 2 * nbQuadEdges - 1;
1054 aVec[SMDSEntity_Node ] = nbNodes;
1055 aVec[SMDSEntity_Edge ] = nbEdges;
1056 aVec[SMDSEntity_Quad_Edge] = nbQuadEdges;
1059 SMESH_subMesh * sm = theMesh.GetSubMesh(theShape);
1060 aResMap.insert( make_pair( sm, aVec ));
1065 //================================================================================
1067 * \brief Return node-node and element-element maps for import of geiven source mesh
1069 //================================================================================
1071 void StdMeshers_Import_1D::getMaps(const SMESH_Mesh* srcMesh,
1072 SMESH_Mesh* tgtMesh,
1076 _ImportData* iData = _Listener::getImportData(srcMesh,tgtMesh);
1079 if ( iData->_copyMeshSubM.empty() )
1081 // n2n->clear(); -- for sharing nodes on EDGEs
1086 //================================================================================
1088 * \brief Return submesh corresponding to the copied mesh
1090 //================================================================================
1092 SMESH_subMesh* StdMeshers_Import_1D::getSubMeshOfCopiedMesh( SMESH_Mesh& tgtMesh,
1093 SMESH_Mesh& srcMesh )
1095 _ImportData* iData = _Listener::getImportData(&srcMesh,&tgtMesh);
1096 if ( iData->_copyMeshSubM.empty() ) return 0;
1097 SMESH_subMesh* sm = tgtMesh.GetSubMeshContaining( iData->_importMeshSubID );