// SMESH DriverMED : driver to read and write 'med' files // // Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // 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 // // // // File : DriverMED_W_SMESHDS_Mesh.cxx // Module : SMESH #include #include "DriverMED_W_SMESHDS_Mesh.h" #include "DriverMED_W_SMDS_Mesh.h" #include "DriverMED_Family.h" #include "SMESHDS_Mesh.hxx" #include "SMDS_MeshElement.hxx" #include "SMDS_MeshNode.hxx" #include "SMDS_PolyhedralVolumeOfNodes.hxx" #include "utilities.h" #include "MED_Utilities.hxx" #define _EDF_NODE_IDS_ //#define _ELEMENTS_BY_DIM_ using namespace std; using namespace MED; DriverMED_W_SMESHDS_Mesh::DriverMED_W_SMESHDS_Mesh(): myAllSubMeshes (false), myDoGroupOfNodes (false), myDoGroupOfEdges (false), myDoGroupOfFaces (false), myDoGroupOfVolumes (false) {} void DriverMED_W_SMESHDS_Mesh::SetFile(const std::string& theFileName, MED::EVersion theId) { myMed = CrWrapper(theFileName,theId); Driver_SMESHDS_Mesh::SetFile(theFileName); } void DriverMED_W_SMESHDS_Mesh::SetFile(const std::string& theFileName) { return SetFile(theFileName,MED::eV2_2); } void DriverMED_W_SMESHDS_Mesh::SetMeshName(const std::string& theMeshName) { myMeshName = theMeshName; } void DriverMED_W_SMESHDS_Mesh::AddGroup(SMESHDS_GroupBase* theGroup) { myGroups.push_back(theGroup); } void DriverMED_W_SMESHDS_Mesh::AddAllSubMeshes() { myAllSubMeshes = true; } void DriverMED_W_SMESHDS_Mesh::AddSubMesh(SMESHDS_SubMesh* theSubMesh, int theID) { mySubMeshes[theID] = theSubMesh; } void DriverMED_W_SMESHDS_Mesh::AddGroupOfNodes() { myDoGroupOfNodes = true; } void DriverMED_W_SMESHDS_Mesh::AddGroupOfEdges() { myDoGroupOfEdges = true; } void DriverMED_W_SMESHDS_Mesh::AddGroupOfFaces() { myDoGroupOfFaces = true; } void DriverMED_W_SMESHDS_Mesh::AddGroupOfVolumes() { myDoGroupOfVolumes = true; } namespace{ typedef double (SMDS_MeshNode::* TGetCoord)() const; typedef const char* TName; typedef const char* TUnit; TUnit aUnit[3] = {"m","m","m"}; TGetCoord aXYZGetCoord[3] = { &SMDS_MeshNode::X, &SMDS_MeshNode::Y, &SMDS_MeshNode::Z }; TName aXYZName[3] = {"x","y","z"}; TGetCoord aXYGetCoord[2] = { &SMDS_MeshNode::X, &SMDS_MeshNode::Y }; TName aXYName[2] = {"x","y"}; TGetCoord aYZGetCoord[2] = { &SMDS_MeshNode::Y, &SMDS_MeshNode::Z }; TName aYZName[2] = {"y","z"}; TGetCoord aXZGetCoord[2] = { &SMDS_MeshNode::X, &SMDS_MeshNode::Z }; TName aXZName[2] = {"x","z"}; TGetCoord aXGetCoord[1] = { &SMDS_MeshNode::X }; TName aXName[1] = {"x"}; TGetCoord aYGetCoord[1] = { &SMDS_MeshNode::Y }; TName aYName[1] = {"y"}; TGetCoord aZGetCoord[1] = { &SMDS_MeshNode::Z }; TName aZName[1] = {"z"}; class TCoordHelper{ SMDS_NodeIteratorPtr myNodeIter; const SMDS_MeshNode* myCurrentNode; TGetCoord* myGetCoord; TName* myName; TUnit* myUnit; public: TCoordHelper(const SMDS_NodeIteratorPtr& theNodeIter, TGetCoord* theGetCoord, TName* theName, TUnit* theUnit = aUnit): myNodeIter(theNodeIter), myGetCoord(theGetCoord), myName(theName), myUnit(theUnit) {} virtual ~TCoordHelper(){} bool Next(){ return myNodeIter->more() && (myCurrentNode = myNodeIter->next()); } const SMDS_MeshNode* GetNode(){ return myCurrentNode; } MED::TIntVector::value_type GetID(){ return myCurrentNode->GetID(); } MED::TFloatVector::value_type GetCoord(TInt theCoodId){ return (myCurrentNode->*myGetCoord[theCoodId])(); } MED::TStringVector::value_type GetName(TInt theDimId){ return myName[theDimId]; } MED::TStringVector::value_type GetUnit(TInt theDimId){ return myUnit[theDimId]; } }; typedef boost::shared_ptr TCoordHelperPtr; } Driver_Mesh::Status DriverMED_W_SMESHDS_Mesh::Perform() { Status aResult = DRS_OK; if (myMesh->hasConstructionEdges() || myMesh->hasConstructionFaces()) { INFOS("SMDS_MESH with hasConstructionEdges() or hasConstructionFaces() do not supports!!!"); return DRS_FAIL; } try{ MESSAGE("Perform - myFile : "<nodesIterator(); double aBounds[6]; if(aNodesIter->more()){ const SMDS_MeshNode* aNode = aNodesIter->next(); aBounds[0] = aBounds[1] = aNode->X(); aBounds[2] = aBounds[3] = aNode->Y(); aBounds[4] = aBounds[5] = aNode->Z(); } while(aNodesIter->more()){ const SMDS_MeshNode* aNode = aNodesIter->next(); aBounds[0] = min(aBounds[0],aNode->X()); aBounds[1] = max(aBounds[1],aNode->X()); aBounds[2] = min(aBounds[2],aNode->Y()); aBounds[3] = max(aBounds[3],aNode->Y()); aBounds[4] = min(aBounds[4],aNode->Z()); aBounds[5] = max(aBounds[5],aNode->Z()); } double EPS = 1.0E-7; anIsXDimension = (aBounds[1] - aBounds[0]) + abs(aBounds[1]) + abs(aBounds[0]) > EPS; anIsYDimension = (aBounds[3] - aBounds[2]) + abs(aBounds[3]) + abs(aBounds[2]) > EPS; anIsZDimension = (aBounds[5] - aBounds[4]) + abs(aBounds[5]) + abs(aBounds[4]) > EPS; aMeshDimension = anIsXDimension + anIsYDimension + anIsZDimension; if(!aMeshDimension) aMeshDimension = 3; } SMDS_NodeIteratorPtr aNodesIter = myMesh->nodesIterator(); switch(aMeshDimension){ case 3: aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aXYZGetCoord,aXYZName)); break; case 2: if(anIsXDimension && anIsYDimension) aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aXYGetCoord,aXYName)); if(anIsYDimension && anIsZDimension) aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aYZGetCoord,aYZName)); if(anIsXDimension && anIsZDimension) aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aXZGetCoord,aXZName)); break; case 1: if(anIsXDimension) aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aXGetCoord,aXName)); if(anIsYDimension) aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aYGetCoord,aYName)); if(anIsZDimension) aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aZGetCoord,aZName)); break; } } PMeshInfo aMeshInfo = myMed->CrMeshInfo(aMeshDimension,aMeshName); MESSAGE("Add - aMeshName : "<GetName()); myMed->SetMeshInfo(aMeshInfo); // Storing SMDS groups and sub-meshes //----------------------------------- int myNodesDefaultFamilyId = 0; int myEdgesDefaultFamilyId = 0; int myFacesDefaultFamilyId = 0; int myVolumesDefaultFamilyId = 0; if (myDoGroupOfNodes) myNodesDefaultFamilyId = REST_NODES_FAMILY; if (myDoGroupOfEdges) myEdgesDefaultFamilyId = REST_EDGES_FAMILY; if (myDoGroupOfFaces) myFacesDefaultFamilyId = REST_FACES_FAMILY; if (myDoGroupOfVolumes) myVolumesDefaultFamilyId = REST_VOLUMES_FAMILY; MESSAGE("Perform - aFamilyInfo"); map anElemFamMap; list aFamilies; if (myAllSubMeshes) { aFamilies = DriverMED_Family::MakeFamilies (myMesh->SubMeshes(), myGroups, myDoGroupOfNodes, myDoGroupOfEdges, myDoGroupOfFaces, myDoGroupOfVolumes); } else { aFamilies = DriverMED_Family::MakeFamilies (mySubMeshes, myGroups, myDoGroupOfNodes, myDoGroupOfEdges, myDoGroupOfFaces, myDoGroupOfVolumes); } list::iterator aFamsIter = aFamilies.begin(); for (; aFamsIter != aFamilies.end(); aFamsIter++) { PFamilyInfo aFamilyInfo = (*aFamsIter)->GetFamilyInfo(myMed,aMeshInfo); myMed->SetFamilyInfo(aFamilyInfo); int aFamId = (*aFamsIter)->GetId(); const set& anElems = (*aFamsIter)->GetElements(); set::const_iterator anElemsIter = anElems.begin(); for (; anElemsIter != anElems.end(); anElemsIter++) { anElemFamMap[*anElemsIter] = aFamId; } // delete (*aFamsIter); } // Storing SMDS nodes to the MED file for the MED mesh //---------------------------------------------------- #ifdef _EDF_NODE_IDS_ typedef map TNodeIdMap; TNodeIdMap aNodeIdMap; #endif TInt aNbElems = myMesh->NbNodes(); MED::TIntVector anElemNums(aNbElems); MED::TIntVector aFamilyNums(aNbElems); MED::TFloatVector aCoordinates(aNbElems*aMeshDimension); for(TInt iNode = 0, aStartId = 0; aCoordHelperPtr->Next(); iNode++, aStartId += aMeshDimension){ for(TInt iCoord = 0; iCoord < aMeshDimension; iCoord++){ aCoordinates[aStartId+iCoord] = aCoordHelperPtr->GetCoord(iCoord); } int aNodeID = aCoordHelperPtr->GetID(); anElemNums[iNode] = aNodeID; #ifdef _EDF_NODE_IDS_ aNodeIdMap[aNodeID] = iNode+1; #endif const SMDS_MeshNode* aNode = aCoordHelperPtr->GetNode(); if (anElemFamMap.find(aNode) != anElemFamMap.end()) aFamilyNums[iNode] = anElemFamMap[aNode]; else aFamilyNums[iNode] = myNodesDefaultFamilyId; } MED::TStringVector aCoordNames(aMeshDimension); MED::TStringVector aCoordUnits(aMeshDimension); for(TInt iCoord = 0; iCoord < aMeshDimension; iCoord++){ aCoordNames[iCoord] = aCoordHelperPtr->GetName(iCoord); aCoordUnits[iCoord] = aCoordHelperPtr->GetUnit(iCoord); } const ERepere SMDS_COORDINATE_SYSTEM = eCART; PNodeInfo aNodeInfo = myMed->CrNodeInfo(aMeshInfo, SMDS_COORDINATE_SYSTEM, aCoordinates, aCoordNames, aCoordUnits, aFamilyNums, anElemNums); MESSAGE("Perform - aNodeInfo->GetNbElem() = "<SetNodeInfo(aNodeInfo); // Storing others SMDS elements to the MED file for the MED mesh //-------------------------------------------------------------- EEntiteMaillage SMDS_MED_ENTITY = eMAILLE; const EConnectivite SMDS_MED_CONNECTIVITY = eNOD; // Storing SMDS Edges if(TInt aNbElems = myMesh->NbEdges()){ #ifdef _ELEMENTS_BY_DIM_ SMDS_MED_ENTITY = eARETE; #endif SMDS_EdgeIteratorPtr anIter = myMesh->edgesIterator(); TInt aNbConnectivity = MED::GetNbNodes(eSEG2); MED::TIntVector anElemNums(aNbElems); MED::TIntVector aFamilyNums(aNbElems); MED::TIntVector aConnectivity(aNbElems*aNbConnectivity); for(TInt iElem = 0, iConn = 0; anIter->more(); iElem++, iConn+=aNbConnectivity){ const SMDS_MeshEdge* anElem = anIter->next(); SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator(); for(TInt iNode = 0; iNode < aNbConnectivity && aNodesIter->more(); iNode++){ const SMDS_MeshElement* aNode = aNodesIter->next(); #ifdef _EDF_NODE_IDS_ aConnectivity[iConn+iNode] = aNodeIdMap[aNode->GetID()]; #else aConnectivity[iConn+iNode] = aNode->GetID(); #endif } anElemNums[iElem] = anElem->GetID(); if (anElemFamMap.find(anElem) != anElemFamMap.end()) aFamilyNums[iElem] = anElemFamMap[anElem]; else aFamilyNums[iElem] = myEdgesDefaultFamilyId; } PCellInfo aCellInfo = myMed->CrCellInfo(aMeshInfo, SMDS_MED_ENTITY, eSEG2, SMDS_MED_CONNECTIVITY, aConnectivity, aFamilyNums, anElemNums); myMed->SetCellInfo(aCellInfo); } // Storing SMDS Faces if(TInt aNbElems = myMesh->NbFaces()){ SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); #ifdef _ELEMENTS_BY_DIM_ SMDS_MED_ENTITY = eFACE; #endif TInt aNbTriaConn = MED::GetNbNodes(eTRIA3); MED::TIntVector anTriaElemNums; anTriaElemNums.reserve(aNbElems); MED::TIntVector aTriaFamilyNums; aTriaFamilyNums.reserve(aNbElems); MED::TIntVector aTriaConn; aTriaConn.reserve(aNbElems*aNbTriaConn); TInt aNbQuadConn = MED::GetNbNodes(eQUAD4); MED::TIntVector aQuadElemNums; aQuadElemNums.reserve(aNbElems); MED::TIntVector aQuadFamilyNums; aQuadFamilyNums.reserve(aNbElems); MED::TIntVector aQuadConn; aQuadConn.reserve(aNbElems*aNbQuadConn); MED::TIntVector aPolygoneElemNums; aPolygoneElemNums.reserve(aNbElems); MED::TIntVector aPolygoneInds; aPolygoneInds.reserve(aNbElems + 1); aPolygoneInds.push_back(1); // reference on the first element in the connectivities MED::TIntVector aPolygoneFamilyNums; aPolygoneFamilyNums.reserve(aNbElems); MED::TIntVector aPolygoneConn; aPolygoneConn.reserve(aNbElems*aNbQuadConn); for(TInt iElem = 0; iElem < aNbElems && anIter->more(); iElem++){ const SMDS_MeshFace* anElem = anIter->next(); TInt aNbNodes = anElem->NbNodes(); SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator(); TInt aNbConnectivity; MED::TIntVector* anElemNums; MED::TIntVector* aFamilyNums; MED::TIntVector* aConnectivity; if (anElem->IsPoly()) { aNbConnectivity = aNbNodes; anElemNums = &aPolygoneElemNums; aFamilyNums = &aPolygoneFamilyNums; aConnectivity = &aPolygoneConn; } else { switch(aNbNodes){ case 3: aNbConnectivity = aNbTriaConn; anElemNums = &anTriaElemNums; aFamilyNums = &aTriaFamilyNums; aConnectivity = &aTriaConn; break; case 4: aNbConnectivity = aNbQuadConn; anElemNums = &aQuadElemNums; aFamilyNums = &aQuadFamilyNums; aConnectivity = &aQuadConn; break; default: break; } } MED::TIntVector aVector(aNbNodes); for(TInt iNode = 0; aNodesIter->more(); iNode++){ const SMDS_MeshElement* aNode = aNodesIter->next(); #ifdef _EDF_NODE_IDS_ aVector[iNode] = aNodeIdMap[aNode->GetID()]; #else aVector[iNode] = aNode->GetID(); #endif } TInt aSize = aConnectivity->size(); aConnectivity->resize(aSize+aNbConnectivity); // There is some differences between SMDS and MED in cells mapping switch(aNbNodes){ case 4: (*aConnectivity)[aSize+0] = aVector[0]; (*aConnectivity)[aSize+1] = aVector[1]; (*aConnectivity)[aSize+2] = aVector[3]; (*aConnectivity)[aSize+3] = aVector[2]; default: for(TInt iNode = 0; iNode < aNbNodes; iNode++) (*aConnectivity)[aSize+iNode] = aVector[iNode]; } if (anElem->IsPoly()) { // fill indices for polygonal element TInt aPrevPos = aPolygoneInds.back(); aPolygoneInds.push_back(aPrevPos + aNbNodes); } anElemNums->push_back(anElem->GetID()); if (anElemFamMap.find(anElem) != anElemFamMap.end()) aFamilyNums->push_back(anElemFamMap[anElem]); else aFamilyNums->push_back(myFacesDefaultFamilyId); } if(TInt aNbElems = anTriaElemNums.size()){ PCellInfo aCellInfo = myMed->CrCellInfo(aMeshInfo, SMDS_MED_ENTITY, eTRIA3, SMDS_MED_CONNECTIVITY, aTriaConn, aTriaFamilyNums, anTriaElemNums); MESSAGE("Perform - anEntity = "<NbFaces(); for (int iface = 1; iface <= aNbFaces; iface++) { int aNbFaceNodes = aPolyedre->NbFaceNodes(iface); for (int inode = 1; inode <= aNbFaceNodes; inode++) { aNodeId = aPolyedre->GetFaceNode(iface, inode)->GetID(); #ifdef _EDF_NODE_IDS_ aPolyedreConn.push_back(aNodeIdMap[aNodeId]); #else aPolyedreConn.push_back(aNodeId); #endif } TInt aPrevPos = aPolyedreFaces.back(); aPolyedreFaces.push_back(aPrevPos + aNbFaceNodes); } TInt aPrevPos = aPolyedreInds.back(); aPolyedreInds.push_back(aPrevPos + aNbFaces); } else { TInt aNbNodes = anElem->NbNodes(); SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator(); TInt aNbConnectivity; MED::TIntVector* aConnectivity; switch(aNbNodes){ case 4: aNbConnectivity = aNbTetraConn; anElemNums = &anTetraElemNums; aFamilyNums = &aTetraFamilyNums; aConnectivity = &aTetraConn; break; case 5: aNbConnectivity = aNbPyraConn; anElemNums = &anPyraElemNums; aFamilyNums = &aPyraFamilyNums; aConnectivity = &aPyraConn; break; case 6: aNbConnectivity = aNbPentaConn; anElemNums = &anPentaElemNums; aFamilyNums = &aPentaFamilyNums; aConnectivity = &aPentaConn; break; case 8: aNbConnectivity = aNbHexaConn; anElemNums = &aHexaElemNums; aFamilyNums = &aHexaFamilyNums; aConnectivity = &aHexaConn; } TInt aSize = aConnectivity->size(); aConnectivity->resize(aSize + aNbConnectivity); MED::TIntVector aVector(aNbNodes); for(TInt iNode = 0; aNodesIter->more(); iNode++){ const SMDS_MeshElement* aNode = aNodesIter->next(); #ifdef _EDF_NODE_IDS_ aVector[iNode] = aNodeIdMap[aNode->GetID()]; #else aVector[iNode] = aNode->GetID(); #endif } // There is some difference between SMDS and MED in cells mapping switch(aNbNodes){ case 5: (*aConnectivity)[aSize+0] = aVector[0]; (*aConnectivity)[aSize+1] = aVector[3]; (*aConnectivity)[aSize+2] = aVector[2]; (*aConnectivity)[aSize+3] = aVector[1]; (*aConnectivity)[aSize+4] = aVector[4]; default: for(TInt iNode = 0; iNode < aNbNodes; iNode++) (*aConnectivity)[aSize+iNode] = aVector[iNode]; } } anElemNums->push_back(anElem->GetID()); if (anElemFamMap.find(anElem) != anElemFamMap.end()) aFamilyNums->push_back(anElemFamMap[anElem]); else aFamilyNums->push_back(myVolumesDefaultFamilyId); } if(TInt aNbElems = anTetraElemNums.size()){ PCellInfo aCellInfo = myMed->CrCellInfo(aMeshInfo, SMDS_MED_ENTITY, eTETRA4, SMDS_MED_CONNECTIVITY, aTetraConn, aTetraFamilyNums, anTetraElemNums); MESSAGE("Perform - anEntity = "<