11#include <range/v3/algorithm/transform.hpp>
12#include <range/v3/view/zip.hpp>
40const std::string
eof_error =
"Error: Unexpected end of file.";
45void checkMeshNames(std::vector<std::unique_ptr<MeshLib::Mesh>>
const& meshes)
47 std::size_t
const n_meshes = meshes.size();
48 for (std::size_t i = 0; i < n_meshes; ++i)
50 std::string
const& name = meshes[i]->getName();
51 for (std::size_t j = i + 1; j < n_meshes; ++j)
53 if (meshes[j]->
getName() == name)
55 std::string
const id_str = std::to_string(meshes[j]->getID());
56 meshes[i]->setName(name +
"--importID-" + id_str);
66 return (str.substr(0, 1) ==
"#");
73 while (std::getline(in, line))
95 while (std::getline(in, line))
118 ERR(
"No known identifier found...");
127 std::ifstream in(file_name);
131 std::getline(in, line);
132 if (line.back() ==
'\r')
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).",
148 while (std::getline(in, line))
150 if (line.substr(0, 5) ==
"name:")
152 mesh_name = line.substr(5, line.length() - 5);
155 std::replace(mesh_name.begin(), mesh_name.end(),
'/',
'-');
156 std::replace(mesh_name.begin(), mesh_name.end(),
'\\',
'-');
158 else if (line.substr(0, 1) ==
"}")
173 while (std::getline(in, line))
175 if (line.substr(0, 1) ==
"}")
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"}};
193 std::find(property_keywords.begin(), property_keywords.end(), str);
194 if (res != property_keywords.end())
198 return std::string(
"");
204 std::vector<std::string>
const& names,
210 std::streampos pos = in.tellg();
212 while (std::getline(in, line))
231 if (names.size() != prop_size.size())
233 ERR(
"Error: Number of PROPERTY-names ({:d}) does not match "
234 "number of ESIZES ({:d})",
235 names.size(), prop_size.size());
238 std::size_t
const n_names(names.size());
239 for (std::size_t i = 1; i < n_names; ++i)
258 std::array<double, 3> data{};
259 sstr >> keyword >>
id >> data[0] >> data[1] >> data[2];
268 while (std::getline(in, line))
270 if (line.substr(0, 26) ==
"END_ATOM_REGION_INDICATORS")
288 std::vector<MeshLib::Node*>& nodes,
289 std::map<std::size_t, std::size_t>& node_id_map,
296 std::vector<PropertyBuffer> property_buffers;
297 for (
auto const& [name, property] : mesh_prop)
306 property_buffers.push_back({{}, p});
311 auto const append_property_buffers = [&property_buffers]()
313 for (
auto& buffer : property_buffers)
320 std::streampos pos = in.tellg();
322 while (std::getline(in, line))
325 if (line.substr(0, 3) ==
"SEG" || line.substr(0, 4) ==
"TRGL")
328 append_property_buffers();
332 if (line.substr(0, 28) ==
"BEGIN_ATOM_REGION_INDICATORS")
336 ERR(
"File ended while parsing Atom Region Indicators...");
339 append_property_buffers();
347 if (!(line.substr(0, 4) ==
"VRTX" || line.substr(0, 5) ==
"PVRTX" ||
348 line.substr(0, 4) ==
"ATOM"))
350 WARN(
"GocadAsciiReader::parseNodes() - Unknown keyword found: {:s}",
355 std::stringstream sstr(line);
365 for (
auto& buffer : property_buffers)
370 if (!(sstr >> value))
372 ERR(
"Error: Could not read the value of property '{:s}' "
373 "of PVRTX line: {:s}",
374 buffer.property->getPropertyName(), line);
377 buffer.values.push_back(value);
380 else if (line.substr(0, 4) ==
"ATOM")
385 sstr >> keyword >> new_id >> ref_id;
386 nodes.push_back(
new MeshLib::Node(nodes[ref_id]->data(), new_id));
388 node_id_map[nodes.back()->getID()] = nodes.size() - 1;
400template <std::
size_t N>
402 std::ifstream& in, std::string_view
const keyword)
404 std::vector<std::array<std::size_t, N>> tuples;
405 std::streampos pos = in.tellg();
407 while (std::getline(in, line))
413 if (!line.starts_with(keyword))
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)
424 if (!(sstr >> node_id))
426 ERR(
"Error: Could not read {:d} node IDs of {:s} line: {:s}", N,
431 tuples.push_back(data);
442template <
typename ElementType>
444 std::vector<std::array<std::size_t, ElementType::n_all_nodes>>
const&
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)
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)
455 std::array<MeshLib::Node*, ElementType::n_all_nodes> elem_nodes{};
456 for (
auto&& [node_id, elem_node] : ranges::views::zip(data, elem_nodes))
458 auto const it = node_id_map.find(node_id);
459 if (it == node_id_map.end() || it->second >= nodes.size())
461 ERR(
"Error: Node ID ({:d}) out of range [0, {:d}).", node_id,
465 elem_node = nodes[it->second];
467 new_elems.push_back(std::make_unique<ElementType>(elem_nodes,
id++));
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(); });
480template <
typename ElementType>
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)
488 auto const element_data =
498 return element_data->size();
514 std::size_t
const count)
517 if (mat_ids ==
nullptr)
519 ERR(
"GocadAsciiReader: Property vector '{:s}' not found.",
mat_id_name);
522 mat_ids->
resize(mat_ids->size() + count,
529 std::vector<MeshLib::Node*>& nodes,
530 std::vector<MeshLib::Element*>& elems,
531 std::map<std::size_t, std::size_t>& node_id_map,
534 if (!
parseNodes(in, nodes, node_id_map, mesh_prop))
539 in,
"SEG", nodes, elems, node_id_map);
546 while (std::getline(in, line))
549 if (str[0] ==
"ILINE")
551 parseLine(in, nodes, elems, node_id_map, mesh_prop);
558 WARN(
"GocadAsciiReader::parseLine() - Unknown keyword found: {:s}",
567 std::vector<MeshLib::Node*>& nodes,
568 std::vector<MeshLib::Element*>& elems,
569 std::map<std::size_t, std::size_t>& node_id_map,
572 if (!
parseNodes(in, nodes, node_id_map, mesh_prop))
577 in,
"TRGL", nodes, elems, node_id_map);
584 while (std::getline(in, line))
587 if (str[0] ==
"TFACE" || str[0] ==
"3DFace")
592 if (str[0] ==
"BSTONE")
596 else if (str[0] ==
"BORDER")
600 else if (line ==
"END")
607 "GocadAsciiReader::parseSurface() - Unknown keyword found: "
619 std::string& mesh_name,
621 bool const flip_elevation)
623 std::vector<MeshLib::Node*> nodes;
624 std::vector<MeshLib::Element*> elems;
625 std::map<std::size_t, std::size_t> node_id_map;
628 return_val = parser(in, nodes, elems, node_id_map, mesh_prop);
634 std::for_each(nodes.begin(), nodes.end(),
649 std::string& mesh_name)
659 bool flip_elevation =
false;
661 while (std::getline(in, line))
668 if (str[0] ==
"GOCAD_ORIGINAL_COORDINATE_SYSTEM")
671 if (!coordinate_system.
parse(in))
673 ERR(
"Error parsing coordinate system.");
676 flip_elevation = (coordinate_system.
z_positive ==
679 else if (str[0] ==
"GEOLOGICAL_FEATURE" ||
680 str[0] ==
"GEOLOGICAL_TYPE" ||
681 str[0] ==
"STRATIGRAPHIC_POSITION" || str[0] ==
"REGION")
685 else if (str[0] ==
"PROPERTY_CLASS_HEADER")
689 ERR(
"Error parsing PROPERTY_CLASS_HEADER.");
693 else if (str[0] ==
"PROPERTIES")
697 ERR(
"Error parsing PROPERTIES");
707 (str[0] ==
"TFACE" || str[0] ==
"3DFace"))
714 WARN(
"GocadAsciiReader::readData() - Unknown keyword found: {:s}",
723 std::vector<std::unique_ptr<MeshLib::Mesh>>& meshes,
726 std::ifstream in(file_name);
729 ERR(
"GocadAsciiReader::readFile(): Could not open file {:s}.",
749 ERR(
"Parsing of type {:s} is not implemented. Skipping "
758 std::to_string(meshes.size() + 1);
759 std::unique_ptr<MeshLib::Mesh> mesh(
readData(in, type, mesh_name));
762 ERR(
"File parsing aborted...");
765 meshes.push_back(std::move(mesh));
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
bool parse(std::istream &in)
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)
std::string dropFileExtension(std::string const &filename)
std::vector< std::string > splitString(std::string const &str)
T str2number(const std::string &str)
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)
const std::string mat_id_name
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)
const std::string eof_error
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
std::vector< double > values