Salome HOME
Mesh module improvement related to selection of geometrical objects in mesh group...
[modules/smesh.git] / src / SMESH_I / SMESH_Gen_i.cxx
index e75216c213501089aec3592be90112e9f141d4bd..4eac9e963ce19db97284ce3ed1913664dd904437 100644 (file)
@@ -17,7 +17,7 @@
 //  License along with this library; if not, write to the Free Software 
 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
 // 
-//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 //
 //
@@ -74,6 +74,8 @@
 
 #include "SMDS_EdgePosition.hxx"
 #include "SMDS_FacePosition.hxx"
+#include "SMDS_VertexPosition.hxx"
+#include "SMDS_SpacePosition.hxx"
 
 #include CORBA_SERVER_HEADER(SMESH_Group)
 #include CORBA_SERVER_HEADER(SMESH_Filter)
@@ -248,7 +250,8 @@ SMESH_Gen_i::SMESH_Gen_i( CORBA::ORB_ptr            orb,
   myShapeReader = NULL;  // shape reader
   mySMESHGen = this;
 
-  OSD::SetSignal( true );
+  // set it in standalone mode only
+  //OSD::SetSignal( true );
 }
 
 //=============================================================================
@@ -421,6 +424,25 @@ GEOM_Client* SMESH_Gen_i::GetShapeReader()
 void SMESH_Gen_i::SetEmbeddedMode( CORBA::Boolean theMode )
 {
   myIsEmbeddedMode = theMode;
+
+  if ( !myIsEmbeddedMode ) {
+    //PAL10867: disable signals catching with "noexcepthandler" option
+    char* envNoCatchSignals = getenv("NOT_INTERCEPT_SIGNALS");
+    if (!envNoCatchSignals || !atoi(envNoCatchSignals))
+    {
+      bool raiseFPE;
+#ifdef _DEBUG_
+      raiseFPE = true;
+      char* envDisableFPE = getenv("DISABLE_FPE");
+      if (envDisableFPE && atoi(envDisableFPE))
+        raiseFPE = false;
+#else
+      raiseFPE = false;
+#endif
+      OSD::SetSignal( raiseFPE );
+    }
+    // else OSD::SetSignal() is called in GUI
+  }
 }
 
 //=============================================================================
@@ -456,13 +478,16 @@ void SMESH_Gen_i::SetCurrentStudy( SALOMEDS::Study_ptr theStudy )
     myStudyContextMap[ studyId ] = new StudyContext;      
   }
 
-  SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder(); 
-  if( !myCurrentStudy->FindComponent( "GEOM" )->_is_nil() )
-    aStudyBuilder->LoadWith( myCurrentStudy->FindComponent( "GEOM" ), GetGeomEngine() );
+  // myCurrentStudy may be nil
+  if ( !CORBA::is_nil( myCurrentStudy ) ) {
+    SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder(); 
+    if( !myCurrentStudy->FindComponent( "GEOM" )->_is_nil() )
+      aStudyBuilder->LoadWith( myCurrentStudy->FindComponent( "GEOM" ), GetGeomEngine() );
 
   // set current study for geom engine
   //if ( !CORBA::is_nil( GetGeomEngine() ) )
   //  GetGeomEngine()->GetCurrentStudy( myCurrentStudy->StudyId() );
+  }
 }
 
 //=============================================================================
@@ -637,6 +662,37 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateMesh( GEOM::GEOM_Object_ptr theShapeObj
   return mesh._retn();
 }
 
+//=============================================================================
+/*!
+ *  SMESH_Gen_i::CreateEmptyMesh
+ *
+ *  Create empty mesh
+ */
+//=============================================================================
+
+SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateEmptyMesh()
+     throw ( SALOME::SALOME_Exception )
+{
+  Unexpect aCatch(SALOME_SalomeException);
+  if(MYDEBUG) MESSAGE( "SMESH_Gen_i::CreateMesh" );
+  // create mesh
+  SMESH::SMESH_Mesh_var mesh = this->createMesh();
+
+  // publish mesh in the study
+  if ( CanPublishInStudy( mesh ) ) {
+    SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder();
+    aStudyBuilder->NewCommand();  // There is a transaction
+    SALOMEDS::SObject_var aSO = PublishMesh( myCurrentStudy, mesh.in() );
+    aStudyBuilder->CommitCommand();
+    if ( !aSO->_is_nil() ) {
+      // Update Python script
+      TPythonDump() << aSO << " = " << this << ".CreateEmptyMesh()";
+    }
+  }
+
+  return mesh._retn();
+}
+
 //=============================================================================
 /*!
  *  SMESH_Gen_i::CreateMeshFromUNV
@@ -668,6 +724,10 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateMeshesFromUNV( const char* theFileName
   SMESH_Mesh_i* aServant = dynamic_cast<SMESH_Mesh_i*>( GetServant( aMesh ).in() );
   ASSERT( aServant );
   aServant->ImportUNVFile( theFileName );
+
+  // Dump creation of groups
+  aServant->GetGroups();
+
   return aMesh._retn();
 }
 
@@ -686,11 +746,6 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMED( const char* theFileName,
   Unexpect aCatch(SALOME_SalomeException);
   if(MYDEBUG) MESSAGE( "SMESH_Gen_i::CreateMeshFromMED" );
 
-  // Python Dump
-  TPythonDump aPythonDump;
-  aPythonDump << "([";
-  //TCollection_AsciiString aStr ("([");
-
   // Retrieve mesh names from the file
   DriverMED_R_SMESHDS_Mesh myReader;
   myReader.SetFile( theFileName );
@@ -699,6 +754,14 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMED( const char* theFileName,
   list<string> aNames = myReader.GetMeshNames(aStatus);
   SMESH::mesh_array_var aResult = new SMESH::mesh_array();
   theStatus = (SMESH::DriverMED_ReadStatus)aStatus;
+
+  { // open a new scope to make aPythonDump die before PythonDump in SMESH_Mesh::GetGroups()
+
+  // Python Dump
+  TPythonDump aPythonDump;
+  aPythonDump << "([";
+  //TCollection_AsciiString aStr ("([");
+
   if (theStatus == SMESH::DRS_OK) {
     SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder();
     aStudyBuilder->NewCommand();  // There is a transaction
@@ -744,6 +807,10 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMED( const char* theFileName,
 
   // Update Python script
   aPythonDump << "], status) = " << this << ".CreateMeshesFromMED('" << theFileName << "')";
+  }
+  // Dump creation of groups
+  for ( int i = 0; i < aResult->length(); ++i )
+    aResult[ i ]->GetGroups();
 
   return aResult._retn();
 }
@@ -1033,6 +1100,10 @@ CORBA::Boolean SMESH_Gen_i::Compute( SMESH::SMESH_Mesh_ptr theMesh,
       return myGen.Compute( myLocMesh, myLocShape);
     }
   }
+  catch ( std::bad_alloc& exc ) {
+    THROW_SALOME_CORBA_EXCEPTION( "Memory allocation problem",
+                                  SALOME::INTERNAL_ERROR );
+  }
   catch ( SALOME_Exception& S_ex ) {
     INFOS( "Compute(): catch exception "<< S_ex.what() );
   }
@@ -1059,6 +1130,41 @@ SMESH_Gen_i::GetGeometryByMeshElement( SMESH::SMESH_Mesh_ptr  theMesh,
   throw ( SALOME::SALOME_Exception )
 {
   Unexpect aCatch(SALOME_SalomeException);
+  GEOM::GEOM_Object_var geom = FindGeometryByMeshElement(theMesh, theElementID);
+  if ( !geom->_is_nil() ) {
+    GEOM::GEOM_Object_var mainShape = theMesh->GetShapeToMesh();
+    GEOM::GEOM_Gen_var    geomGen   = GetGeomEngine();
+
+    // try to find the corresponding SObject
+    GeomObjectToShape( geom ); // geom client remembers the found shape
+    SALOMEDS::SObject_var SObj = ObjectToSObject( myCurrentStudy, geom.in() );
+    if ( SObj->_is_nil() )
+      // publish a new subshape
+      SObj = geomGen->AddInStudy( myCurrentStudy, geom, theGeomName, mainShape );
+    // return only published geometry
+    if ( !SObj->_is_nil() )
+      return geom._retn();
+  }
+  return GEOM::GEOM_Object::_nil();
+}
+
+
+//================================================================================
+/*!
+ * \brief Return geometrical object the given element is built on.
+ *  \param theMesh - the mesh the element is in
+ *  \param theElementID - the element ID
+ *  \retval GEOM::GEOM_Object_ptr - the found geom object
+ */
+//================================================================================
+
+GEOM::GEOM_Object_ptr
+SMESH_Gen_i::FindGeometryByMeshElement( SMESH::SMESH_Mesh_ptr  theMesh,
+                                   CORBA::Long            theElementID)
+  throw ( SALOME::SALOME_Exception )
+{
+  Unexpect aCatch(SALOME_SalomeException);
   if ( CORBA::is_nil( theMesh ) )
     THROW_SALOME_CORBA_EXCEPTION( "bad Mesh reference", SALOME::BAD_PARAM );
 
@@ -1083,17 +1189,8 @@ SMESH_Gen_i::GetGeometryByMeshElement( SMESH::SMESH_Mesh_ptr  theMesh,
           if ( !op->_is_nil() )
             geom = op->GetSubShape( mainShape, shapeID );
         }
-        if ( !geom->_is_nil() ) {
-          // try to find the corresponding SObject
-          GeomObjectToShape( geom ); // geom client remembers the found shape
-          SALOMEDS::SObject_var SObj = ObjectToSObject( myCurrentStudy, geom.in() );
-          if ( SObj->_is_nil() )
-            // publish a new subshape
-            SObj = geomGen->AddInStudy( myCurrentStudy, geom, theGeomName, mainShape );
-          // return only published geometry
-          if ( !SObj->_is_nil() )
-            return geom._retn();
-        }
+        if ( !geom->_is_nil() )
+         return geom._retn();
       }
   }
   return GEOM::GEOM_Object::_nil();
@@ -1592,8 +1689,9 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
              }
            }
             // All sub-meshes will be stored in MED file
-            if ( shapeRefFound )
-              myWriter.AddAllSubMeshes();
+            // .. will NOT (PAL 12992)
+            //if ( shapeRefFound )
+            //myWriter.AddAllSubMeshes();
 
            // groups root sub-branch
            SALOMEDS::SObject_var myGroupsBranch;
@@ -1695,10 +1793,79 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
                 myLocMesh.ShapeToMesh( nullShape ); // remove shape referring data
               }
 
-              // Store node positions on sub-shapes (SMDS_Position):
-
               if ( !mySMESHDSMesh->SubMeshes().empty() )
               {
+                // Store submeshes
+                // ----------------
+                aGroup = new HDFgroup( "Submeshes", aTopGroup );
+                aGroup->CreateOnDisk();
+
+                // each element belongs to one or none submesh,
+                // so for each node/element, we store a submesh ID
+
+                // Make maps of submesh IDs of elements sorted by element IDs
+                typedef int TElemID;
+                typedef int TSubMID;
+                map< TElemID, TSubMID > eId2smId, nId2smId;
+                map< TElemID, TSubMID >::iterator hint; // insertion to map is done before hint
+                const map<int,SMESHDS_SubMesh*>& aSubMeshes = mySMESHDSMesh->SubMeshes();
+                map<int,SMESHDS_SubMesh*>::const_iterator itSubM ( aSubMeshes.begin() );
+                SMDS_NodeIteratorPtr itNode;
+                SMDS_ElemIteratorPtr itElem;
+                for ( itSubM = aSubMeshes.begin(); itSubM != aSubMeshes.end() ; itSubM++ )
+                {
+                  TSubMID          aSubMeID = itSubM->first;
+                  SMESHDS_SubMesh* aSubMesh = itSubM->second;
+                  if ( aSubMesh->IsComplexSubmesh() )
+                    continue; // submesh containing other submeshs
+                  // nodes
+                  hint = nId2smId.begin(); // optimize insertion basing on increasing order of elem Ids in submesh
+                  for ( itNode = aSubMesh->GetNodes(); itNode->more(); ++hint)
+                    hint = nId2smId.insert( hint, make_pair( itNode->next()->GetID(), aSubMeID ));
+                  // elements
+                  hint = eId2smId.begin();
+                  for ( itElem = aSubMesh->GetElements(); itElem->more(); ++hint)
+                    hint = eId2smId.insert( hint, make_pair( itElem->next()->GetID(), aSubMeID ));
+                }
+
+                // Care of elements that are not on submeshes
+                if ( mySMESHDSMesh->NbNodes() != nId2smId.size() ) {
+                  for ( itNode = mySMESHDSMesh->nodesIterator(); itNode->more(); )
+                    /*  --- stl_map.h says : */
+                    /*  A %map relies on unique keys and thus a %pair is only inserted if its */
+                    /*  first element (the key) is not already present in the %map.           */
+                    nId2smId.insert( make_pair( itNode->next()->GetID(), 0 ));
+                }
+                int nbElems = mySMESHDSMesh->NbEdges() + mySMESHDSMesh->NbFaces() + mySMESHDSMesh->NbVolumes();
+                if ( nbElems != eId2smId.size() ) {
+                  for ( itElem = mySMESHDSMesh->elementsIterator(); itElem->more(); )
+                    eId2smId.insert( make_pair( itElem->next()->GetID(), 0 ));
+                }
+
+                // Store submesh IDs
+                for ( int isNode = 0; isNode < 2; ++isNode )
+                {
+                  map< TElemID, TSubMID >& id2smId = isNode ? nId2smId : eId2smId;
+                  if ( id2smId.empty() ) continue;
+                  map< TElemID, TSubMID >::const_iterator id_smId = id2smId.begin();
+                  // make and fill array of submesh IDs
+                  int* smIDs = new int [ id2smId.size() ];
+                  for ( int i = 0; id_smId != id2smId.end(); ++id_smId, ++i )
+                    smIDs[ i ] = id_smId->second;
+                  // write HDF group
+                  aSize[ 0 ] = id2smId.size();
+                  string aDSName( isNode ? "Node Submeshes" : "Element Submeshes");
+                  aDataset = new HDFdataset( (char*)aDSName.c_str(), aGroup, HDF_INT32, aSize, 1 );
+                  aDataset->CreateOnDisk();
+                  aDataset->WriteOnDisk( smIDs );
+                  aDataset->CloseOnDisk();
+                  //
+                  delete smIDs;
+                }
+                
+                // Store node positions on sub-shapes (SMDS_Position):
+                // ----------------------------------------------------
+
                 aGroup = new HDFgroup( "Node Positions", aTopGroup );
                 aGroup->CreateOnDisk();
 
@@ -1714,9 +1881,7 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
                 int nbEdgeNodes = 0, nbFaceNodes = 0;
                 list<SMESHDS_SubMesh*> aEdgeSM, aFaceSM;
                 // loop on SMESHDS_SubMesh'es
-                const map<int,SMESHDS_SubMesh*>& aSubMeshes = mySMESHDSMesh->SubMeshes();
-                map<int,SMESHDS_SubMesh*>::const_iterator itSubM ( aSubMeshes.begin() );
-                for ( ; itSubM != aSubMeshes.end() ; itSubM++ )
+                for ( itSubM = aSubMeshes.begin(); itSubM != aSubMeshes.end() ; itSubM++ )
                 {
                   SMESHDS_SubMesh* aSubMesh = (*itSubM).second;
                   if ( aSubMesh->IsComplexSubmesh() )
@@ -1757,8 +1922,6 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
                   for ( ; itSM != pListSM->end(); itSM++ )
                   {
                     SMESHDS_SubMesh* aSubMesh = (*itSM);
-                    if ( aSubMesh->IsComplexSubmesh() )
-                      continue; // submesh containing other submeshs
 
                     SMDS_NodeIteratorPtr itNode = aSubMesh->GetNodes();
                     // loop on nodes in aSubMesh
@@ -1890,6 +2053,31 @@ void SMESH_Gen_i::loadGeomData( SALOMEDS::SComponent_ptr theCompRoot )
   SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder(); 
   aStudyBuilder->LoadWith( theCompRoot, GetGeomEngine() );
 }
+//=============================================================================
+/*!
+ * \brief Creates SMDS_Position according to shape type
+ */
+//=============================================================================
+
+class PositionCreator {
+public:
+  SMDS_PositionPtr MakePosition(const TopAbs_ShapeEnum type) {
+    return (this->*myFuncTable[ type ])();
+  }
+  PositionCreator() {
+    myFuncTable.resize( (size_t) TopAbs_SHAPE, & PositionCreator::defaultPosition );
+    myFuncTable[ TopAbs_FACE ] = & PositionCreator::facePosition;
+    myFuncTable[ TopAbs_EDGE ] = & PositionCreator::edgePosition;
+    myFuncTable[ TopAbs_VERTEX ] = & PositionCreator::vertexPosition;
+  }
+private:
+  SMDS_PositionPtr edgePosition()    const { return SMDS_PositionPtr( new SMDS_EdgePosition  ); }
+  SMDS_PositionPtr facePosition()    const { return SMDS_PositionPtr( new SMDS_FacePosition  ); }
+  SMDS_PositionPtr vertexPosition()  const { return SMDS_PositionPtr( new SMDS_VertexPosition); }
+  SMDS_PositionPtr defaultPosition() const { return SMDS_SpacePosition::originSpacePosition();  }
+  typedef SMDS_PositionPtr (PositionCreator:: * FmakePos)() const;
+  vector<FmakePos> myFuncTable;
+};
 
 //=============================================================================
 /*!
@@ -2477,10 +2665,80 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
          }
 
          if(hasData) {
+            
            // Read sub-meshes from MED
+            // -------------------------
            if(MYDEBUG) MESSAGE("Create all sub-meshes");
-           myReader.CreateAllSubMeshes();
+            bool submeshesInFamilies = ( ! aTopGroup->ExistInternalObject( "Submeshes" ));
+            if ( submeshesInFamilies )
+            {
+              // old way working before fix of PAL 12992
+              myReader.CreateAllSubMeshes();
+            }
+            else
+            {
+              // open a group
+              aGroup = new HDFgroup( "Submeshes", aTopGroup ); 
+              aGroup->OpenOnDisk();
 
+              int maxID = mySMESHDSMesh->MaxShapeIndex();
+              vector< SMESHDS_SubMesh * > subMeshes( maxID + 1, (SMESHDS_SubMesh*) 0 );
+              vector< TopAbs_ShapeEnum  > smType   ( maxID + 1, TopAbs_SHAPE ); 
+              
+              PositionCreator aPositionCreator;
+
+              SMDS_NodeIteratorPtr nIt = mySMESHDSMesh->nodesIterator();
+              SMDS_ElemIteratorPtr eIt = mySMESHDSMesh->elementsIterator();
+              for ( int isNode = 0; isNode < 2; ++isNode )
+              {
+                string aDSName( isNode ? "Node Submeshes" : "Element Submeshes");
+                if ( aGroup->ExistInternalObject( (char*) aDSName.c_str() ))
+                {
+                  aDataset = new HDFdataset( (char*) aDSName.c_str(), aGroup );
+                  aDataset->OpenOnDisk();
+                  // read submesh IDs for all elements sorted by ID
+                  int nbElems = aDataset->GetSize();
+                  int* smIDs = new int [ nbElems ];
+                  aDataset->ReadFromDisk( smIDs );
+                 aDataset->CloseOnDisk();
+
+                  // get elements sorted by ID
+                  ::SMESH_MeshEditor::TIDSortedElemSet elemSet;
+                  if ( isNode )
+                    while ( nIt->more() ) elemSet.insert( nIt->next() );
+                  else
+                    while ( eIt->more() ) elemSet.insert( eIt->next() );
+                  ASSERT( elemSet.size() == nbElems );
+
+                  // add elements to submeshes
+                  ::SMESH_MeshEditor::TIDSortedElemSet::iterator iE = elemSet.begin();
+                  for ( int i = 0; i < nbElems; ++i, ++iE )
+                  {
+                    int smID = smIDs[ i ];
+                    if ( smID == 0 ) continue;
+                    ASSERT( smID <= maxID );
+                    const SMDS_MeshElement* elem = *iE;
+                    // get or create submesh
+                    SMESHDS_SubMesh* & sm = subMeshes[ smID ];
+                    if ( ! sm ) {
+                      sm = mySMESHDSMesh->NewSubMesh( smID );
+                      smType[ smID ] = mySMESHDSMesh->IndexToShape( smID ).ShapeType();
+                    }
+                    // add
+                    if ( isNode ) {
+                      SMDS_PositionPtr pos = aPositionCreator.MakePosition( smType[ smID ]);
+                      pos->SetShapeId( smID );
+                      SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( static_cast<const SMDS_MeshNode*>( elem ));
+                      node->SetPosition( pos );
+                      sm->AddNode( node );
+                    } else {
+                      sm->AddElement( elem );
+                    }
+                  }
+                  delete smIDs;
+                }
+              }
+            } // end reading submeshes
 
             // Read node positions on sub-shapes (SMDS_Position)
 
@@ -2549,6 +2807,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
                     nbFids = aSize;
                   }
                 }
+                aDataset->CloseOnDisk();
               } // loop on 5 datasets
 
               // Set node positions on edges or faces