Salome HOME
fix SHAPERSTUDY: when two meshes are on the same geometry
[modules/smesh.git] / src / SMESH_I / SMESH_Mesh_i.cxx
index d4e396cbdfacd0556715d974ba7d7b1d655a9077..9988bf4cbf0a137ed9cb962eb72be50801f285ec 100644 (file)
@@ -270,6 +270,16 @@ void SMESH_Mesh_i::ReplaceShape(GEOM::GEOM_Object_ptr theNewGeom)
   if (geomClient->Find(S, aIOR)) {
     geomClient->RemoveShapeFromBuffer(aIOR);
   }
+  // clear buffer also for sub-groups
+  const std::set<SMESHDS_GroupBase*>& groups = _impl->GetMeshDS()->GetGroups();
+  std::set<SMESHDS_GroupBase*>::const_iterator g = groups.begin();
+  for (; g != groups.end(); ++g)
+    if (const SMESHDS_GroupOnGeom* group = dynamic_cast<SMESHDS_GroupOnGeom*>(*g))
+    {
+      const TopoDS_Shape& s = group->GetShape();
+      if (geomClient->Find(s, aIOR))
+        geomClient->RemoveShapeFromBuffer(aIOR);
+    }
 
   // update the reference to theNewGeom (needed for correct execution of a dumped python script)
   SMESH::SMESH_Mesh_var   me = _this();
@@ -2028,9 +2038,9 @@ void SMESH_Mesh_i::addGeomGroupData(GEOM::GEOM_Object_ptr theGeomObj,
   if ( groupSO->_is_nil() )
     return;
   // group indices
-  GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine( theGeomObj );
-  GEOM::GEOM_IGroupOperations_ptr groupOp = geomGen->GetIGroupOperations();
-  GEOM::ListOfLong_var ids = groupOp->GetObjects( theGeomObj );
+  GEOM::GEOM_Gen_var               geomGen = _gen_i->GetGeomEngine( theGeomObj );
+  GEOM::GEOM_IGroupOperations_wrap groupOp = geomGen->GetIGroupOperations();
+  GEOM::ListOfLong_var                 ids = groupOp->GetObjects( theGeomObj );
 
   // store data
   _geomGroupData.push_back( TGeomGroupData() );
@@ -2076,59 +2086,82 @@ enum { ONLY_IF_CHANGED, IS_BREAK_LINK, MAIN_TRANSFORMED };
 TopoDS_Shape SMESH_Mesh_i::newGroupShape( TGeomGroupData & groupData, int how )
 {
   TopoDS_Shape newShape;
+  SALOMEDS::SObject_wrap groupSO;
 
   if ( how == IS_BREAK_LINK )
   {
     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( groupData._smeshObject );
-    SALOMEDS::SObject_wrap geomRefSO, geomSO;
+    SALOMEDS::SObject_wrap geomRefSO;
     if ( !meshSO->_is_nil() &&
-         meshSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
-         geomRefSO->ReferencedObject( geomSO.inout() ))
+         meshSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ))
     {
-      CORBA::Object_var  geomObj = _gen_i->SObjectToObject( geomSO );
-      GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( geomObj );
-      newShape = _gen_i->GeomObjectToShape( geom );
-      CORBA::String_var entry = geom->GetStudyEntry();
-      groupData._groupEntry = entry.in();
+      geomRefSO->ReferencedObject( groupSO.inout() );
     }
   }
   else
   {
     // get geom group
-    SALOMEDS::SObject_wrap groupSO = SMESH_Gen_i::getStudyServant()->FindObjectID( groupData._groupEntry.c_str() );
-    if ( !groupSO->_is_nil() )
+    groupSO = _gen_i->getStudyServant()->FindObjectID( groupData._groupEntry.c_str() );
+  }
+
+  if ( groupSO->_is_nil() )
+    return newShape;
+
+  CORBA::Object_var      groupObj = _gen_i->SObjectToObject( groupSO );
+  GEOM::GEOM_Object_var geomGroup = GEOM::GEOM_Object::_narrow( groupObj );
+  if ( geomGroup->_is_nil() )
+    return newShape;
+
+  // get indices of group items
+  set<int> curIndices;
+  GEOM::GEOM_Gen_var               geomGen = _gen_i->GetGeomEngine( geomGroup );
+  GEOM::GEOM_IGroupOperations_wrap groupOp = geomGen->GetIGroupOperations();
+  GEOM::ListOfLong_var                 ids = groupOp->GetObjects( geomGroup );
+  for ( CORBA::ULong i = 0; i < ids->length(); ++i )
+    curIndices.insert( ids[i] );
+
+  bool sameIndices = ( groupData._indices == curIndices );
+  if ( how == ONLY_IF_CHANGED && sameIndices )
+    return newShape; // group not changed
+
+  // update data
+  CORBA::String_var entry = geomGroup->GetStudyEntry();
+  groupData._groupEntry = entry.in();
+  groupData._indices = curIndices;
+
+  newShape = _gen_i->GeomObjectToShape( geomGroup );
+
+  // check if newShape is up-to-date
+  if ( !newShape.IsNull() && ids->length() > 0 )
+  {
+    bool toUpdate = ! _impl->GetMeshDS()->IsGroupOfSubShapes( newShape );
+    if ( !toUpdate )
     {
-      CORBA::Object_var groupObj = _gen_i->SObjectToObject( groupSO );
-      if ( CORBA::is_nil( groupObj )) return newShape;
-      GEOM::GEOM_Object_var geomGroup = GEOM::GEOM_Object::_narrow( groupObj );
-
-      // get indices of group items
-      set<int> curIndices;
-      GEOM::GEOM_Gen_var              geomGen = _gen_i->GetGeomEngine( geomGroup );
-      GEOM::GEOM_IGroupOperations_ptr groupOp = geomGen->GetIGroupOperations();
-      GEOM::ListOfLong_var                ids = groupOp->GetObjects( geomGroup );
-      for ( CORBA::ULong i = 0; i < ids->length(); ++i )
-        curIndices.insert( ids[i] );
-
-      if ( how == ONLY_IF_CHANGED && groupData._indices == curIndices )
-        return newShape; // group not changed
-
-      // update data
-      groupData._indices = curIndices;
-
-      GEOM_Client* geomClient = _gen_i->GetShapeReader();
-      if ( !geomClient ) return newShape;
+      TopExp_Explorer exp( newShape, (TopAbs_ShapeEnum)( groupOp->GetType( geomGroup )));
+      for ( ; exp.More() && !toUpdate; exp.Next() )
+      {
+        int ind = _impl->GetMeshDS()->ShapeToIndex( exp.Current() );
+        toUpdate = ( curIndices.erase( ind ) == 0 );
+      }
+      if ( !curIndices.empty() )
+        toUpdate = true;
+    }
+    if ( toUpdate )
+    {
+      GEOM_Client*    geomClient = _gen_i->GetShapeReader();
       CORBA::String_var groupIOR = geomGen->GetStringFromIOR( geomGroup );
       geomClient->RemoveShapeFromBuffer( groupIOR.in() );
       newShape = _gen_i->GeomObjectToShape( geomGroup );
     }
   }
-  if ( newShape.IsNull() ) {
+  else
+  {
     // geom group becomes empty - return empty compound
     TopoDS_Compound compound;
     BRep_Builder().MakeCompound(compound);
     newShape = compound;
   }
+
   return newShape;
 }
 
@@ -2295,9 +2328,18 @@ void SMESH_Mesh_i::CheckGeomModif( bool isBreakLink )
   if ( !geomClient ) return;
   GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine( mainGO );
   if ( geomGen->_is_nil() ) return;
+  CORBA::String_var geomComponentType = geomGen->ComponentDataType();
+  bool isShaper = ( strcmp( geomComponentType.in(), "SHAPERSTUDY" ) == 0 );
 
-  CORBA::String_var ior = geomGen->GetStringFromIOR( mainGO );
-  geomClient->RemoveShapeFromBuffer( ior.in() );
+  SMESHDS_Mesh * meshDS = _impl->GetMeshDS();
+
+  TopoDS_Shape newShape = _gen_i->GeomObjectToShape( mainGO );
+  if ( meshDS->ShapeToIndex( newShape ) == 1 ) // not yet updated
+  {
+    CORBA::String_var ior = geomGen->GetStringFromIOR( mainGO );
+    geomClient->RemoveShapeFromBuffer( ior.in() );
+    newShape = _gen_i->GeomObjectToShape( mainGO );
+  }
 
   // Update data taking into account that if topology doesn't change
   // all sub-shapes change but IDs of sub-shapes remain (except for geom groups)
@@ -2305,18 +2347,14 @@ void SMESH_Mesh_i::CheckGeomModif( bool isBreakLink )
   if ( _preMeshInfo )
     _preMeshInfo->ForgetAllData();
 
-  
-  if (isBreakLink)
+  if ( isBreakLink || !isShaper )
     _impl->Clear();
-  TopoDS_Shape newShape = _gen_i->GeomObjectToShape( mainGO );
   if ( newShape.IsNull() )
     return;
 
   _mainShapeTick = mainGO->GetTick();
 
-  SMESHDS_Mesh * meshDS = _impl->GetMeshDS();
-
-  // store data of groups on geometry
+  // store data of groups on geometry including new TopoDS_Shape's
   std::vector< TGroupOnGeomData > groupsData;
   const std::set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
   groupsData.reserve( groups.size() );
@@ -2337,7 +2375,10 @@ void SMESH_Mesh_i::CheckGeomModif( bool isBreakLink )
       GEOM::GEOM_Object_var geom;
       if ( !gog->_is_nil() )
       {
-        if ( isBreakLink )
+        if ( !isBreakLink )
+          geom = gog->GetShape();
+
+        if ( isBreakLink || geom->_is_nil() )
         {
           SALOMEDS::SObject_wrap grpSO = _gen_i->ObjectToSObject( gog );
           SALOMEDS::SObject_wrap geomRefSO, geomSO;
@@ -2349,22 +2390,23 @@ void SMESH_Mesh_i::CheckGeomModif( bool isBreakLink )
             geom = GEOM::GEOM_Object::_narrow( geomObj );
           }
         }
-        else
-        {
-          geom = gog->GetShape();
-        }
       }
-      if ( !geom->_is_nil() )
+      if ( old2newShapeMap.IsBound( group->GetShape() ))
       {
-        CORBA::String_var ior = geomGen->GetStringFromIOR( geom );
-        geomClient->RemoveShapeFromBuffer( ior.in() );
-        groupsData.back()._shape = _gen_i->GeomObjectToShape( geom );
-        old2newShapeMap.Bind( group->GetShape(), groupsData.back()._shape );
+        groupsData.back()._shape = old2newShapeMap( group->GetShape() );
       }
-      else if ( old2newShapeMap.IsBound( group->GetShape() ))
+      else if ( !geom->_is_nil() )
       {
-        groupsData.back()._shape = old2newShapeMap( group->GetShape() );
+        groupsData.back()._shape = _gen_i->GeomObjectToShape( geom );
+        if ( meshDS->IsGroupOfSubShapes( groupsData.back()._shape ))
+        {
+          CORBA::String_var ior = geomGen->GetStringFromIOR( geom );
+          geomClient->RemoveShapeFromBuffer( ior.in() );
+          groupsData.back()._shape = _gen_i->GeomObjectToShape( geom );
+        }
+        old2newShapeMap.Bind( group->GetShape(), groupsData.back()._shape );
       }
+      
     }
   }
   // store assigned hypotheses
@@ -2377,7 +2419,7 @@ void SMESH_Mesh_i::CheckGeomModif( bool isBreakLink )
     ids2Hyps.push_back( make_pair( meshDS->ShapeToIndex( s ), hyps ));
   }
 
-  std::map< std::set<int>, int > ii2iMap; // group sub-ids to group id in SMESHDS
+  std::multimap< std::set<int>, int > ii2iMap; // group sub-ids to group id in SMESHDS
 
   // count shapes excluding compounds corresponding to geom groups
   int oldNbSubShapes = meshDS->MaxShapeIndex();
@@ -2411,19 +2453,43 @@ void SMESH_Mesh_i::CheckGeomModif( bool isBreakLink )
   }
 
   // re-add shapes (compounds) of geom groups
+  typedef std::map< std::vector< int >, TGeomGroupData* > TIndices2GroupData;
+  TIndices2GroupData ii2grData;
+  std::vector< int > ii;
   std::map< int, int > old2newIDs; // group IDs
-  std::list<TGeomGroupData>::iterator data = _geomGroupData.begin();
-  for ( ; data != _geomGroupData.end(); ++data )
+  std::list<TGeomGroupData>::iterator dataIt = _geomGroupData.begin();
+  for ( ; dataIt != _geomGroupData.end(); ++dataIt )
   {
+    TGeomGroupData* data = &(*dataIt);
+    ii.reserve( data->_indices.size() );
+    ii.assign( data->_indices.begin(), data->_indices.end() );
+    TIndices2GroupData::iterator ii2gd = ii2grData.insert( std::make_pair( ii, data )).first;
+    if ( ii2gd->second != data )
+    {
+      data->_groupEntry = ii2gd->second->_groupEntry;
+      data->_indices    = ii2gd->second->_indices;
+      continue;
+    }
+    const int  oldNbSub = data->_indices.size();
+    const int soleOldID = oldNbSub == 1 ? *data->_indices.begin() : 0;
     int oldID = 0;
-    std::map< std::set<int>, int >::iterator ii2i = ii2iMap.find( data->_indices );
+    std::multimap< std::set<int>, int >::iterator ii2i = ii2iMap.find( data->_indices );
     if ( ii2i != ii2iMap.end() )
+    {
       oldID = ii2i->second;
+      ii2iMap.erase( ii2i );
+    }
+    if ( !oldID && oldNbSub == 1 )
+      oldID = soleOldID;
+    if ( old2newIDs.count( oldID ))
+      continue;
+
+    int how = ( isBreakLink || !sameTopology ) ? IS_BREAK_LINK : MAIN_TRANSFORMED;
+    newShape = newGroupShape( *data, how );
 
-    TopoDS_Shape newShape = newGroupShape( *data, isBreakLink ? IS_BREAK_LINK : MAIN_TRANSFORMED );
     if ( !newShape.IsNull() )
     {
-      if ( meshDS->ShapeToIndex( newShape ) > 0 ) // a group reduced to one sub-shape
+      if ( oldNbSub > 1 && meshDS->ShapeToIndex( newShape ) > 0 ) // group reduced to one sub-shape
       {
         TopoDS_Compound compound;
         BRep_Builder().MakeCompound( compound );
@@ -2431,33 +2497,31 @@ void SMESH_Mesh_i::CheckGeomModif( bool isBreakLink )
         newShape = compound;
       }
       int newID = _impl->GetSubMesh( newShape )->GetId();
-      if ( oldID && oldID != newID )
+      if ( oldID /*&& oldID != newID*/ )
         old2newIDs.insert( std::make_pair( oldID, newID ));
+      if ( oldNbSub == 1 )
+        old2newIDs.insert( std::make_pair( soleOldID, newID ));
     }
   }
 
   // re-assign hypotheses
   for ( size_t i = 0; i < ids2Hyps.size(); ++i )
   {
-    if ( !sameTopology && ids2Hyps[i].first != 1 )
-      continue; // assign only global hypos
     int sID = ids2Hyps[i].first;
     std::map< int, int >::iterator o2n = old2newIDs.find( sID );
     if ( o2n != old2newIDs.end() )
       sID = o2n->second;
+    else if ( !sameTopology && sID != 1 )
+      continue;
     const TopoDS_Shape& s = meshDS->IndexToShape( sID );
-    const THypList&  hyps = ids2Hyps[i].second;
+    if ( s.IsNull() )
+      continue;
+    const THypList& hyps = ids2Hyps[i].second;
     THypList::const_iterator h = hyps.begin();
     for ( ; h != hyps.end(); ++h )
       _impl->AddHypothesis( s, (*h)->GetID() );
   }
 
-  if ( !sameTopology )
-  {
-    // remove invalid study sub-objects
-    CheckGeomGroupModif();
-  }
-  else
   {
     // restore groups on geometry
     for ( size_t i = 0; i < groupsData.size(); ++i )
@@ -2479,23 +2543,26 @@ void SMESH_Mesh_i::CheckGeomModif( bool isBreakLink )
         g->GetGroupDS()->SetColor( data._color );
     }
 
-    std::map< int, int >::iterator o2n = old2newIDs.begin();
-    for ( ; o2n != old2newIDs.end(); ++o2n )
+    if ( !sameTopology )
     {
-      int newID = o2n->second, oldID = o2n->first;
-      if ( !_mapSubMesh.count( oldID ))
-        continue;
-      if ( newID > 0 )
+      std::map< int, int >::iterator o2n = old2newIDs.begin();
+      for ( ; o2n != old2newIDs.end(); ++o2n )
       {
-        _mapSubMesh   [ newID ] = _impl->GetSubMeshContaining( newID );
-        _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
-        _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
+        int newID = o2n->second, oldID = o2n->first;
+        if ( newID == oldID || !_mapSubMesh.count( oldID ))
+          continue;
+        if ( newID > 0 )
+        {
+          _mapSubMesh   [ newID ] = _impl->GetSubMeshContaining( newID );
+          _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
+          _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
+        }
+        _mapSubMesh.   erase(oldID);
+        _mapSubMesh_i. erase(oldID);
+        _mapSubMeshIor.erase(oldID);
+        if ( newID > 0 )
+          _mapSubMesh_i [ newID ]->changeLocalId( newID );
       }
-      _mapSubMesh.   erase(oldID);
-      _mapSubMesh_i. erase(oldID);
-      _mapSubMeshIor.erase(oldID);
-      if ( newID > 0 )
-        _mapSubMesh_i [ newID ]->changeLocalId( newID );
     }
 
     // update _mapSubMesh
@@ -2504,9 +2571,15 @@ void SMESH_Mesh_i::CheckGeomModif( bool isBreakLink )
       i_sm->second = _impl->GetSubMesh( meshDS->IndexToShape( i_sm->first ));
   }
 
+  if ( !sameTopology )
+  {
+    // remove invalid study sub-objects
+    CheckGeomGroupModif();
+  }
+
   _gen_i->UpdateIcons( me );
 
-  if ( !isBreakLink )
+  if ( !isBreakLink && isShaper )
   {
     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( me );
     if ( !meshSO->_is_nil() )
@@ -2582,13 +2655,21 @@ void SMESH_Mesh_i::CheckGeomGroupModif()
   {
     SMESH::SMESH_GroupBase_ptr group = i_gr->second;
     ++i_gr;
-    SALOMEDS::SObject_wrap        groupSO = _gen_i->ObjectToSObject( group ), refSO;
+    SALOMEDS::SObject_wrap        groupSO = _gen_i->ObjectToSObject( group ), refSO, geomSO;
     SMESH::SMESH_GroupOnGeom_var   onGeom = SMESH::SMESH_GroupOnGeom::_narrow  ( group );
     SMESH::SMESH_GroupOnFilter_var onFilt = SMESH::SMESH_GroupOnFilter::_narrow( group );
     bool isValidGeom = false;
     if ( !onGeom->_is_nil() )
     {
-      isValidGeom = ( ! GEOM::GEOM_Object_var( onGeom->GetShape() )->_is_nil() );
+      isValidGeom = ( ! GEOM::GEOM_Object_var( onGeom->GetShape() )->_is_nil() ); // check TopoDS
+      if ( !isValidGeom ) // check reference
+      {
+        isValidGeom = ( ! groupSO->_is_nil() &&
+                        groupSO->FindSubObject( SMESH::Tag_RefOnShape, refSO.inout() ) &&
+                        refSO->ReferencedObject( geomSO.inout() ) &&
+                        ! geomSO->_is_nil() &&
+                        !CORBA::is_nil( CORBA::Object_var( geomSO->GetObject() )));
+      }
     }
     else if ( !onFilt->_is_nil() )
     {