diff --git a/Applications/DataExplorer/mainwindow.cpp b/Applications/DataExplorer/mainwindow.cpp index 60810f90f78def314e1d2f4506a631533e12f50a..beee85aa5a82e9786b53064330e15faa2eebf5ae 100644 --- a/Applications/DataExplorer/mainwindow.cpp +++ b/Applications/DataExplorer/mainwindow.cpp @@ -39,7 +39,7 @@ #include "Applications/FileIO/GMSInterface.h" #include "Applications/FileIO/Gmsh/GMSHInterface.h" #include "Applications/FileIO/Gmsh/GmshReader.h" -#include "Applications/FileIO/GocadIO/GocadTSurfaceReader.h" +#include "Applications/FileIO/GocadIO/GocadAsciiReader.h" #include "Applications/FileIO/Legacy/OGSIOVer4.h" #include "Applications/FileIO/PetrelInterface.h" #include "Applications/FileIO/TetGenInterface.h" @@ -687,7 +687,7 @@ void MainWindow::loadFile(ImportFileType::type t, const QString &fileName) else if (t == ImportFileType::GOCAD_TSURF) { std::string file_name(fileName.toStdString()); - FileIO::Gocad::GocadTSurfaceReader gcts; + FileIO::Gocad::GocadAsciiReader gcts; std::vector<std::unique_ptr<MeshLib::Mesh>> meshes; if (gcts.readFile(file_name, meshes)) { diff --git a/Applications/FileIO/GocadIO/GocadTSurfaceReader.cpp b/Applications/FileIO/GocadIO/GocadAsciiReader.cpp similarity index 68% rename from Applications/FileIO/GocadIO/GocadTSurfaceReader.cpp rename to Applications/FileIO/GocadIO/GocadAsciiReader.cpp index 9287c5b15abcd1031df280eb2061a21b88755aca..0f1dd070876c22f01dd9cb52baccd4db22558703 100644 --- a/Applications/FileIO/GocadIO/GocadTSurfaceReader.cpp +++ b/Applications/FileIO/GocadIO/GocadAsciiReader.cpp @@ -7,7 +7,7 @@ * http://www.opengeosys.org/LICENSE.txt */ -#include "GocadTSurfaceReader.h" +#include "GocadAsciiReader.h" #include <logog/include/logog.hpp> @@ -16,6 +16,7 @@ #include "Applications/FileIO/GocadIO/CoordinateSystem.h" #include "BaseLib/FileTools.h" #include "BaseLib/StringTools.h" +#include "MeshLib/Elements/Line.h" #include "MeshLib/Elements/Tri.h" #include "MeshLib/Mesh.h" #include "MeshLib/Node.h" @@ -27,11 +28,9 @@ namespace Gocad const std::string mat_id_name = "MaterialIDs"; const std::string eof_error = "Error: Unexpected end of file."; -GocadTSurfaceReader::GocadTSurfaceReader() -{ -} +GocadAsciiReader::GocadAsciiReader() {} -bool GocadTSurfaceReader::readFile( +bool GocadAsciiReader::readFile( std::string const& file_name, std::vector<std::unique_ptr<MeshLib::Mesh>>& meshes) { @@ -43,11 +42,23 @@ bool GocadTSurfaceReader::readFile( return false; } - while (TSurfaceFound(in)) + GOCAD_DATA_TYPE type; + while ((type = datasetFound(in)) != GOCAD_DATA_TYPE::UNDEFINED) { + if (type == GOCAD_DATA_TYPE::VSET || type == GOCAD_DATA_TYPE::MODEL3D) + { + if (!skipToEND(in)) + { + std::string const t = (type == GOCAD_DATA_TYPE::VSET) ? "VSet" : "Model3D"; + ERR("Parsing of type %s is not implemented. Skipping section.", t); + return false; + } + continue; + } + std::string mesh_name = BaseLib::dropFileExtension(file_name) + std::to_string(meshes.size() + 1); - std::unique_ptr<MeshLib::Mesh> mesh(readMesh(in, mesh_name)); + std::unique_ptr<MeshLib::Mesh> mesh(readData(in, type, mesh_name)); if (mesh == nullptr) { ERR("File parsing aborted...") @@ -58,8 +69,9 @@ bool GocadTSurfaceReader::readFile( return true; } -MeshLib::Mesh* GocadTSurfaceReader::readMesh(std::ifstream& in, - std::string& mesh_name) +MeshLib::Mesh* GocadAsciiReader::readData(std::ifstream& in, + GOCAD_DATA_TYPE const& type, + std::string& mesh_name) { if (!parseHeader(in, mesh_name)) { @@ -108,7 +120,21 @@ MeshLib::Mesh* GocadTSurfaceReader::readMesh(std::ifstream& in, return nullptr; } } - else if (str[0] == "TFACE") + else if (type == GOCAD_DATA_TYPE::PLINE && str[0] == "ILINE") + { + std::vector<MeshLib::Node*> nodes; + std::vector<MeshLib::Element*> elems; + std::map<std::size_t, std::size_t> node_id_map; + INFO("Parsing line %s", mesh_name.c_str()); + if (!parseLine(in, nodes, elems, node_id_map, mesh_prop)) + { + ERR("Error parsing Line %s.", mesh_name.c_str()); + clearData(nodes, elems); + return nullptr; + } + return new MeshLib::Mesh(mesh_name, nodes, elems, mesh_prop); + } + else if (type == GOCAD_DATA_TYPE::TSURF && str[0] == "TFACE") { std::vector<MeshLib::Node*> nodes; std::vector<MeshLib::Element*> elems; @@ -120,7 +146,6 @@ MeshLib::Mesh* GocadTSurfaceReader::readMesh(std::ifstream& in, clearData(nodes, elems); return nullptr; } - return new MeshLib::Mesh(mesh_name, nodes, elems, mesh_prop); } else @@ -133,7 +158,7 @@ MeshLib::Mesh* GocadTSurfaceReader::readMesh(std::ifstream& in, return nullptr; } -bool GocadTSurfaceReader::TSurfaceFound(std::ifstream& in) const +GOCAD_DATA_TYPE GocadAsciiReader::datasetFound(std::ifstream& in) const { std::string line; while (std::getline(in, line)) @@ -142,35 +167,38 @@ bool GocadTSurfaceReader::TSurfaceFound(std::ifstream& in) const { continue; } - if (line.substr(0, 11) == "GOCAD TSurf") + + if (line.substr(0, 10) == "GOCAD VSet") { - return true; - // No idea why this is allowed in a *.ts file. - // It should be a whole different file type. + return GOCAD_DATA_TYPE::VSET; } - if (line.substr(0, 13) == "GOCAD Model3d") + else if (line.substr(0, 11) == "GOCAD PLine") { - if (!skipModel3d(in)) - { - ERR("Error parsing Model3d"); - return false; - } + return GOCAD_DATA_TYPE::PLINE; + } + else if (line.substr(0, 11) == "GOCAD TSurf") + { + return GOCAD_DATA_TYPE::TSURF; + } + else if (line.substr(0, 13) == "GOCAD Model3d") + { + return GOCAD_DATA_TYPE::MODEL3D; } else { - ERR("No TSurf-identifier found..."); - return false; + ERR("No known identifier found..."); + return GOCAD_DATA_TYPE::UNDEFINED; } } - return false; + return GOCAD_DATA_TYPE::UNDEFINED; } -bool GocadTSurfaceReader::isCommentLine(std::string const& str) const +bool GocadAsciiReader::isCommentLine(std::string const& str) const { return (str.substr(0, 1) == "#"); } -bool GocadTSurfaceReader::parseHeader(std::ifstream& in, std::string& mesh_name) +bool GocadAsciiReader::parseHeader(std::ifstream& in, std::string& mesh_name) { std::string line; while (std::getline(in, line)) @@ -190,7 +218,7 @@ bool GocadTSurfaceReader::parseHeader(std::ifstream& in, std::string& mesh_name) return false; } -bool GocadTSurfaceReader::parsePropertyClass(std::ifstream& in) const +bool GocadAsciiReader::parsePropertyClass(std::ifstream& in) const { std::string line; while (std::getline(in, line)) @@ -222,7 +250,7 @@ std::string propertyCheck(std::string const& strng) return std::string(""); } -bool GocadTSurfaceReader::parseProperties(std::ifstream& in, +bool GocadAsciiReader::parseProperties(std::ifstream& in, std::vector<std::string> const& names, MeshLib::Properties& mesh_prop) { @@ -272,7 +300,45 @@ bool GocadTSurfaceReader::parseProperties(std::ifstream& in, return false; } -bool GocadTSurfaceReader::parseSurface( +bool GocadAsciiReader::parseLine( + std::ifstream& in, + std::vector<MeshLib::Node*>& nodes, + std::vector<MeshLib::Element*>& elems, + std::map<std::size_t, std::size_t>& node_id_map, + MeshLib::Properties& mesh_prop) +{ + if (!parseNodes(in, nodes, node_id_map, mesh_prop)) + { + return false; + } + if (!parseLineSegments(in, nodes, elems, node_id_map, mesh_prop)) + { + return false; + } + + std::string line; + while (std::getline(in, line)) + { + std::vector<std::string> str = BaseLib::splitString(line); + if (str[0] == "ILINE") + { + parseLine(in, nodes, elems, node_id_map, mesh_prop); + return true; + } + else if (line == "END") + { + return true; + } + else + { + WARN("GocadTSurfaceReader::parseLine() - Unknown keyword found: %s", line.c_str()); + } + } + ERR("%s", eof_error.c_str()); + return false; +} + +bool GocadAsciiReader::parseSurface( std::ifstream& in, std::vector<MeshLib::Node*>& nodes, std::vector<MeshLib::Element*>& elems, @@ -311,10 +377,7 @@ bool GocadTSurfaceReader::parseSurface( } else { - WARN( - "GocadTSurfaceReader::parseSurface() - Unknown keyword found: " - "%s", - line.c_str()); + WARN("GocadTSurfaceReader::parseSurface() - Unknown keyword found: %s", line.c_str()); } } ERR("%s", eof_error.c_str()); @@ -330,7 +393,7 @@ MeshLib::Node* createNode(std::stringstream& sstr) return new MeshLib::Node(data, id); } -bool GocadTSurfaceReader::parseNodes( +bool GocadAsciiReader::parseNodes( std::ifstream& in, std::vector<MeshLib::Node*>& nodes, std::map<std::size_t, std::size_t>& node_id_map, @@ -345,7 +408,13 @@ bool GocadTSurfaceReader::parseNodes( while (std::getline(in, line)) { std::vector<std::string> str = BaseLib::splitString(line); - if (line.substr(0, 4) == "TRGL") + if (line.substr(0, 3) == "SEG") + { + in.seekg(pos); + return true; + } + + else if (line.substr(0, 4) == "TRGL") { in.seekg(pos); return true; @@ -358,9 +427,7 @@ bool GocadTSurfaceReader::parseNodes( if (!(line.substr(0, 4) == "VRTX" || line.substr(0, 5) == "PVRTX" || line.substr(0, 4) == "ATOM")) { - WARN( - "GocadTSurfaceReader::parseNodes() - Unknown keyword found: %s", - line.c_str()); + WARN("GocadTSurfaceReader::parseNodes() - Unknown keyword found: %s", line.c_str()); continue; } @@ -397,7 +464,62 @@ bool GocadTSurfaceReader::parseNodes( return false; } -bool GocadTSurfaceReader::parseElements( +bool GocadAsciiReader::parseLineSegments( + std::ifstream& in, + std::vector<MeshLib::Node*>& nodes, + std::vector<MeshLib::Element*>& elems, + std::map<std::size_t, std::size_t> const& node_id_map, + MeshLib::Properties& mesh_prop) +{ + std::string keyword; + std::array<std::size_t, 3> data; + MeshLib::PropertyVector<int>& mat_ids = + *mesh_prop.getPropertyVector<int>(mat_id_name); + int current_mat_id(0); + if (!mat_ids.empty()) + { + current_mat_id = (*std::max_element(mat_ids.begin(), mat_ids.end()))++; + } + std::streampos pos = in.tellg(); + std::size_t id(0); + std::string line; + while (std::getline(in, line)) + { + if (line.empty() || isCommentLine(line)) + { + continue; + } + if (line.substr(0, 3) == "SEG") + { + std::stringstream sstr(line); + sstr >> keyword >> data[0] >> data[1]; + std::array<MeshLib::Node*, 2> elem_nodes; + for (std::size_t i = 0; i < 2; ++i) + { + auto const it = node_id_map.find(data[i]); + if (it == node_id_map.end() || it->second >= nodes.size()) + { + ERR("Error: Node ID (%d) out of range (0, %d).", data[i], + nodes.back()->getID()); + return false; + } + elem_nodes[i] = nodes[it->second]; + } + elems.push_back(new MeshLib::Line(elem_nodes, id++)); + mat_ids.push_back(current_mat_id); + } + else + { + in.seekg(pos); + return true; + } + pos = in.tellg(); + } + ERR("%s", eof_error.c_str()); + return false; +} + +bool GocadAsciiReader::parseElements( std::ifstream& in, std::vector<MeshLib::Node*>& nodes, std::vector<MeshLib::Element*>& elems, @@ -452,7 +574,7 @@ bool GocadTSurfaceReader::parseElements( return false; } -bool GocadTSurfaceReader::skipModel3d(std::ifstream& in) const +bool GocadAsciiReader::skipToEND(std::ifstream& in) const { std::string line; while (std::getline(in, line)) @@ -466,7 +588,7 @@ bool GocadTSurfaceReader::skipModel3d(std::ifstream& in) const return false; } -void GocadTSurfaceReader::clearData(std::vector<MeshLib::Node*>& nodes, +void GocadAsciiReader::clearData(std::vector<MeshLib::Node*>& nodes, std::vector<MeshLib::Element*>& elems) { for (MeshLib::Element* e : elems) diff --git a/Applications/FileIO/GocadIO/GocadTSurfaceReader.h b/Applications/FileIO/GocadIO/GocadAsciiReader.h similarity index 68% rename from Applications/FileIO/GocadIO/GocadTSurfaceReader.h rename to Applications/FileIO/GocadIO/GocadAsciiReader.h index 08a3bb8490a02432eafd7b00d0aa5d1819e371e3..a1f68b4441f93b7770a4a251d20478dfa0cdd027 100644 --- a/Applications/FileIO/GocadIO/GocadTSurfaceReader.h +++ b/Applications/FileIO/GocadIO/GocadAsciiReader.h @@ -26,31 +26,41 @@ namespace FileIO { namespace Gocad { -class GocadTSurfaceReader final + +enum class GOCAD_DATA_TYPE +{ + UNDEFINED, + VSET, + PLINE, + TSURF, + MODEL3D +}; + +class GocadAsciiReader final { public: /** * Constructor takes as argument the Gocad .sg text file. */ - explicit GocadTSurfaceReader(); + explicit GocadAsciiReader(); - GocadTSurfaceReader(GocadTSurfaceReader&& src) = delete; - GocadTSurfaceReader(GocadTSurfaceReader const& src) = delete; - GocadTSurfaceReader& operator=(GocadTSurfaceReader&& rhs) = delete; - GocadTSurfaceReader& operator=(GocadTSurfaceReader const& rhs) = delete; + GocadAsciiReader(GocadAsciiReader&& src) = delete; + GocadAsciiReader(GocadAsciiReader const& src) = delete; + GocadAsciiReader& operator=(GocadAsciiReader&& rhs) = delete; + GocadAsciiReader& operator=(GocadAsciiReader const& rhs) = delete; /// Reads the specified file and writes data into internal mesh vector bool readFile(std::string const& file_name, std::vector<std::unique_ptr<MeshLib::Mesh>>& meshes); private: /// Reads one mesh contained in the file (there may be more than one!) - MeshLib::Mesh* readMesh(std::ifstream& in, std::string& mesh_name); + MeshLib::Mesh* readData(std::ifstream& in, GOCAD_DATA_TYPE const& type, std::string& mesh_name); /// Checks if the current line is a comment bool isCommentLine(std::string const& str) const; /// Checks if a TSurf identifier is found at the current stream position. - bool TSurfaceFound(std::ifstream& in) const; + GOCAD_DATA_TYPE datasetFound(std::ifstream& in) const; /// Parses the HEADER section (everything except the name is ignored right now) bool parseHeader(std::ifstream& in, std::string& mesh_name); @@ -65,6 +75,12 @@ private: std::vector<std::string> const& names, MeshLib::Properties& mesh_prop); + /// Parses line information (nodes, segments, properties) + bool parseLine(std::ifstream& in, std::vector<MeshLib::Node*>& nodes, + std::vector<MeshLib::Element*>& elems, + std::map<std::size_t, std::size_t>& node_id_map, + MeshLib::Properties& mesh_prop); + /// Parses the surface information (nodes, triangles, properties) bool parseSurface(std::ifstream& in, std::vector<MeshLib::Node*>& nodes, std::vector<MeshLib::Element*>& elems, @@ -76,14 +92,20 @@ private: std::map<std::size_t, std::size_t>& node_id_map, MeshLib::Properties& mesh_prop); + /// Parses the segments of a line + bool parseLineSegments(std::ifstream& in, std::vector<MeshLib::Node*>& nodes, + std::vector<MeshLib::Element*>& elems, + std::map<std::size_t, std::size_t> const& node_id_map, + MeshLib::Properties& mesh_prop); + /// Parses the element data for the current mesh bool parseElements(std::ifstream& in, std::vector<MeshLib::Node*>& nodes, std::vector<MeshLib::Element*>& elems, std::map<std::size_t, std::size_t> const& node_id_map, MeshLib::Properties& mesh_prop); - /// Skips over the Model3d sections of the file, should there be any. - bool skipModel3d(std::ifstream& in) const; + /// Parses current section until END-tag is reached + bool skipToEND(std::ifstream& in) const; /// Clears the memory if an error occured void clearData(std::vector<MeshLib::Node*>& nodes, @@ -95,7 +117,6 @@ private: VRTX, PVRTX }; - }; // end class GocadTSurfaceReader } // end namespace Gocad diff --git a/Applications/Utils/FileConverter/GocadTSurfaceReader.cpp b/Applications/Utils/FileConverter/GocadTSurfaceReader.cpp index 48625b0dd28f7181908526b94310ab5a06e7e33a..f881976a6b4fbf33c09b8890d052a05931cd67c6 100644 --- a/Applications/Utils/FileConverter/GocadTSurfaceReader.cpp +++ b/Applications/Utils/FileConverter/GocadTSurfaceReader.cpp @@ -13,7 +13,7 @@ #include "MeshLib/Mesh.h" #include "MeshLib/IO/VtkIO/VtuInterface.h" #include "Applications/ApplicationsLib/LogogSetup.h" -#include "Applications/FileIO/GocadIO/GocadTSurfaceReader.h" +#include "Applications/FileIO/GocadIO/GocadAsciiReader.h" std::string getDelim(std::string const& str) { @@ -27,7 +27,7 @@ int main(int argc, char* argv[]) ApplicationsLib::LogogSetup logog_setup; TCLAP::CmdLine cmd( - "Reads a Gocad triangular surfaces file (*.ts) and writes the " + "Reads Gocad ascii files (*.ts, *.pl, *.mx) and writes TSurf- and PLine" "data into one or more VTU unstructured grids.\n\n" "OpenGeoSys-6 software, version " + BaseLib::BuildInfo::ogs_version + @@ -54,18 +54,21 @@ int main(int argc, char* argv[]) cmd.parse(argc, argv); std::string const file_name (input_arg.getValue()); - FileIO::Gocad::GocadTSurfaceReader gcts; + FileIO::Gocad::GocadAsciiReader gcts; std::vector<std::unique_ptr<MeshLib::Mesh>> meshes; if (!gcts.readFile(file_name, meshes)) { ERR("Error reading file."); return 1; } + INFO("%d meshes found.", meshes.size()); std::string const dir = output_arg.getValue(); bool const write_binary = write_binary_arg.getValue(); std::string const delim = getDelim(dir); for (auto& mesh : meshes) { + if (mesh == nullptr) + continue; INFO("Writing mesh \"%s\"", mesh->getName().c_str()); int data_mode = (write_binary) ? 2 : 0; bool compressed = (write_binary);