From 189fcd01c2bc3d10b5bef4c8dbdfe3c152dcc883 Mon Sep 17 00:00:00 2001
From: rinkk <karsten.rink@ufz.de>
Date: Thu, 1 Aug 2019 12:47:13 +0200
Subject: [PATCH] added support for GoCAD PLine data, checking for VSet and
 Model3d

---
 Applications/DataExplorer/mainwindow.cpp      |   4 +-
 ...SurfaceReader.cpp => GocadAsciiReader.cpp} | 206 ++++++++++++++----
 ...cadTSurfaceReader.h => GocadAsciiReader.h} |  43 +++-
 .../FileConverter/GocadTSurfaceReader.cpp     |   9 +-
 4 files changed, 204 insertions(+), 58 deletions(-)
 rename Applications/FileIO/GocadIO/{GocadTSurfaceReader.cpp => GocadAsciiReader.cpp} (68%)
 rename Applications/FileIO/GocadIO/{GocadTSurfaceReader.h => GocadAsciiReader.h} (68%)

diff --git a/Applications/DataExplorer/mainwindow.cpp b/Applications/DataExplorer/mainwindow.cpp
index 60810f90f78..beee85aa5a8 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 9287c5b15ab..0f1dd070876 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 08a3bb8490a..a1f68b4441f 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 48625b0dd28..f881976a6b4 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);
-- 
GitLab