OGS
GocadAsciiReader.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "GocadAsciiReader.h"
5
6#include <algorithm>
7#include <fstream>
8#include <iterator>
9#include <memory>
10#include <optional>
11#include <range/v3/algorithm/transform.hpp>
12#include <range/v3/view/zip.hpp>
13#include <string_view>
14
16#include "BaseLib/FileTools.h"
17#include "BaseLib/Logging.h"
18#include "BaseLib/StringTools.h"
21#include "MeshLib/Mesh.h"
22#include "MeshLib/Node.h"
23#include "MeshLib/Properties.h"
25
26namespace FileIO
27{
28namespace Gocad
29{
31{
38
39const std::string mat_id_name = "MaterialIDs";
40const std::string eof_error = "Error: Unexpected end of file.";
41
45void checkMeshNames(std::vector<std::unique_ptr<MeshLib::Mesh>> const& meshes)
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}
62
64bool isCommentLine(std::string const& str)
65{
66 return (str.substr(0, 1) == "#");
67}
68
70bool skipToEND(std::ifstream& in)
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}
83
85bool isKeyword(DataType const t, std::string const& line)
86{
87 std::size_t str_length = dataType2String(t).length();
88 return (line.substr(0, str_length) == dataType2String(t));
89}
90
92DataType datasetFound(std::ifstream& in)
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}
123
124void checkLineEndings(std::string const& file_name)
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}
143
145bool parseHeader(std::ifstream& in, std::string& mesh_name)
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}
167
170bool parsePropertyClass(std::ifstream& in)
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}
183
185std::string propertyCheck(std::string const& string)
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}
200
203bool parseProperties(std::ifstream& in,
204 std::vector<std::string> const& names,
205 MeshLib::Properties& mesh_prop)
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}
253
254MeshLib::Node* createNode(std::stringstream& sstr)
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}
262
265bool parseAtomRegionIndicators(std::ifstream& in)
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}
277
285
287bool parseNodes(std::ifstream& in,
288 std::vector<MeshLib::Node*>& nodes,
289 std::map<std::size_t, std::size_t>& node_id_map,
290 MeshLib::Properties const& mesh_prop)
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}
394
400template <std::size_t N>
401std::optional<std::vector<std::array<std::size_t, N>>> parseNodeIdTuples(
402 std::ifstream& in, std::string_view const keyword)
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}
437
442template <typename ElementType>
444 std::vector<std::array<std::size_t, ElementType::n_all_nodes>> const&
445 element_data,
446 std::vector<MeshLib::Node*> const& nodes,
447 std::vector<MeshLib::Element*>& elems,
448 std::map<std::size_t, std::size_t> const& node_id_map)
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}
476
480template <typename ElementType>
481std::optional<std::size_t> parseAndCreateElements(
482 std::ifstream& in,
483 std::string_view const keyword,
484 std::vector<MeshLib::Node*> const& nodes,
485 std::vector<MeshLib::Element*>& elems,
486 std::map<std::size_t, std::size_t> const& node_id_map)
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}
500
514 std::size_t const count)
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}
526
528bool parseLine(std::ifstream& in,
529 std::vector<MeshLib::Node*>& nodes,
530 std::vector<MeshLib::Element*>& elems,
531 std::map<std::size_t, std::size_t>& node_id_map,
532 MeshLib::Properties& mesh_prop)
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}
564
566bool parseSurface(std::ifstream& in,
567 std::vector<MeshLib::Node*>& nodes,
568 std::vector<MeshLib::Element*>& elems,
569 std::map<std::size_t, std::size_t>& node_id_map,
570 MeshLib::Properties& mesh_prop)
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}
615
617template <typename T>
618MeshLib::Mesh* createMesh(std::ifstream& in, DataType type,
619 std::string& mesh_name,
620 MeshLib::Properties& mesh_prop, T parser,
621 bool const flip_elevation)
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}
645
647MeshLib::Mesh* readData(std::ifstream& in,
648 DataType const& type,
649 std::string& mesh_name)
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}
721
722bool readFile(std::string const& file_name,
723 std::vector<std::unique_ptr<MeshLib::Mesh>>& meshes,
724 DataType const export_type)
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}
770
771} // namespace GocadAsciiReader
772} // end namespace Gocad
773} // end namespace FileIO
#define OGS_FATAL(...)
Definition Error.h:10
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
std::string getName(std::string const &line)
Returns the name/title from the "Zone"-description.
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
PropertyVector< T > * createNewPropertyVector(std::string_view name, MeshItemType mesh_item_type, std::size_t n_components=1)
PropertyVector< T > const * getPropertyVector(std::string_view name) const
constexpr void resize(std::size_t const size)
void trim(std::string &str, char ch)
void cleanupVectorElements(std::vector< T * > &items)
Definition Algorithm.h:274
std::string dropFileExtension(std::string const &filename)
std::vector< std::string > splitString(std::string const &str)
T str2number(const std::string &str)
Definition StringTools.h:54
std::optional< std::vector< std::array< std::size_t, N > > > parseNodeIdTuples(std::ifstream &in, std::string_view const keyword)
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 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 parsePropertyClass(std::ifstream &in)
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.
void checkMeshNames(std::vector< std::unique_ptr< MeshLib::Mesh > > const &meshes)
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 parseAtomRegionIndicators(std::ifstream &in)
bool 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.
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::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!)
bool appendSectionMaterialIds(MeshLib::Properties &mesh_prop, std::size_t const count)
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.
DataType datasetFound(std::ifstream &in)
Checks if a GoCAD data set begins at the current stream position.
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)
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)
MeshLib::Node * createNode(std::stringstream &sstr)
std::string dataType2String(DataType const t)
Given a Gocad DataType this returns the appropriate string.
std::string dataType2ShortString(DataType const t)
Given a Gocad DataType this returns the appropriate short form.
constexpr void appendValues(PropertyVector< T > &property, R &&values)
int nextUnusedMaterialId(PropertyVector< int > const &material_ids)
MeshLib::PropertyVector< double > * property