OGS
FileIO::Gocad::GocadAsciiReader Namespace Reference

Classes

struct  PropertyBuffer

Enumerations

enum class  NodeType { UNSPECIFIED , VRTX , PVRTX }

Functions

void checkMeshNames (std::vector< std::unique_ptr< MeshLib::Mesh > > const &meshes)
bool isCommentLine (std::string const &str)
 Checks if the current line is a comment.
bool skipToEND (std::ifstream &in)
 Parses current section until END-tag is reached.
bool isKeyword (DataType const t, std::string const &line)
 Checks if current line is a designated keyword for a GoCAD data set.
DataType datasetFound (std::ifstream &in)
 Checks if a GoCAD data set begins at the current stream position.
void checkLineEndings (std::string const &file_name)
 Checks if current line is a designated keyword for a GoCAD data set.
bool parseHeader (std::ifstream &in, std::string &mesh_name)
 Parses the HEADER section (everything except the name is ignored right now)
bool parsePropertyClass (std::ifstream &in)
std::string propertyCheck (std::string const &string)
 Checks if the current line starts with one of the allowed keywords.
bool parseProperties (std::ifstream &in, std::vector< std::string > const &names, MeshLib::Properties &mesh_prop)
MeshLib::NodecreateNode (std::stringstream &sstr)
bool parseAtomRegionIndicators (std::ifstream &in)
bool parseNodes (std::ifstream &in, std::vector< MeshLib::Node * > &nodes, std::map< std::size_t, std::size_t > &node_id_map, MeshLib::Properties const &mesh_prop)
 Parses the node data for the current mesh.
template<std::size_t N>
std::optional< std::vector< std::array< std::size_t, N > > > parseNodeIdTuples (std::ifstream &in, std::string_view const keyword)
template<typename ElementType>
bool createElements (std::vector< std::array< std::size_t, ElementType::n_all_nodes > > const &element_data, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &elems, std::map< std::size_t, std::size_t > const &node_id_map)
template<typename ElementType>
std::optional< std::size_t > parseAndCreateElements (std::ifstream &in, std::string_view const keyword, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &elems, std::map< std::size_t, std::size_t > const &node_id_map)
bool appendSectionMaterialIds (MeshLib::Properties &mesh_prop, std::size_t const count)
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 line information (nodes, segments, properties)
bool parseSurface (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)
template<typename T>
MeshLib::MeshcreateMesh (std::ifstream &in, DataType type, std::string &mesh_name, MeshLib::Properties &mesh_prop, T parser, bool const flip_elevation)
 Converts parsed data into mesh.
MeshLib::MeshreadData (std::ifstream &in, DataType const &type, std::string &mesh_name)
 Reads one mesh contained in the file (there may be more than one!)
bool readFile (std::string const &file_name, std::vector< std::unique_ptr< MeshLib::Mesh > > &meshes, DataType const export_type=DataType::ALL)
 Reads the specified file and writes data into internal mesh vector.

Variables

const std::string mat_id_name = "MaterialIDs"
const std::string eof_error = "Error: Unexpected end of file."

Enumeration Type Documentation

◆ NodeType

Function Documentation

◆ appendSectionMaterialIds()

bool FileIO::Gocad::GocadAsciiReader::appendSectionMaterialIds ( MeshLib::Properties & mesh_prop,
std::size_t const count )

Assigns a fresh material ID to the count elements of the Gocad section that has just been parsed.

All Gocad sections of a data set share one MaterialIDs vector. Each section gets a material ID one larger than the current maximum in that vector (or 0 if it is still empty). The IDs already assigned to earlier sections are not modified.

Called after the elements have been appended, so on a missing MaterialIDs vector the element vector already holds the section's elements. That is not observable: the caller aborts the parsing of the whole data set, which discards all nodes and elements read so far.

Definition at line 513 of file GocadAsciiReader.cpp.

515{
516 auto* const mat_ids = mesh_prop.getPropertyVector<int>(mat_id_name);
517 if (mat_ids == nullptr)
518 {
519 ERR("GocadAsciiReader: Property vector '{:s}' not found.", mat_id_name);
520 return false;
521 }
522 mat_ids->resize(mat_ids->size() + count,
524 return true;
525}
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
PropertyVector< T > const * getPropertyVector(std::string_view name) const
constexpr void resize(std::size_t const size)
int nextUnusedMaterialId(PropertyVector< int > const &material_ids)

References ERR(), MeshLib::Properties::getPropertyVector(), mat_id_name, MeshLib::nextUnusedMaterialId(), and MeshLib::PropertyVector< PROP_VAL_TYPE >::resize().

Referenced by parseLine(), and parseSurface().

◆ checkLineEndings()

void FileIO::Gocad::GocadAsciiReader::checkLineEndings ( std::string const & file_name)

Checks if current line is a designated keyword for a GoCAD data set.

Definition at line 124 of file GocadAsciiReader.cpp.

125{
126#ifndef _WIN32
127 std::ifstream in(file_name);
128 if (in.is_open())
129 {
130 std::string line;
131 std::getline(in, line);
132 if (line.back() == '\r')
133 {
134 OGS_FATAL(
135 "Error in input file: {:s}. The line endings are in windows "
136 "format. To read this file under UNIX, transform the input "
137 "file to unix style line endings (e.g. dos2unix).",
138 file_name);
139 }
140 }
141#endif
142}
#define OGS_FATAL(...)
Definition Error.h:10

References OGS_FATAL.

Referenced by readFile().

◆ checkMeshNames()

void FileIO::Gocad::GocadAsciiReader::checkMeshNames ( std::vector< std::unique_ptr< MeshLib::Mesh > > const & meshes)

A GoCAD file may contain multiple datasets with the same name. To avoid conflicts when writing meshes, a unique id is appended to the mesh name if another dataset with the same name exists.

Definition at line 45 of file GocadAsciiReader.cpp.

46{
47 std::size_t const n_meshes = meshes.size();
48 for (std::size_t i = 0; i < n_meshes; ++i)
49 {
50 std::string const& name = meshes[i]->getName();
51 for (std::size_t j = i + 1; j < n_meshes; ++j)
52 {
53 if (meshes[j]->getName() == name)
54 {
55 std::string const id_str = std::to_string(meshes[j]->getID());
56 meshes[i]->setName(name + "--importID-" + id_str);
57 break;
58 }
59 }
60 }
61}
std::string getName(std::string const &line)
Returns the name/title from the "Zone"-description.

References getName().

Referenced by readFile().

◆ createElements()

template<typename ElementType>
bool FileIO::Gocad::GocadAsciiReader::createElements ( std::vector< std::array< std::size_t, ElementType::n_all_nodes > > const & element_data,
std::vector< MeshLib::Node * > const & nodes,
std::vector< MeshLib::Element * > & elems,
std::map< std::size_t, std::size_t > const & node_id_map )

Creates elements from parsed node ID tuples. All elements are constructed first and appended to elems only if every element could be created, i.e. elems is left unchanged on error. The number of nodes per element is taken from the element type.

Definition at line 443 of file GocadAsciiReader.cpp.

449{
450 std::size_t id = elems.size();
451 std::vector<std::unique_ptr<ElementType>> new_elems;
452 new_elems.reserve(element_data.size());
453 for (auto const& data : element_data)
454 {
455 std::array<MeshLib::Node*, ElementType::n_all_nodes> elem_nodes{};
456 for (auto&& [node_id, elem_node] : ranges::views::zip(data, elem_nodes))
457 {
458 auto const it = node_id_map.find(node_id);
459 if (it == node_id_map.end() || it->second >= nodes.size())
460 {
461 ERR("Error: Node ID ({:d}) out of range [0, {:d}).", node_id,
462 nodes.size());
463 return false;
464 }
465 elem_node = nodes[it->second];
466 }
467 new_elems.push_back(std::make_unique<ElementType>(elem_nodes, id++));
468 }
469
470 elems.reserve(elems.size() + new_elems.size());
471 ranges::transform(new_elems, std::back_inserter(elems),
472 [](auto& new_elem) { return new_elem.release(); });
473
474 return true;
475}

References ERR().

Referenced by parseAndCreateElements().

◆ createMesh()

template<typename T>
MeshLib::Mesh * FileIO::Gocad::GocadAsciiReader::createMesh ( std::ifstream & in,
DataType type,
std::string & mesh_name,
MeshLib::Properties & mesh_prop,
T parser,
bool const flip_elevation )

Converts parsed data into mesh.

Definition at line 618 of file GocadAsciiReader.cpp.

622{
623 std::vector<MeshLib::Node*> nodes;
624 std::vector<MeshLib::Element*> elems;
625 std::map<std::size_t, std::size_t> node_id_map;
626 INFO("Parsing {:s} {:s}.", dataType2ShortString(type), mesh_name);
627 bool return_val;
628 return_val = parser(in, nodes, elems, node_id_map, mesh_prop);
629
630 if (return_val)
631 {
632 if (flip_elevation)
633 {
634 std::for_each(nodes.begin(), nodes.end(),
635 [](MeshLib::Node* n) { (*n)[2] *= -1; });
636 }
637 return new MeshLib::Mesh(mesh_name, nodes, elems,
638 true /* compute_element_neighbors */,
639 mesh_prop);
640 }
641 ERR("Error parsing {:s} {:s}.", dataType2ShortString(type), mesh_name);
642 BaseLib::cleanupVectorElements(nodes, elems);
643 return nullptr;
644}
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void cleanupVectorElements(std::vector< T * > &items)
Definition Algorithm.h:274
std::string dataType2ShortString(DataType const t)
Given a Gocad DataType this returns the appropriate short form.

References BaseLib::cleanupVectorElements(), FileIO::Gocad::dataType2ShortString(), ERR(), and INFO().

Referenced by readData().

◆ createNode()

MeshLib::Node * FileIO::Gocad::GocadAsciiReader::createNode ( std::stringstream & sstr)

Definition at line 254 of file GocadAsciiReader.cpp.

255{
256 std::string keyword;
257 std::size_t id;
258 std::array<double, 3> data{};
259 sstr >> keyword >> id >> data[0] >> data[1] >> data[2];
260 return new MeshLib::Node(data, id);
261}

References MeshLib::Node.

Referenced by parseNodes().

◆ datasetFound()

DataType FileIO::Gocad::GocadAsciiReader::datasetFound ( std::ifstream & in)

Checks if a GoCAD data set begins at the current stream position.

Definition at line 92 of file GocadAsciiReader.cpp.

93{
94 std::string line;
95 while (std::getline(in, line))
96 {
97 if (line.empty() || isCommentLine(line))
98 {
99 continue;
100 }
101
102 if (isKeyword(DataType::VSET, line))
103 {
104 return DataType::VSET;
105 }
106 if (isKeyword(DataType::PLINE, line))
107 {
108 return DataType::PLINE;
109 }
110 if (isKeyword(DataType::TSURF, line))
111 {
112 return DataType::TSURF;
113 }
114 if (isKeyword(DataType::MODEL3D, line))
115 {
116 return DataType::MODEL3D;
117 }
118 ERR("No known identifier found...");
119 return DataType::UNDEFINED;
120 }
121 return DataType::UNDEFINED;
122}
bool isCommentLine(std::string const &str)
Checks if the current line is a comment.
bool isKeyword(DataType const t, std::string const &line)
Checks if current line is a designated keyword for a GoCAD data set.

References ERR(), isCommentLine(), isKeyword(), FileIO::Gocad::MODEL3D, FileIO::Gocad::PLINE, FileIO::Gocad::TSURF, FileIO::Gocad::UNDEFINED, and FileIO::Gocad::VSET.

Referenced by readFile().

◆ isCommentLine()

bool FileIO::Gocad::GocadAsciiReader::isCommentLine ( std::string const & str)

Checks if the current line is a comment.

Definition at line 64 of file GocadAsciiReader.cpp.

65{
66 return (str.substr(0, 1) == "#");
67}

Referenced by datasetFound(), parseNodeIdTuples(), parseNodes(), and readData().

◆ isKeyword()

bool FileIO::Gocad::GocadAsciiReader::isKeyword ( DataType const t,
std::string const & line )

Checks if current line is a designated keyword for a GoCAD data set.

Definition at line 85 of file GocadAsciiReader.cpp.

86{
87 std::size_t str_length = dataType2String(t).length();
88 return (line.substr(0, str_length) == dataType2String(t));
89}
std::string dataType2String(DataType const t)
Given a Gocad DataType this returns the appropriate string.

References FileIO::Gocad::dataType2String().

Referenced by datasetFound().

◆ parseAndCreateElements()

template<typename ElementType>
std::optional< std::size_t > FileIO::Gocad::GocadAsciiReader::parseAndCreateElements ( std::ifstream & in,
std::string_view const keyword,
std::vector< MeshLib::Node * > const & nodes,
std::vector< MeshLib::Element * > & elems,
std::map< std::size_t, std::size_t > const & node_id_map )

Parses the node ID tuples of all lines starting with keyword and creates the corresponding elements. Returns the number of created elements, or nothing on error, in which case elems is left unchanged.

Definition at line 481 of file GocadAsciiReader.cpp.

487{
488 auto const element_data =
490 if (!element_data)
491 {
492 return std::nullopt;
493 }
494 if (!createElements<ElementType>(*element_data, nodes, elems, node_id_map))
495 {
496 return std::nullopt;
497 }
498 return element_data->size();
499}
std::optional< std::vector< std::array< std::size_t, N > > > parseNodeIdTuples(std::ifstream &in, std::string_view const keyword)
bool createElements(std::vector< std::array< std::size_t, ElementType::n_all_nodes > > const &element_data, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &elems, std::map< std::size_t, std::size_t > const &node_id_map)

References createElements(), and parseNodeIdTuples().

Referenced by parseLine(), and parseSurface().

◆ parseAtomRegionIndicators()

bool FileIO::Gocad::GocadAsciiReader::parseAtomRegionIndicators ( std::ifstream & in)

parse Atom Region Indicator section for current TFACE (currently the information in this section is ignored)

Definition at line 265 of file GocadAsciiReader.cpp.

266{
267 std::string line;
268 while (std::getline(in, line))
269 {
270 if (line.substr(0, 26) == "END_ATOM_REGION_INDICATORS")
271 {
272 return true;
273 }
274 }
275 return false;
276}

Referenced by parseNodes().

◆ parseHeader()

bool FileIO::Gocad::GocadAsciiReader::parseHeader ( std::ifstream & in,
std::string & mesh_name )

Parses the HEADER section (everything except the name is ignored right now)

Definition at line 145 of file GocadAsciiReader.cpp.

146{
147 std::string line;
148 while (std::getline(in, line))
149 {
150 if (line.substr(0, 5) == "name:")
151 {
152 mesh_name = line.substr(5, line.length() - 5);
153 BaseLib::trim(mesh_name, ' ');
154 // replace chars that will prevent writing the file
155 std::replace(mesh_name.begin(), mesh_name.end(), '/', '-');
156 std::replace(mesh_name.begin(), mesh_name.end(), '\\', '-');
157 }
158 else if (line.substr(0, 1) == "}")
159 {
160 return true;
161 }
162 // ignore all other header parameters
163 }
164 ERR("{:s}", eof_error);
165 return false;
166}
void trim(std::string &str, char ch)

References eof_error, ERR(), and BaseLib::trim().

Referenced by readData().

◆ parseLine()

bool FileIO::Gocad::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 )

Parses line information (nodes, segments, properties)

Definition at line 528 of file GocadAsciiReader.cpp.

533{
534 if (!parseNodes(in, nodes, node_id_map, mesh_prop))
535 {
536 return false;
537 }
538 auto const n_elements = parseAndCreateElements<MeshLib::Line>(
539 in, "SEG", nodes, elems, node_id_map);
540 if (!n_elements || !appendSectionMaterialIds(mesh_prop, *n_elements))
541 {
542 return false;
543 }
544
545 std::string line;
546 while (std::getline(in, line))
547 {
548 std::vector<std::string> str = BaseLib::splitString(line);
549 if (str[0] == "ILINE")
550 {
551 parseLine(in, nodes, elems, node_id_map, mesh_prop);
552 return true;
553 }
554 if (line == "END")
555 {
556 return true;
557 }
558 WARN("GocadAsciiReader::parseLine() - Unknown keyword found: {:s}",
559 line);
560 }
561 ERR("{:s}", eof_error);
562 return false;
563}
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
std::vector< std::string > splitString(std::string const &str)
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 line information (nodes, segments, properties)
std::optional< std::size_t > parseAndCreateElements(std::ifstream &in, std::string_view const keyword, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &elems, std::map< std::size_t, std::size_t > const &node_id_map)
bool parseNodes(std::ifstream &in, std::vector< MeshLib::Node * > &nodes, std::map< std::size_t, std::size_t > &node_id_map, MeshLib::Properties const &mesh_prop)
Parses the node data for the current mesh.
bool appendSectionMaterialIds(MeshLib::Properties &mesh_prop, std::size_t const count)

References appendSectionMaterialIds(), eof_error, ERR(), parseAndCreateElements(), parseLine(), parseNodes(), BaseLib::splitString(), and WARN().

Referenced by parseLine(), and readData().

◆ parseNodeIdTuples()

template<std::size_t N>
std::optional< std::vector< std::array< std::size_t, N > > > FileIO::Gocad::GocadAsciiReader::parseNodeIdTuples ( std::ifstream & in,
std::string_view const keyword )

Parses the node ID tuples of all consecutive lines starting with keyword, e.g. the segments of a line ("SEG") or the triangles of a surface ("TRGL"). The stream is rewound to the first line that does not start with keyword. Returns std::nullopt if the file ended while parsing, or if a line does not carry the expected number of node IDs.

Definition at line 401 of file GocadAsciiReader.cpp.

403{
404 std::vector<std::array<std::size_t, N>> tuples;
405 std::streampos pos = in.tellg();
406 std::string line;
407 while (std::getline(in, line))
408 {
409 if (line.empty() || isCommentLine(line))
410 {
411 continue;
412 }
413 if (!line.starts_with(keyword))
414 {
415 in.seekg(pos);
416 return tuples;
417 }
418 std::stringstream sstr(line);
419 std::string parsed_keyword;
420 sstr >> parsed_keyword;
421 std::array<std::size_t, N> data{};
422 for (auto& node_id : data)
423 {
424 if (!(sstr >> node_id))
425 {
426 ERR("Error: Could not read {:d} node IDs of {:s} line: {:s}", N,
427 keyword, line);
428 return std::nullopt;
429 }
430 }
431 tuples.push_back(data);
432 pos = in.tellg();
433 }
434 ERR("{:s}", eof_error);
435 return std::nullopt;
436}

References eof_error, ERR(), and isCommentLine().

Referenced by parseAndCreateElements().

◆ parseNodes()

bool FileIO::Gocad::GocadAsciiReader::parseNodes ( std::ifstream & in,
std::vector< MeshLib::Node * > & nodes,
std::map< std::size_t, std::size_t > & node_id_map,
MeshLib::Properties const & mesh_prop )

Parses the node data for the current mesh.

Definition at line 287 of file GocadAsciiReader.cpp.

291{
292 // The buffers follow the iteration over mesh_prop, which is ordered by
293 // property name, while the values of a PVRTX line follow the order of the
294 // PROPERTIES declaration. Zipping the two below therefore assumes that
295 // declaration to be in alphabetical order.
296 std::vector<PropertyBuffer> property_buffers;
297 for (auto const& [name, property] : mesh_prop)
298 {
299 if (name == mat_id_name)
300 {
301 continue;
302 }
303 if (auto* const p =
304 dynamic_cast<MeshLib::PropertyVector<double>*>(property))
305 {
306 property_buffers.push_back({{}, p});
307 }
308 }
309 // Appends the buffered values of this section to the values of the already
310 // parsed sections with a single bulk write per property.
311 auto const append_property_buffers = [&property_buffers]()
312 {
313 for (auto& buffer : property_buffers)
314 {
315 MeshLib::appendValues(*buffer.property, buffer.values);
316 }
317 };
318
320 std::streampos pos = in.tellg();
321 std::string line;
322 while (std::getline(in, line))
323 {
324 std::vector<std::string> str = BaseLib::splitString(line);
325 if (line.substr(0, 3) == "SEG" || line.substr(0, 4) == "TRGL")
326 {
327 in.seekg(pos);
328 append_property_buffers();
329 return true;
330 }
331
332 if (line.substr(0, 28) == "BEGIN_ATOM_REGION_INDICATORS")
333 {
335 {
336 ERR("File ended while parsing Atom Region Indicators...");
337 return false;
338 }
339 append_property_buffers();
340 return true;
341 }
342
343 if (line.empty() || isCommentLine(line))
344 {
345 continue;
346 }
347 if (!(line.substr(0, 4) == "VRTX" || line.substr(0, 5) == "PVRTX" ||
348 line.substr(0, 4) == "ATOM"))
349 {
350 WARN("GocadAsciiReader::parseNodes() - Unknown keyword found: {:s}",
351 line);
352 continue;
353 }
354
355 std::stringstream sstr(line);
356 if (line.substr(0, 4) == "VRTX" && t != NodeType::PVRTX)
357 {
358 t = NodeType::VRTX;
359 nodes.push_back(createNode(sstr));
360 }
361 else if (line.substr(0, 5) == "PVRTX" && t != NodeType::VRTX)
362 {
363 t = NodeType::PVRTX;
364 nodes.push_back(createNode(sstr));
365 for (auto& buffer : property_buffers)
366 {
367 // property_buffers only holds PropertyVector<double> entries,
368 // so reading a double per column is safe here.
369 double value;
370 if (!(sstr >> value))
371 {
372 ERR("Error: Could not read the value of property '{:s}' "
373 "of PVRTX line: {:s}",
374 buffer.property->getPropertyName(), line);
375 return false;
376 }
377 buffer.values.push_back(value);
378 }
379 }
380 else if (line.substr(0, 4) == "ATOM")
381 {
382 std::size_t new_id;
383 std::size_t ref_id;
384 std::string keyword;
385 sstr >> keyword >> new_id >> ref_id;
386 nodes.push_back(new MeshLib::Node(nodes[ref_id]->data(), new_id));
387 }
388 node_id_map[nodes.back()->getID()] = nodes.size() - 1;
389 pos = in.tellg();
390 }
391 ERR("{:s}", eof_error);
392 return false;
393}
bool parseAtomRegionIndicators(std::ifstream &in)
MeshLib::Node * createNode(std::stringstream &sstr)
constexpr void appendValues(PropertyVector< T > &property, R &&values)

References MeshLib::appendValues(), createNode(), eof_error, ERR(), isCommentLine(), mat_id_name, parseAtomRegionIndicators(), PVRTX, BaseLib::splitString(), UNSPECIFIED, VRTX, and WARN().

Referenced by parseLine(), and parseSurface().

◆ parseProperties()

bool FileIO::Gocad::GocadAsciiReader::parseProperties ( std::ifstream & in,
std::vector< std::string > const & names,
MeshLib::Properties & mesh_prop )

Parses information of node properties. Only property names and array sizes are currently used.

Definition at line 203 of file GocadAsciiReader.cpp.

206{
207 // Because properties have no end-tag, the position of the last line is
208 // stored, so the stream can be set back if none of the allowed property-
209 // related keywords is found.
210 std::streampos pos = in.tellg();
211 std::string line;
212 while (std::getline(in, line))
213 {
214 std::string const key = propertyCheck(line);
215 // This is the intended way to exit this method:
216 // No property-related keyword has been found, so the stream is set
217 // back one line and the (unrelated) keyword can be read again in the
218 // parent method.
219 if (key.empty())
220 {
221 in.seekg(pos);
222 return true;
223 }
224
225 // Currently all property parameters except array name and size are
226 // ignored.
227 if (key == "ESIZES")
228 {
229 std::vector<std::string> prop_size = BaseLib::splitString(line);
230
231 if (names.size() != prop_size.size())
232 {
233 ERR("Error: Number of PROPERTY-names ({:d}) does not match "
234 "number of ESIZES ({:d})",
235 names.size(), prop_size.size());
236 return false;
237 }
238 std::size_t const n_names(names.size());
239 for (std::size_t i = 1; i < n_names; ++i)
240 {
241 mesh_prop.createNewPropertyVector<double>(
242 names[i],
245 }
246 }
247 // Remember current position in case the properties black ends now.
248 pos = in.tellg();
249 }
250 ERR("{:s}", eof_error);
251 return false;
252}
PropertyVector< T > * createNewPropertyVector(std::string_view name, MeshItemType mesh_item_type, std::size_t n_components=1)
T str2number(const std::string &str)
Definition StringTools.h:54
std::string propertyCheck(std::string const &string)
Checks if the current line starts with one of the allowed keywords.

References MeshLib::Properties::createNewPropertyVector(), eof_error, ERR(), MeshLib::Node, propertyCheck(), BaseLib::splitString(), and BaseLib::str2number().

Referenced by readData().

◆ parsePropertyClass()

bool FileIO::Gocad::GocadAsciiReader::parsePropertyClass ( std::ifstream & in)

Reads PROPERTY_CLASS_HEADER sections of the file. All this information is currently ignored.

Definition at line 170 of file GocadAsciiReader.cpp.

171{
172 std::string line;
173 while (std::getline(in, line))
174 {
175 if (line.substr(0, 1) == "}")
176 {
177 return true;
178 }
179 }
180 ERR("{:s}", eof_error);
181 return false;
182}

References eof_error, and ERR().

Referenced by readData().

◆ parseSurface()

bool FileIO::Gocad::GocadAsciiReader::parseSurface ( 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)

Definition at line 566 of file GocadAsciiReader.cpp.

571{
572 if (!parseNodes(in, nodes, node_id_map, mesh_prop))
573 {
574 return false;
575 }
576 auto const n_elements = parseAndCreateElements<MeshLib::Tri>(
577 in, "TRGL", nodes, elems, node_id_map);
578 if (!n_elements || !appendSectionMaterialIds(mesh_prop, *n_elements))
579 {
580 return false;
581 }
582
583 std::string line;
584 while (std::getline(in, line))
585 {
586 std::vector<std::string> str = BaseLib::splitString(line);
587 if (str[0] == "TFACE" || str[0] == "3DFace")
588 {
589 parseSurface(in, nodes, elems, node_id_map, mesh_prop);
590 return true;
591 }
592 if (str[0] == "BSTONE")
593 {
594 // borderstone definition - currently ignored
595 }
596 else if (str[0] == "BORDER")
597 {
598 // border tracking direction - currently ignored
599 }
600 else if (line == "END")
601 {
602 return true;
603 }
604 else
605 {
606 WARN(
607 "GocadAsciiReader::parseSurface() - Unknown keyword found: "
608 "{:s}",
609 line);
610 }
611 }
612 ERR("{:s}", eof_error);
613 return false;
614}
bool parseSurface(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)

References appendSectionMaterialIds(), eof_error, ERR(), parseAndCreateElements(), parseNodes(), parseSurface(), BaseLib::splitString(), and WARN().

Referenced by parseSurface(), and readData().

◆ propertyCheck()

std::string FileIO::Gocad::GocadAsciiReader::propertyCheck ( std::string const & string)

Checks if the current line starts with one of the allowed keywords.

Definition at line 185 of file GocadAsciiReader.cpp.

186{
187 std::array<std::string, 7> const property_keywords = {
188 {"PROPERTY_CLASSES", "PROP_LEGAL_RANGES", "NO_DATA_VALUES",
189 "PROPERTY_KINDS", "PROPERTY_SUBCLASSES", "UNITS", "ESIZES"}};
190
191 std::string const str = BaseLib::splitString(string)[0];
192 auto res =
193 std::find(property_keywords.begin(), property_keywords.end(), str);
194 if (res != property_keywords.end())
195 {
196 return *res;
197 }
198 return std::string("");
199}

References BaseLib::splitString().

Referenced by parseProperties().

◆ readData()

MeshLib::Mesh * FileIO::Gocad::GocadAsciiReader::readData ( std::ifstream & in,
DataType const & type,
std::string & mesh_name )

Reads one mesh contained in the file (there may be more than one!)

Definition at line 647 of file GocadAsciiReader.cpp.

650{
651 if (!parseHeader(in, mesh_name))
652 {
653 return nullptr;
654 }
655
656 MeshLib::Properties mesh_prop;
659 bool flip_elevation = false;
660 std::string line;
661 while (std::getline(in, line))
662 {
663 std::vector<std::string> str = BaseLib::splitString(line);
664 if (line.empty() || isCommentLine(line))
665 {
666 continue;
667 }
668 if (str[0] == "GOCAD_ORIGINAL_COORDINATE_SYSTEM")
669 {
670 CoordinateSystem coordinate_system;
671 if (!coordinate_system.parse(in))
672 {
673 ERR("Error parsing coordinate system.");
674 return nullptr;
675 }
676 flip_elevation = (coordinate_system.z_positive ==
678 }
679 else if (str[0] == "GEOLOGICAL_FEATURE" ||
680 str[0] == "GEOLOGICAL_TYPE" ||
681 str[0] == "STRATIGRAPHIC_POSITION" || str[0] == "REGION")
682 {
683 // geological and stratigraphic information - currently ignored
684 }
685 else if (str[0] == "PROPERTY_CLASS_HEADER")
686 {
687 if (!parsePropertyClass(in))
688 {
689 ERR("Error parsing PROPERTY_CLASS_HEADER.");
690 return nullptr;
691 }
692 }
693 else if (str[0] == "PROPERTIES")
694 {
695 if (!parseProperties(in, str, mesh_prop))
696 {
697 ERR("Error parsing PROPERTIES");
698 return nullptr;
699 }
700 }
701 else if (type == DataType::PLINE && str[0] == "ILINE")
702 {
703 return createMesh(in, type, mesh_name, mesh_prop, parseLine,
704 flip_elevation);
705 }
706 else if (type == DataType::TSURF &&
707 (str[0] == "TFACE" || str[0] == "3DFace"))
708 {
709 return createMesh(in, type, mesh_name, mesh_prop, parseSurface,
710 flip_elevation);
711 }
712 else
713 {
714 WARN("GocadAsciiReader::readData() - Unknown keyword found: {:s}",
715 line);
716 }
717 }
718 ERR("{:s}", eof_error);
719 return nullptr;
720}
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
bool parseHeader(std::ifstream &in, std::string &mesh_name)
Parses the HEADER section (everything except the name is ignored right now)
bool parsePropertyClass(std::ifstream &in)
bool parseProperties(std::ifstream &in, std::vector< std::string > const &names, MeshLib::Properties &mesh_prop)
MeshLib::Mesh * createMesh(std::ifstream &in, DataType type, std::string &mesh_name, MeshLib::Properties &mesh_prop, T parser, bool const flip_elevation)
Converts parsed data into mesh.

References MeshLib::Cell, createMesh(), MeshLib::Properties::createNewPropertyVector(), FileIO::Gocad::CoordinateSystem::Depth, eof_error, ERR(), isCommentLine(), mat_id_name, FileIO::Gocad::CoordinateSystem::parse(), parseHeader(), parseLine(), parseProperties(), parsePropertyClass(), parseSurface(), FileIO::Gocad::PLINE, BaseLib::splitString(), FileIO::Gocad::TSURF, WARN(), and FileIO::Gocad::CoordinateSystem::z_positive.

Referenced by readFile().

◆ readFile()

bool FileIO::Gocad::GocadAsciiReader::readFile ( std::string const & file_name,
std::vector< std::unique_ptr< MeshLib::Mesh > > & meshes,
DataType const export_type )

Reads the specified file and writes data into internal mesh vector.

Definition at line 722 of file GocadAsciiReader.cpp.

725{
726 std::ifstream in(file_name);
727 if (!in.is_open())
728 {
729 ERR("GocadAsciiReader::readFile(): Could not open file {:s}.",
730 file_name);
731 return false;
732 }
733
734 checkLineEndings(file_name);
735
736 DataType type;
737 while ((type = datasetFound(in)) != DataType::UNDEFINED)
738 {
739 if (export_type != DataType::ALL && type != export_type)
740 {
741 skipToEND(in);
742 continue;
743 }
744
745 if (type == DataType::VSET || type == DataType::MODEL3D)
746 {
747 if (!skipToEND(in))
748 {
749 ERR("Parsing of type {:s} is not implemented. Skipping "
750 "section.",
751 dataType2String(type));
752 return false;
753 }
754 continue;
755 }
756
757 std::string mesh_name = BaseLib::dropFileExtension(file_name) +
758 std::to_string(meshes.size() + 1);
759 std::unique_ptr<MeshLib::Mesh> mesh(readData(in, type, mesh_name));
760 if (mesh == nullptr)
761 {
762 ERR("File parsing aborted...");
763 return false;
764 }
765 meshes.push_back(std::move(mesh));
766 }
767 checkMeshNames(meshes);
768 return true;
769}
std::string dropFileExtension(std::string const &filename)
void checkLineEndings(std::string const &file_name)
Checks if current line is a designated keyword for a GoCAD data set.
bool skipToEND(std::ifstream &in)
Parses current section until END-tag is reached.
void checkMeshNames(std::vector< std::unique_ptr< MeshLib::Mesh > > const &meshes)
MeshLib::Mesh * readData(std::ifstream &in, DataType const &type, std::string &mesh_name)
Reads one mesh contained in the file (there may be more than one!)
DataType datasetFound(std::ifstream &in)
Checks if a GoCAD data set begins at the current stream position.

References FileIO::Gocad::ALL, checkLineEndings(), checkMeshNames(), datasetFound(), FileIO::Gocad::dataType2String(), BaseLib::dropFileExtension(), ERR(), FileIO::Gocad::MODEL3D, readData(), skipToEND(), FileIO::Gocad::UNDEFINED, and FileIO::Gocad::VSET.

Referenced by MainWindow::loadFile(), and main().

◆ skipToEND()

bool FileIO::Gocad::GocadAsciiReader::skipToEND ( std::ifstream & in)

Parses current section until END-tag is reached.

Definition at line 70 of file GocadAsciiReader.cpp.

71{
72 std::string line;
73 while (std::getline(in, line))
74 {
75 if (line == "END")
76 {
77 return true;
78 }
79 }
80 ERR("{:s}", eof_error);
81 return false;
82}

References eof_error, and ERR().

Referenced by readFile().

Variable Documentation

◆ eof_error

const std::string FileIO::Gocad::GocadAsciiReader::eof_error = "Error: Unexpected end of file."

◆ mat_id_name

const std::string FileIO::Gocad::GocadAsciiReader::mat_id_name = "MaterialIDs"

Definition at line 39 of file GocadAsciiReader.cpp.

Referenced by appendSectionMaterialIds(), parseNodes(), and readData().