diff --git a/src/Mod/Fem/App/FemMesh.cpp b/src/Mod/Fem/App/FemMesh.cpp index 1e8b3f8b6c..aeb214a8e8 100644 --- a/src/Mod/Fem/App/FemMesh.cpp +++ b/src/Mod/Fem/App/FemMesh.cpp @@ -1105,6 +1105,215 @@ std::set FemMesh::getFacesOnly(void) const return resultIDs; } +namespace { +class NastranElement { +public: + virtual ~NastranElement() = default; + bool isValid() const { + return element_id >= 0; + } + virtual void read(const std::string& str1, const std::string& str2) = 0; + virtual void addToMesh(SMESHDS_Mesh* meshds) = 0; + +protected: + int element_id = -1; + std::vector elements; +}; + +typedef std::shared_ptr NastranElementPtr; + +class GRIDElement : public NastranElement { + void addToMesh(SMESHDS_Mesh* meshds) { + meshds->AddNodeWithID(node.x, node.y, node.z, element_id); + } + +protected: + Base::Vector3d node; +}; + +class GRIDFreeFieldElement : public GRIDElement { + void read(const std::string& str, const std::string&) { + char_separator sep(","); + tokenizer > tokens(str, sep); + std::vector token_results; + token_results.assign(tokens.begin(),tokens.end()); + if (token_results.size() < 6) + return;//Line does not include Nodal coordinates + + element_id = atoi(token_results[1].c_str()); + node.x = atof(token_results[3].c_str()); + node.y = atof(token_results[4].c_str()); + node.z = atof(token_results[5].c_str()); + } +}; + +class GRIDLongFieldElement : public GRIDElement { + void read(const std::string& str1, const std::string& str2) { + element_id = atoi(str1.substr(8,24).c_str()); + node.x = atof(str1.substr(40,56).c_str()); + node.y = atof(str1.substr(56,72).c_str()); + node.z = atof(str2.substr(8,24).c_str()); + } +}; + +class GRIDSmallFieldElement : public GRIDElement { + void read(const std::string&, const std::string&) { + } +}; + +class CTRIA3Element : public NastranElement { +public: + void addToMesh(SMESHDS_Mesh* meshds) { + const SMDS_MeshNode* n0 = meshds->FindNode(elements[0]); + const SMDS_MeshNode* n1 = meshds->FindNode(elements[1]); + const SMDS_MeshNode* n2 = meshds->FindNode(elements[2]); + if (n0 && n1 && n2) { + meshds->AddFaceWithID + ( + n0, n1, n2, + element_id + ); + } + else { + Base::Console().Warning("NASTRAN: Failed to add face %d from nodes: (%d, %d, %d,)\n", + element_id, + elements[0], + elements[1], + elements[2]); + } + } +}; + +class CTRIA3FreeFieldElement : public CTRIA3Element { +public: + void read(const std::string& str, const std::string&) { + char_separator sep(","); + tokenizer > tokens(str, sep); + std::vector token_results; + token_results.assign(tokens.begin(),tokens.end()); + if (token_results.size() < 6) + return;//Line does not include enough nodal IDs + + element_id = atoi(token_results[1].c_str()); + elements.push_back(atoi(token_results[3].c_str())); + elements.push_back(atoi(token_results[4].c_str())); + elements.push_back(atoi(token_results[5].c_str())); + } +}; + +class CTRIA3LongFieldElement : public CTRIA3Element { +public: + void read(const std::string& str, const std::string&) { + element_id = atoi(str.substr(8,16).c_str()); + elements.push_back(atoi(str.substr(24,32).c_str())); + elements.push_back(atoi(str.substr(32,40).c_str())); + elements.push_back(atoi(str.substr(40,48).c_str())); + } +}; + +class CTRIA3SmallFieldElement : public CTRIA3Element { +public: + void read(const std::string&, const std::string&) { + } +}; + +class CTETRAElement : public NastranElement { +public: + void addToMesh(SMESHDS_Mesh* meshds) { + const SMDS_MeshNode* n0 = meshds->FindNode(elements[1]); + const SMDS_MeshNode* n1 = meshds->FindNode(elements[0]); + const SMDS_MeshNode* n2 = meshds->FindNode(elements[2]); + const SMDS_MeshNode* n3 = meshds->FindNode(elements[3]); + const SMDS_MeshNode* n4 = meshds->FindNode(elements[4]); + const SMDS_MeshNode* n5 = meshds->FindNode(elements[6]); + const SMDS_MeshNode* n6 = meshds->FindNode(elements[5]); + const SMDS_MeshNode* n7 = meshds->FindNode(elements[8]); + const SMDS_MeshNode* n8 = meshds->FindNode(elements[7]); + const SMDS_MeshNode* n9 = meshds->FindNode(elements[9]); + if (n0 && n1 && n2 && n3 && n4 && n5 && n6 && n7 && n8 && n9) { + meshds->AddVolumeWithID + ( + n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, + element_id + ); + } + else { + Base::Console().Warning("NASTRAN: Failed to add volume %d from nodes: (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d)\n", + element_id, + elements[1], + elements[0], + elements[2], + elements[3], + elements[4], + elements[6], + elements[5], + elements[8], + elements[7], + elements[9]); + } + } +}; + +class CTETRAFreeFieldElement : public CTETRAElement { +public: + void read(const std::string& str, const std::string&) { + char_separator sep(","); + tokenizer > tokens(str, sep); + std::vector token_results; + token_results.assign(tokens.begin(),tokens.end()); + if (token_results.size() < 14) + return;//Line does not include enough nodal IDs + + element_id = atoi(token_results[1].c_str()); + elements.push_back(atoi(token_results[3].c_str())); + elements.push_back(atoi(token_results[4].c_str())); + elements.push_back(atoi(token_results[5].c_str())); + elements.push_back(atoi(token_results[6].c_str())); + elements.push_back(atoi(token_results[7].c_str())); + elements.push_back(atoi(token_results[8].c_str())); + elements.push_back(atoi(token_results[10].c_str())); + elements.push_back(atoi(token_results[11].c_str())); + elements.push_back(atoi(token_results[12].c_str())); + elements.push_back(atoi(token_results[13].c_str())); + } +}; + +class CTETRALongFieldElement : public CTETRAElement { +public: + void read(const std::string& str1, const std::string& str2) { + int id = atoi(str1.substr(8,16).c_str()); + int offset = 0; + + if(id < 1000000) + offset = 0; + else if (id < 10000000) + offset = 1; + else if (id < 100000000) + offset = 2; + + + element_id = id; + elements.push_back(atoi(str1.substr(24,32).c_str())); + elements.push_back(atoi(str1.substr(32,40).c_str())); + elements.push_back(atoi(str1.substr(40,48).c_str())); + elements.push_back(atoi(str1.substr(48,56).c_str())); + elements.push_back(atoi(str1.substr(56,64).c_str())); + elements.push_back(atoi(str1.substr(64,72).c_str())); + elements.push_back(atoi(str2.substr(8+offset,16+offset).c_str())); + elements.push_back(atoi(str2.substr(16+offset,24+offset).c_str())); + elements.push_back(atoi(str2.substr(24+offset,32+offset).c_str())); + elements.push_back(atoi(str2.substr(32+offset,40+offset).c_str())); + } +}; + + +class CTETRASmallFieldElement : public CTETRAElement { +public: + void read(const std::string&, const std::string&) { + } +}; +} + void FemMesh::readNastran(const std::string &Filename) { Base::TimeInfo Start; @@ -1116,129 +1325,68 @@ void FemMesh::readNastran(const std::string &Filename) inputfile.open(Filename.c_str()); inputfile.seekg(std::ifstream::beg); std::string line1,line2; - std::vector token_results; - Base::Vector3d current_node; - std::vector vertices; - std::vector nodal_id; - std::vector > all_elements; - std::vector element_id; - bool nastran_free_format = false; + std::vector mesh_elements; + enum Format { + FreeField, + SmallField, + LongField + }; + Format nastranFormat = Format::LongField; do { std::getline(inputfile,line1); - if (line1.size() == 0) continue; - if (!nastran_free_format && line1.find(',')!= std::string::npos) - nastran_free_format = true; - if (!nastran_free_format && line1.find("GRID*")!= std::string::npos ) //We found a Grid line - { + if (line1.size() == 0) + continue; + if (line1.find(',') != std::string::npos) + nastranFormat = Format::FreeField; + + NastranElementPtr ptr; + if (line1.find("GRID*") != std::string::npos) { //We found a Grid line //Now lets extract the GRID Points = Nodes //As each GRID Line consists of two subsequent lines we have to //take care of that as well - std::getline(inputfile,line2); - //Get the Nodal ID - nodal_id.push_back(atoi(line1.substr(8,24).c_str())); - //Extract X Value - current_node.x = atof(line1.substr(40,56).c_str()); - //Extract Y Value - current_node.y = atof(line1.substr(56,72).c_str()); - //Extract Z Value - current_node.z = atof(line2.substr(8,24).c_str()); - - vertices.push_back(current_node); + if (nastranFormat == Format::LongField) { + std::getline(inputfile,line2); + ptr = std::make_shared(); + ptr->read(line1, line2); + } } - else if (!nastran_free_format && line1.find("CTETRA")!= std::string::npos) - { + else if (line1.find("GRID") != std::string::npos) { //We found a Grid line + if (nastranFormat == Format::FreeField) { + ptr = std::make_shared(); + ptr->read(line1, ""); + } + } + else if (line1.find("CTRIA3") != std::string::npos) { + if (nastranFormat == Format::FreeField) { + ptr = std::make_shared(); + ptr->read(line1, ""); + } + else { + ptr = std::make_shared(); + ptr->read(line1, ""); + } + } + else if (line1.find("CTETRA") != std::string::npos) { //Lets extract the elements //As each Element Line consists of two subsequent lines as well //we have to take care of that //At a first step we only extract Quadratic Tetrahedral Elements std::getline(inputfile,line2); - unsigned int id = atoi(line1.substr(8,16).c_str()); - int offset = 0; - - if(id < 1000000) - offset = 0; - else if (id < 10000000) - offset = 1; - else if (id < 100000000) - offset = 2; - - - element_id.push_back(id); - std::vector tetra_element; - tetra_element.push_back(atoi(line1.substr(24,32).c_str())); - tetra_element.push_back(atoi(line1.substr(32,40).c_str())); - tetra_element.push_back(atoi(line1.substr(40,48).c_str())); - tetra_element.push_back(atoi(line1.substr(48,56).c_str())); - tetra_element.push_back(atoi(line1.substr(56,64).c_str())); - tetra_element.push_back(atoi(line1.substr(64,72).c_str())); - tetra_element.push_back(atoi(line2.substr(8+offset,16+offset).c_str())); - tetra_element.push_back(atoi(line2.substr(16+offset,24+offset).c_str())); - tetra_element.push_back(atoi(line2.substr(24+offset,32+offset).c_str())); - tetra_element.push_back(atoi(line2.substr(32+offset,40+offset).c_str())); - - all_elements.push_back(tetra_element); - } - else if (nastran_free_format && line1.find("GRID")!= std::string::npos ) //We found a Grid line - { - char_separator sep(","); - tokenizer > tokens(line1, sep); - token_results.assign(tokens.begin(),tokens.end()); - if (token_results.size() < 6) - continue;//Line does not include Nodal coordinates - - nodal_id.push_back(atoi(token_results[1].c_str())); - current_node.x = atof(token_results[3].c_str()); - current_node.y = atof(token_results[4].c_str()); - current_node.z = atof(token_results[5].c_str()); - vertices.push_back(current_node); - } - else if (nastran_free_format && line1.find("CTRIA3")!= std::string::npos ) - { - char_separator sep(","); - tokenizer > tokens(line1, sep); - token_results.assign(tokens.begin(),tokens.end()); - if (token_results.size() < 6) - continue;//Line does not include enough nodal IDs - - element_id.push_back(atoi(token_results[1].c_str())); - std::vector face_element; - face_element.push_back(atoi(token_results[3].c_str())); - face_element.push_back(atoi(token_results[4].c_str())); - face_element.push_back(atoi(token_results[5].c_str())); - - all_elements.push_back(face_element); - } - else if (nastran_free_format && line1.find("CTETRA")!= std::string::npos) - { - //Lets extract the elements - //As each Element Line consists of two subsequent lines as well - //we have to take care of that - //At a first step we only extract Quadratic Tetrahedral Elements - std::getline(inputfile,line2); - char_separator sep(","); - tokenizer > tokens(line1.append(line2), sep); - token_results.assign(tokens.begin(),tokens.end()); - if (token_results.size() < 14) - continue;//Line does not include enough nodal IDs - - element_id.push_back(atoi(token_results[1].c_str())); - std::vector tetra_element; - tetra_element.push_back(atoi(token_results[3].c_str())); - tetra_element.push_back(atoi(token_results[4].c_str())); - tetra_element.push_back(atoi(token_results[5].c_str())); - tetra_element.push_back(atoi(token_results[6].c_str())); - tetra_element.push_back(atoi(token_results[7].c_str())); - tetra_element.push_back(atoi(token_results[8].c_str())); - tetra_element.push_back(atoi(token_results[10].c_str())); - tetra_element.push_back(atoi(token_results[11].c_str())); - tetra_element.push_back(atoi(token_results[12].c_str())); - tetra_element.push_back(atoi(token_results[13].c_str())); - - all_elements.push_back(tetra_element); + if (nastranFormat == Format::FreeField) { + ptr = std::make_shared(); + ptr->read(line1.append(line2), ""); + } + else { + ptr = std::make_shared(); + ptr->read(line1, line2); + } } + if (ptr && ptr->isValid()) { + mesh_elements.push_back(ptr); + } } while (inputfile.good()); inputfile.close(); @@ -1246,74 +1394,13 @@ void FemMesh::readNastran(const std::string &Filename) Base::Console().Log(" %f: File read, start building mesh\n",Base::TimeInfo::diffTimeF(Start,Base::TimeInfo())); //Now fill the SMESH datastructure - std::vector::const_iterator anodeiterator; SMESHDS_Mesh* meshds = this->myMesh->GetMeshDS(); meshds->ClearMesh(); - unsigned int j=0; - for(anodeiterator=vertices.begin(); anodeiterator!=vertices.end(); anodeiterator++) - { - meshds->AddNodeWithID((*anodeiterator).x,(*anodeiterator).y,(*anodeiterator).z,nodal_id[j]); - j++; + + for (auto it : mesh_elements) { + it->addToMesh(meshds); } - for(size_t i=0;iFindNode(all_elements[i][0]); - const SMDS_MeshNode* n1 = meshds->FindNode(all_elements[i][1]); - const SMDS_MeshNode* n2 = meshds->FindNode(all_elements[i][2]); - if (n0 && n1 && n2) { - meshds->AddFaceWithID - ( - n0, n1, n2, - element_id[i] - ); - } - else { - Base::Console().Warning("NASTRAN: Failed to add face %d from nodes: (%d, %d, %d,)\n", - element_id[i], - all_elements[i][0], - all_elements[i][1], - all_elements[i][2]); - } - } - else if (all_elements[i].size() == 10) { - const SMDS_MeshNode* n0 = meshds->FindNode(all_elements[i][1]); - const SMDS_MeshNode* n1 = meshds->FindNode(all_elements[i][0]); - const SMDS_MeshNode* n2 = meshds->FindNode(all_elements[i][2]); - const SMDS_MeshNode* n3 = meshds->FindNode(all_elements[i][3]); - const SMDS_MeshNode* n4 = meshds->FindNode(all_elements[i][4]); - const SMDS_MeshNode* n5 = meshds->FindNode(all_elements[i][6]); - const SMDS_MeshNode* n6 = meshds->FindNode(all_elements[i][5]); - const SMDS_MeshNode* n7 = meshds->FindNode(all_elements[i][8]); - const SMDS_MeshNode* n8 = meshds->FindNode(all_elements[i][7]); - const SMDS_MeshNode* n9 = meshds->FindNode(all_elements[i][9]); - if (n0 && n1 && n2 && n3 && n4 && n5 && n6 && n7 && n8 && n9) { - meshds->AddVolumeWithID - ( - n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, - element_id[i] - ); - } - else { - Base::Console().Warning("NASTRAN: Failed to add volume %d from nodes: (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d)\n", - element_id[i], - all_elements[i][1], - all_elements[i][0], - all_elements[i][2], - all_elements[i][3], - all_elements[i][4], - all_elements[i][6], - all_elements[i][5], - all_elements[i][8], - all_elements[i][7], - all_elements[i][9]); - } - } - } Base::Console().Log(" %f: Done \n",Base::TimeInfo::diffTimeF(Start,Base::TimeInfo())); }