|
@@ -1,514 +1,211 @@
|
|
|
|
|
+/* high level interface for MshLoader */
|
|
|
|
|
+
|
|
|
|
|
+/* Copyright (C) 2020 Vladimir Fonov <[email protected]> */
|
|
|
|
|
+/*
|
|
|
|
|
+/* This Source Code Form is subject to the terms of the Mozilla */
|
|
|
|
|
+/* Public License v. 2.0. If a copy of the MPL was not distributed */
|
|
|
|
|
+/* with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
-// This file is part of libigl, a simple c++ geometry processing library.
|
|
|
|
|
-//
|
|
|
|
|
-// Copyright (C) 2018 Alec Jacobson <[email protected]>
|
|
|
|
|
-//
|
|
|
|
|
-// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
|
|
|
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
|
|
|
-// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
-//
|
|
|
|
|
#include "readMSH.h"
|
|
#include "readMSH.h"
|
|
|
|
|
+#include "MshLoader.h"
|
|
|
#include <iostream>
|
|
#include <iostream>
|
|
|
-#include <sstream>
|
|
|
|
|
-#include <fstream>
|
|
|
|
|
-#include <vector>
|
|
|
|
|
-#include <map>
|
|
|
|
|
|
|
|
|
|
-template <
|
|
|
|
|
- typename DerivedV,
|
|
|
|
|
- typename DerivedT>
|
|
|
|
|
-IGL_INLINE bool igl::readMSH(
|
|
|
|
|
- const std::string & filename,
|
|
|
|
|
- Eigen::PlainObjectBase<DerivedV> & V,
|
|
|
|
|
- Eigen::PlainObjectBase<DerivedT> & T)
|
|
|
|
|
|
|
+IGL_INLINE bool igl::readMSH(const std::string &msh,
|
|
|
|
|
+ Eigen::MatrixXd &X,
|
|
|
|
|
+ Eigen::MatrixXi &Tri,
|
|
|
|
|
+ Eigen::MatrixXi &Tet,
|
|
|
|
|
+ Eigen::VectorXi &TriTag,
|
|
|
|
|
+ Eigen::VectorXi &TetTag,
|
|
|
|
|
+ std::vector<std::string> &XFields,
|
|
|
|
|
+ std::vector<Eigen::MatrixXd> &XF,
|
|
|
|
|
+ std::vector<std::string> &EFields,
|
|
|
|
|
+ std::vector<Eigen::MatrixXd> &TriF,
|
|
|
|
|
+ std::vector<Eigen::MatrixXd> &TetF
|
|
|
|
|
+ )
|
|
|
{
|
|
{
|
|
|
- // https://github.com/Yixin-Hu/TetWild/blob/master/pymesh/MshSaver.cpp
|
|
|
|
|
- // Original copyright: /* This file is part of PyMesh. Copyright (c) 2015 by Qingnan Zhou */
|
|
|
|
|
- typedef typename DerivedV::Scalar Float;
|
|
|
|
|
- typedef Eigen::Matrix<Float,Eigen::Dynamic,1> VectorF;
|
|
|
|
|
- typedef Eigen::Matrix<int,Eigen::Dynamic,1> VectorI;
|
|
|
|
|
- typedef std::map<std::string, VectorF> FieldMap;
|
|
|
|
|
- typedef std::vector<std::string> FieldNames;
|
|
|
|
|
- VectorF m_nodes;
|
|
|
|
|
- VectorI m_elements;
|
|
|
|
|
- FieldMap m_node_fields;
|
|
|
|
|
- FieldMap m_element_fields;
|
|
|
|
|
-
|
|
|
|
|
- bool m_binary;
|
|
|
|
|
- size_t m_data_size;
|
|
|
|
|
- size_t m_nodes_per_element;
|
|
|
|
|
- size_t m_element_type;
|
|
|
|
|
- std::ifstream fin(filename.c_str(), std::ios::in | std::ios::binary);
|
|
|
|
|
- if (!fin.is_open())
|
|
|
|
|
- {
|
|
|
|
|
- std::stringstream err_msg;
|
|
|
|
|
- err_msg << "failed to open file \"" << filename << "\"";
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- // Parse header
|
|
|
|
|
- std::string buf;
|
|
|
|
|
- double version;
|
|
|
|
|
- int type;
|
|
|
|
|
- fin >> buf;
|
|
|
|
|
- const auto invalid_format = []()->bool
|
|
|
|
|
- {
|
|
|
|
|
- assert(false && "Invalid format");
|
|
|
|
|
- return false;
|
|
|
|
|
- };
|
|
|
|
|
- const auto not_implemented = []()->bool
|
|
|
|
|
- {
|
|
|
|
|
- assert(false && "Not implemented");
|
|
|
|
|
- return false;
|
|
|
|
|
- };
|
|
|
|
|
- if (buf != "$MeshFormat") { return invalid_format(); }
|
|
|
|
|
-
|
|
|
|
|
- fin >> version >> type >> m_data_size;
|
|
|
|
|
- m_binary = (type == 1);
|
|
|
|
|
-
|
|
|
|
|
- // Some sanity check.
|
|
|
|
|
- if (m_data_size != 8) {
|
|
|
|
|
- std::cerr << "Error: data size must be 8 bytes." << std::endl;
|
|
|
|
|
- return not_implemented();
|
|
|
|
|
- }
|
|
|
|
|
- if (sizeof(int) != 4) {
|
|
|
|
|
- std::cerr << "Error: code must be compiled with int size 4 bytes." << std::endl;
|
|
|
|
|
- return not_implemented();
|
|
|
|
|
- }
|
|
|
|
|
- const auto eat_white_space = [](std::ifstream& fin)
|
|
|
|
|
- {
|
|
|
|
|
- char next = fin.peek();
|
|
|
|
|
- while (next == '\n' || next == ' ' || next == '\t' || next == '\r')
|
|
|
|
|
|
|
+ try
|
|
|
{
|
|
{
|
|
|
- fin.get();
|
|
|
|
|
- next = fin.peek();
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- // Read in extra info from binary header.
|
|
|
|
|
- if (m_binary) {
|
|
|
|
|
- int one;
|
|
|
|
|
- eat_white_space(fin);
|
|
|
|
|
- fin.read(reinterpret_cast<char*>(&one), sizeof(int));
|
|
|
|
|
- if (one != 1) {
|
|
|
|
|
- std::cerr << "Warning: binary msh file " << filename
|
|
|
|
|
- << " is saved with different endianness than this machine."
|
|
|
|
|
- << std::endl;
|
|
|
|
|
- return not_implemented();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- fin >> buf;
|
|
|
|
|
- if (buf != "$EndMeshFormat") { return not_implemented(); }
|
|
|
|
|
-
|
|
|
|
|
- const auto num_nodes_per_elem_type = [](int elem_type)->int
|
|
|
|
|
- {
|
|
|
|
|
- size_t nodes_per_element = 0;
|
|
|
|
|
- switch (elem_type) {
|
|
|
|
|
- case 2:
|
|
|
|
|
- nodes_per_element = 3; // Triangle
|
|
|
|
|
- break;
|
|
|
|
|
- case 3:
|
|
|
|
|
- nodes_per_element = 4; // Quad
|
|
|
|
|
- break;
|
|
|
|
|
- case 4:
|
|
|
|
|
- nodes_per_element = 4; // Tet
|
|
|
|
|
- break;
|
|
|
|
|
- case 5:
|
|
|
|
|
- nodes_per_element = 8; // hexahedron
|
|
|
|
|
- break;
|
|
|
|
|
- default:
|
|
|
|
|
- assert(false && "not implemented");
|
|
|
|
|
- nodes_per_element = -1;
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- return nodes_per_element;
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ igl::MshLoader _loader(msh);
|
|
|
|
|
+ const int USETAG = 1;
|
|
|
|
|
|
|
|
- const auto parse_nodes = [&](std::ifstream& fin)
|
|
|
|
|
- {
|
|
|
|
|
- size_t num_nodes;
|
|
|
|
|
- fin >> num_nodes;
|
|
|
|
|
- m_nodes.resize(num_nodes*3);
|
|
|
|
|
|
|
+ #ifndef NDEBUG
|
|
|
|
|
+ std::cout<<"readMSH:Total number of nodes:" << _loader.get_nodes().size()<<std::endl;
|
|
|
|
|
+ std::cout<<"readMSH:Total number of elements:" << _loader.get_elements().size()<<std::endl;
|
|
|
|
|
|
|
|
- if (m_binary) {
|
|
|
|
|
- size_t num_bytes = (4+3*m_data_size) * num_nodes;
|
|
|
|
|
- char* data = new char[num_bytes];
|
|
|
|
|
- eat_white_space(fin);
|
|
|
|
|
- fin.read(data, num_bytes);
|
|
|
|
|
-
|
|
|
|
|
- for (size_t i=0; i<num_nodes; i++) {
|
|
|
|
|
- int node_idx = *reinterpret_cast<int*> (&data[i*(4+3*m_data_size)]) - 1;
|
|
|
|
|
- m_nodes[node_idx*3] = *reinterpret_cast<Float*>(&data[i*(4+3*m_data_size) + 4]);
|
|
|
|
|
- m_nodes[node_idx*3+1] = *reinterpret_cast<Float*>(&data[i*(4+3*m_data_size) + 4 + m_data_size]);
|
|
|
|
|
- m_nodes[node_idx*3+2] = *reinterpret_cast<Float*>(&data[i*(4+3*m_data_size) + 4 + 2*m_data_size]);
|
|
|
|
|
|
|
+ std::cout<<"readMSH:Node fields:" << std::endl;
|
|
|
|
|
+ for(auto i=std::begin(_loader.get_node_fields_names()); i!=std::end(_loader.get_node_fields_names()); i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ std::cout << i->c_str() << ":" << _loader.get_node_fields()[i-std::begin(_loader.get_node_fields_names())].size() << std::endl;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- delete [] data;
|
|
|
|
|
- } else {
|
|
|
|
|
- int node_idx;
|
|
|
|
|
- for (size_t i=0; i<num_nodes; i++) {
|
|
|
|
|
- fin >> node_idx;
|
|
|
|
|
- node_idx -= 1;
|
|
|
|
|
- fin >> m_nodes[node_idx*3]
|
|
|
|
|
- >> m_nodes[node_idx*3+1]
|
|
|
|
|
- >> m_nodes[node_idx*3+2];
|
|
|
|
|
|
|
+
|
|
|
|
|
+ std::cout << "readMSH:Element fields:" << std::endl;
|
|
|
|
|
+ for(auto i=std::begin(_loader.get_element_fields_names()); i!=std::end(_loader.get_element_fields_names()); i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ std::cout << i->c_str() << ":" << _loader.get_element_fields()[i-std::begin(_loader.get_element_fields_names())].size() << std::endl;
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const auto parse_elements = [&](std::ifstream& fin)
|
|
|
|
|
- {
|
|
|
|
|
- size_t num_elements;
|
|
|
|
|
- fin >> num_elements;
|
|
|
|
|
-
|
|
|
|
|
- // Tmp storage of elements;
|
|
|
|
|
- std::vector<int> triangle_element_idx;
|
|
|
|
|
- std::vector<int> triangle_elements;
|
|
|
|
|
- std::vector<int> quad_element_idx;
|
|
|
|
|
- std::vector<int> quad_elements;
|
|
|
|
|
- std::vector<int> tet_element_idx;
|
|
|
|
|
- std::vector<int> tet_elements;
|
|
|
|
|
- std::vector<int> hex_element_idx;
|
|
|
|
|
- std::vector<int> hex_elements;
|
|
|
|
|
-
|
|
|
|
|
- auto get_element_storage = [&](int elem_type) -> std::vector<int>* {
|
|
|
|
|
- switch (elem_type) {
|
|
|
|
|
- default:
|
|
|
|
|
- assert(false && "Unsupported element type encountered");
|
|
|
|
|
- case 2:
|
|
|
|
|
- return &triangle_elements;
|
|
|
|
|
- case 3:
|
|
|
|
|
- return &quad_elements;
|
|
|
|
|
- case 4:
|
|
|
|
|
- return &tet_elements;
|
|
|
|
|
- case 5:
|
|
|
|
|
- return &hex_elements;
|
|
|
|
|
- };
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- auto get_element_idx_storage = [&](int elem_type) -> std::vector<int>* {
|
|
|
|
|
- switch (elem_type) {
|
|
|
|
|
- default:
|
|
|
|
|
- assert(false && "Unsupported element type encountered");
|
|
|
|
|
- case 2:
|
|
|
|
|
- return &triangle_element_idx;
|
|
|
|
|
- case 3:
|
|
|
|
|
- return &quad_element_idx;
|
|
|
|
|
- case 4:
|
|
|
|
|
- return &tet_element_idx;
|
|
|
|
|
- case 5:
|
|
|
|
|
- return &hex_element_idx;
|
|
|
|
|
- };
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- size_t nodes_per_element;
|
|
|
|
|
- int glob_elem_type = -1;
|
|
|
|
|
-
|
|
|
|
|
|
|
|
|
|
- if (m_binary)
|
|
|
|
|
- {
|
|
|
|
|
- eat_white_space(fin);
|
|
|
|
|
- int elem_read = 0;
|
|
|
|
|
- while (elem_read < num_elements) {
|
|
|
|
|
- // Parse element header.
|
|
|
|
|
- int elem_type, num_elems, num_tags;
|
|
|
|
|
- fin.read((char*)&elem_type, sizeof(int));
|
|
|
|
|
- fin.read((char*)&num_elems, sizeof(int));
|
|
|
|
|
- fin.read((char*)&num_tags, sizeof(int));
|
|
|
|
|
- nodes_per_element = num_nodes_per_elem_type(elem_type);
|
|
|
|
|
- std::vector<int>& elements = *get_element_storage(elem_type);
|
|
|
|
|
- std::vector<int>& element_idx = *get_element_idx_storage(elem_type);
|
|
|
|
|
-
|
|
|
|
|
- for (size_t i=0; i<num_elems; i++) {
|
|
|
|
|
- int elem_idx;
|
|
|
|
|
- fin.read((char*)&elem_idx, sizeof(int));
|
|
|
|
|
- elem_idx -= 1;
|
|
|
|
|
- element_idx.push_back(elem_idx);
|
|
|
|
|
-
|
|
|
|
|
- // Eat up tags.
|
|
|
|
|
- for (size_t j=0; j<num_tags; j++) {
|
|
|
|
|
- int tag;
|
|
|
|
|
- fin.read((char*)&tag, sizeof(int));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Element values.
|
|
|
|
|
- for (size_t j=0; j<nodes_per_element; j++) {
|
|
|
|
|
- int idx;
|
|
|
|
|
- fin.read((char*)&idx, sizeof(int));
|
|
|
|
|
- elements.push_back(idx-1);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if(_loader.is_element_map_identity())
|
|
|
|
|
+ std::cout<<"readMSH:Element ids map is identity"<<std::endl;
|
|
|
|
|
+ else
|
|
|
|
|
+ std::cout<<"readMSH:Element ids map is NOT identity"<<std::endl;
|
|
|
|
|
+
|
|
|
|
|
+ #endif
|
|
|
|
|
+
|
|
|
|
|
+ // convert nodes
|
|
|
|
|
+ // hadrcoded for 3D
|
|
|
|
|
+ Eigen::Map< const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> >
|
|
|
|
|
+ node_map( _loader.get_nodes().data(), _loader.get_nodes().size()/3, 3 );
|
|
|
|
|
+
|
|
|
|
|
+ X = node_map;
|
|
|
|
|
+ XFields = _loader.get_element_fields_names();
|
|
|
|
|
+ XF.resize(_loader.get_node_fields().size());
|
|
|
|
|
+ XFields = _loader.get_node_fields_names();
|
|
|
|
|
+ for(size_t i=0;i<_loader.get_node_fields().size();++i)
|
|
|
|
|
+ {
|
|
|
|
|
+ Eigen::Map< const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> >
|
|
|
|
|
+ field_map( _loader.get_node_fields()[i].data(),
|
|
|
|
|
+ _loader.get_node_fields()[i].size()/_loader.get_node_fields_components()[i],
|
|
|
|
|
+ _loader.get_node_fields_components()[i] );
|
|
|
|
|
+ XF[i] = field_map;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- elem_read += num_elems;
|
|
|
|
|
- }
|
|
|
|
|
- } else
|
|
|
|
|
- {
|
|
|
|
|
- for (size_t i=0; i<num_elements; i++) {
|
|
|
|
|
- // Parse per element header
|
|
|
|
|
- int elem_num, elem_type, num_tags;
|
|
|
|
|
- fin >> elem_num >> elem_type >> num_tags;
|
|
|
|
|
- for (size_t j=0; j<num_tags; j++) {
|
|
|
|
|
- int tag;
|
|
|
|
|
- fin >> tag;
|
|
|
|
|
- }
|
|
|
|
|
- nodes_per_element = num_nodes_per_elem_type(elem_type);
|
|
|
|
|
- std::vector<int>& elements = *get_element_storage(elem_type);
|
|
|
|
|
- std::vector<int>& element_idx = *get_element_idx_storage(elem_type);
|
|
|
|
|
-
|
|
|
|
|
- elem_num -= 1;
|
|
|
|
|
- element_idx.push_back(elem_num);
|
|
|
|
|
-
|
|
|
|
|
- // Parse node idx.
|
|
|
|
|
- for (size_t j=0; j<nodes_per_element; j++) {
|
|
|
|
|
- int idx;
|
|
|
|
|
- fin >> idx;
|
|
|
|
|
- elements.push_back(idx-1); // msh index starts from 1.
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- auto copy_to_array = [&](
|
|
|
|
|
- const std::vector<int>& elements,
|
|
|
|
|
- const int nodes_per_element) {
|
|
|
|
|
- const size_t num_elements = elements.size() / nodes_per_element;
|
|
|
|
|
- if (elements.size() % nodes_per_element != 0) {
|
|
|
|
|
- assert(false && "parsing element failed");
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ // calculate number of elements
|
|
|
|
|
+ std::map<int,int> element_counts;
|
|
|
|
|
+
|
|
|
|
|
+ for(auto i:_loader.get_elements_types())
|
|
|
|
|
+ {
|
|
|
|
|
+ auto j=element_counts.insert({i,1});
|
|
|
|
|
+ if(!j.second) (*j.first).second+=1;
|
|
|
}
|
|
}
|
|
|
- m_elements.resize(elements.size());
|
|
|
|
|
- std::copy(elements.begin(), elements.end(), m_elements.data());
|
|
|
|
|
- m_nodes_per_element = nodes_per_element;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- if (!tet_elements.empty()) {
|
|
|
|
|
- copy_to_array(tet_elements, 4);
|
|
|
|
|
- m_element_type = 4;
|
|
|
|
|
- } else if (!hex_elements.empty()) {
|
|
|
|
|
- copy_to_array(hex_elements, 8);
|
|
|
|
|
- m_element_type = 5;
|
|
|
|
|
- } else if (!triangle_elements.empty()) {
|
|
|
|
|
- copy_to_array(triangle_elements, 3);
|
|
|
|
|
- m_element_type = 2;
|
|
|
|
|
- } else if (!quad_elements.empty()) {
|
|
|
|
|
- copy_to_array(quad_elements, 4);
|
|
|
|
|
- m_element_type = 3;
|
|
|
|
|
- } else {
|
|
|
|
|
- // 0 elements, use triangle by default.
|
|
|
|
|
- m_element_type = 2;
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
- const auto parse_element_field = [&](std::ifstream& fin)
|
|
|
|
|
- {
|
|
|
|
|
- size_t num_string_tags;
|
|
|
|
|
- size_t num_real_tags;
|
|
|
|
|
- size_t num_int_tags;
|
|
|
|
|
-
|
|
|
|
|
- fin >> num_string_tags;
|
|
|
|
|
- std::string* str_tags = new std::string[num_string_tags];
|
|
|
|
|
- for (size_t i=0; i<num_string_tags; i++) {
|
|
|
|
|
- eat_white_space(fin);
|
|
|
|
|
- if (fin.peek() == '\"') {
|
|
|
|
|
- // Handle field name between quoates.
|
|
|
|
|
- char buf[128];
|
|
|
|
|
- fin.get(); // remove the quote at the beginning.
|
|
|
|
|
- fin.getline(buf, 128, '\"');
|
|
|
|
|
- str_tags[i] = std::string(buf);
|
|
|
|
|
- } else {
|
|
|
|
|
- fin >> str_tags[i];
|
|
|
|
|
|
|
+ #ifndef NDEBUG
|
|
|
|
|
+ std::cout<<"ReadMSH: elements found"<<std::endl;
|
|
|
|
|
+ for(auto i:element_counts)
|
|
|
|
|
+ std::cout<<"\t"<<i.first<<":"<<i.second<<std::endl;
|
|
|
|
|
+ #endif
|
|
|
|
|
+ int n_tri_el=0;
|
|
|
|
|
+ int n_tet_el=0;
|
|
|
|
|
+
|
|
|
|
|
+ auto n_tri_el_=element_counts.find(igl::MshLoader::ELEMENT_TRI);
|
|
|
|
|
+ auto n_tet_el_=element_counts.find(igl::MshLoader::ELEMENT_TET);
|
|
|
|
|
+ if(n_tri_el_!=std::end(element_counts))
|
|
|
|
|
+ n_tri_el=n_tri_el_->second;
|
|
|
|
|
+ if(n_tet_el_!=std::end(element_counts))
|
|
|
|
|
+ n_tet_el=n_tet_el_->second;
|
|
|
|
|
+
|
|
|
|
|
+ Tri.resize(n_tri_el,3);
|
|
|
|
|
+ Tet.resize(n_tet_el,4);
|
|
|
|
|
+ TriTag.resize(n_tri_el);
|
|
|
|
|
+ TetTag.resize(n_tet_el);
|
|
|
|
|
+ size_t el_start = 0;
|
|
|
|
|
+ TriF.resize(_loader.get_element_fields().size());
|
|
|
|
|
+ TetF.resize(_loader.get_element_fields().size());
|
|
|
|
|
+ for(size_t i=0;i<_loader.get_element_fields().size();++i)
|
|
|
|
|
+ {
|
|
|
|
|
+ TriF[i].resize(n_tri_el,_loader.get_element_fields_components()[i]);
|
|
|
|
|
+ TetF[i].resize(n_tet_el,_loader.get_element_fields_components()[i]);
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- fin >> num_real_tags;
|
|
|
|
|
- Float* real_tags = new Float[num_real_tags];
|
|
|
|
|
- for (size_t i=0; i<num_real_tags; i++)
|
|
|
|
|
- fin >> real_tags[i];
|
|
|
|
|
-
|
|
|
|
|
- fin >> num_int_tags;
|
|
|
|
|
- int* int_tags = new int[num_int_tags];
|
|
|
|
|
- for (size_t i=0; i<num_int_tags; i++)
|
|
|
|
|
- fin >> int_tags[i];
|
|
|
|
|
-
|
|
|
|
|
- if (num_string_tags <= 0 || num_int_tags <= 2) {
|
|
|
|
|
- delete[] str_tags;
|
|
|
|
|
- delete[] real_tags;
|
|
|
|
|
- delete[] int_tags;
|
|
|
|
|
- assert(false && "invalid format");
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- std::string fieldname = str_tags[0];
|
|
|
|
|
- int num_components = int_tags[1];
|
|
|
|
|
- int num_entries = int_tags[2];
|
|
|
|
|
- VectorF field(num_entries * num_components);
|
|
|
|
|
-
|
|
|
|
|
- delete [] str_tags;
|
|
|
|
|
- delete [] real_tags;
|
|
|
|
|
- delete [] int_tags;
|
|
|
|
|
-
|
|
|
|
|
- if (m_binary) {
|
|
|
|
|
- size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
|
|
|
|
|
- char* data = new char[num_bytes];
|
|
|
|
|
- eat_white_space(fin);
|
|
|
|
|
- fin.read(data, num_bytes);
|
|
|
|
|
- for (size_t i=0; i<num_entries; i++) {
|
|
|
|
|
- int elem_idx = *reinterpret_cast<int*>(&data[i*(4+num_components*m_data_size)]);
|
|
|
|
|
- elem_idx -= 1;
|
|
|
|
|
- size_t base_idx = i*(4+num_components*m_data_size) + 4;
|
|
|
|
|
- for (size_t j=0; j<num_components; j++) {
|
|
|
|
|
- field[elem_idx * num_components + j] = *reinterpret_cast<Float*>(&data[base_idx+j*m_data_size]);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- delete [] data;
|
|
|
|
|
- } else {
|
|
|
|
|
- int elem_idx;
|
|
|
|
|
- for (size_t i=0; i<num_entries; i++) {
|
|
|
|
|
- fin >> elem_idx;
|
|
|
|
|
- elem_idx -= 1;
|
|
|
|
|
- for (size_t j=0; j<num_components; j++) {
|
|
|
|
|
- fin >> field[elem_idx * num_components + j];
|
|
|
|
|
|
|
+ EFields = _loader.get_element_fields_names();
|
|
|
|
|
+ int i_tri = 0;
|
|
|
|
|
+ int i_tet = 0;
|
|
|
|
|
+
|
|
|
|
|
+ for(size_t i=0;i<_loader.get_elements_lengths().size();++i)
|
|
|
|
|
+ {
|
|
|
|
|
+ if(_loader.get_elements_types()[i]==MshLoader::ELEMENT_TRI )
|
|
|
|
|
+ {
|
|
|
|
|
+ assert(_loader.get_elements_lengths()[i]==3);
|
|
|
|
|
+
|
|
|
|
|
+ Tri(i_tri, 0) = _loader.get_elements()[el_start ];
|
|
|
|
|
+ Tri(i_tri, 1) = _loader.get_elements()[el_start+1];
|
|
|
|
|
+ Tri(i_tri, 2) = _loader.get_elements()[el_start+2];
|
|
|
|
|
+
|
|
|
|
|
+ TriTag(i_tri) = _loader.get_elements_tags()[1][i];
|
|
|
|
|
+
|
|
|
|
|
+ for(size_t j=0;j<_loader.get_element_fields().size();++j)
|
|
|
|
|
+ for(size_t k=0;k<_loader.get_element_fields_components()[j];++k)
|
|
|
|
|
+ TriF[j](i_tri,k) = _loader.get_element_fields()[j][_loader.get_element_fields_components()[j]*i+k];
|
|
|
|
|
+
|
|
|
|
|
+ ++i_tri;
|
|
|
|
|
+ } else if(_loader.get_elements_types()[i]==MshLoader::ELEMENT_TET ) {
|
|
|
|
|
+ assert(_loader.get_elements_lengths()[i]==4);
|
|
|
|
|
+
|
|
|
|
|
+ Tet(i_tet, 0) = _loader.get_elements()[el_start ];
|
|
|
|
|
+ Tet(i_tet, 1) = _loader.get_elements()[el_start+1];
|
|
|
|
|
+ Tet(i_tet, 2) = _loader.get_elements()[el_start+2];
|
|
|
|
|
+ Tet(i_tet, 3) = _loader.get_elements()[el_start+3];
|
|
|
|
|
+
|
|
|
|
|
+ TetTag(i_tet) = _loader.get_elements_tags()[USETAG][i];
|
|
|
|
|
+
|
|
|
|
|
+ for(size_t j=0;j<_loader.get_element_fields().size();++j)
|
|
|
|
|
+ for(size_t k=0;k<_loader.get_element_fields_components()[j];++k)
|
|
|
|
|
+ TetF[j](i_tet,k) = _loader.get_element_fields()[j][_loader.get_element_fields_components()[j]*i+k];
|
|
|
|
|
+
|
|
|
|
|
+ ++i_tet;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // else: it's unsupported type of the element, ignore for now
|
|
|
|
|
+ std::cerr<<"readMSH: unsupported element type: "<<_loader.get_elements_types()[i] <<
|
|
|
|
|
+ ", length: "<< _loader.get_elements_lengths()[i] <<std::endl;
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- m_element_fields[fieldname] = field;
|
|
|
|
|
- };
|
|
|
|
|
|
|
|
|
|
- const auto parse_node_field = [&](std::ifstream& fin)
|
|
|
|
|
- {
|
|
|
|
|
- size_t num_string_tags;
|
|
|
|
|
- size_t num_real_tags;
|
|
|
|
|
- size_t num_int_tags;
|
|
|
|
|
-
|
|
|
|
|
- fin >> num_string_tags;
|
|
|
|
|
- std::string* str_tags = new std::string[num_string_tags];
|
|
|
|
|
- for (size_t i=0; i<num_string_tags; i++) {
|
|
|
|
|
- eat_white_space(fin);
|
|
|
|
|
- if (fin.peek() == '\"') {
|
|
|
|
|
- // Handle field name between quoates.
|
|
|
|
|
- char buf[128];
|
|
|
|
|
- fin.get(); // remove the quote at the beginning.
|
|
|
|
|
- fin.getline(buf, 128, '\"');
|
|
|
|
|
- str_tags[i] = std::string(buf);
|
|
|
|
|
- } else {
|
|
|
|
|
- fin >> str_tags[i];
|
|
|
|
|
|
|
+ el_start += _loader.get_elements_lengths()[i];
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- fin >> num_real_tags;
|
|
|
|
|
- Float* real_tags = new Float[num_real_tags];
|
|
|
|
|
- for (size_t i=0; i<num_real_tags; i++)
|
|
|
|
|
- fin >> real_tags[i];
|
|
|
|
|
-
|
|
|
|
|
- fin >> num_int_tags;
|
|
|
|
|
- int* int_tags = new int[num_int_tags];
|
|
|
|
|
- for (size_t i=0; i<num_int_tags; i++)
|
|
|
|
|
- fin >> int_tags[i];
|
|
|
|
|
-
|
|
|
|
|
- if (num_string_tags <= 0 || num_int_tags <= 2) {
|
|
|
|
|
- delete[] str_tags;
|
|
|
|
|
- delete[] real_tags;
|
|
|
|
|
- delete[] int_tags;
|
|
|
|
|
- assert(false && "invalid format");
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- std::string fieldname = str_tags[0];
|
|
|
|
|
- int num_components = int_tags[1];
|
|
|
|
|
- int num_entries = int_tags[2];
|
|
|
|
|
- VectorF field(num_entries * num_components);
|
|
|
|
|
|
|
|
|
|
- delete [] str_tags;
|
|
|
|
|
- delete [] real_tags;
|
|
|
|
|
- delete [] int_tags;
|
|
|
|
|
-
|
|
|
|
|
- if (m_binary) {
|
|
|
|
|
- size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
|
|
|
|
|
- char* data = new char[num_bytes];
|
|
|
|
|
- eat_white_space(fin);
|
|
|
|
|
- fin.read(data, num_bytes);
|
|
|
|
|
- for (size_t i=0; i<num_entries; i++) {
|
|
|
|
|
- int node_idx = *reinterpret_cast<int*>(&data[i*(4+num_components*m_data_size)]);
|
|
|
|
|
- node_idx -= 1;
|
|
|
|
|
- size_t base_idx = i*(4+num_components*m_data_size) + 4;
|
|
|
|
|
- for (size_t j=0; j<num_components; j++) {
|
|
|
|
|
- field[node_idx * num_components + j] = *reinterpret_cast<Float*>(&data[base_idx+j*m_data_size]);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- delete [] data;
|
|
|
|
|
- } else {
|
|
|
|
|
- int node_idx;
|
|
|
|
|
- for (size_t i=0; i<num_entries; i++) {
|
|
|
|
|
- fin >> node_idx;
|
|
|
|
|
- node_idx -= 1;
|
|
|
|
|
- for (size_t j=0; j<num_components; j++) {
|
|
|
|
|
- fin >> field[node_idx * num_components + j];
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ assert(i_tet == n_tet_el);
|
|
|
|
|
+ assert(i_tri == n_tri_el);
|
|
|
|
|
+ } catch(const std::exception& e) {
|
|
|
|
|
+ std::cerr << e.what() << std::endl;
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- m_node_fields[fieldname] = field;
|
|
|
|
|
- };
|
|
|
|
|
- const auto parse_unknown_field = [](std::ifstream& fin,
|
|
|
|
|
- const std::string& fieldname)
|
|
|
|
|
- {
|
|
|
|
|
- std::cerr << "Warning: \"" << fieldname << "\" not supported yet. Ignored." << std::endl;
|
|
|
|
|
- std::string endmark = fieldname.substr(0,1) + "End"
|
|
|
|
|
- + fieldname.substr(1,fieldname.size()-1);
|
|
|
|
|
|
|
+IGL_INLINE bool igl::readMSH(const std::string &msh,
|
|
|
|
|
+ Eigen::MatrixXd &X,
|
|
|
|
|
+ Eigen::MatrixXi &Tri,
|
|
|
|
|
+ Eigen::MatrixXi &Tet,
|
|
|
|
|
+ Eigen::VectorXi &TriTag,
|
|
|
|
|
+ Eigen::VectorXi &TetTag
|
|
|
|
|
+ )
|
|
|
|
|
+{
|
|
|
|
|
+ std::vector<std::string> XFields;
|
|
|
|
|
+ std::vector<Eigen::MatrixXd> XF;
|
|
|
|
|
+ std::vector<std::string> EFields;
|
|
|
|
|
+ std::vector<Eigen::MatrixXd> TriF;
|
|
|
|
|
+ std::vector<Eigen::MatrixXd> TetF;
|
|
|
|
|
+ return igl::readMSH(msh,X,Tri,Tet,TriTag,TetTag,XFields,XF,EFields,TriF,TetF);
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- std::string buf("");
|
|
|
|
|
- while (buf != endmark && !fin.eof()) {
|
|
|
|
|
- fin >> buf;
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
|
|
+IGL_INLINE bool igl::readMSH(const std::string &msh,
|
|
|
|
|
+ Eigen::MatrixXd &X,
|
|
|
|
|
+ Eigen::MatrixXi &Tri,
|
|
|
|
|
+ Eigen::VectorXi &TriTag
|
|
|
|
|
+ )
|
|
|
|
|
+{
|
|
|
|
|
+ Eigen::MatrixXi Tet;
|
|
|
|
|
+ Eigen::VectorXi TetTag;
|
|
|
|
|
|
|
|
|
|
+ std::vector<std::string> XFields;
|
|
|
|
|
+ std::vector<Eigen::MatrixXd> XF;
|
|
|
|
|
+ std::vector<std::string> EFields;
|
|
|
|
|
+ std::vector<Eigen::MatrixXd> TriF;
|
|
|
|
|
+ std::vector<Eigen::MatrixXd> TetF;
|
|
|
|
|
|
|
|
- while (!fin.eof()) {
|
|
|
|
|
- buf.clear();
|
|
|
|
|
- fin >> buf;
|
|
|
|
|
- if (buf == "$Nodes") {
|
|
|
|
|
- parse_nodes(fin);
|
|
|
|
|
- fin >> buf;
|
|
|
|
|
- if (buf != "$EndNodes") { return invalid_format(); }
|
|
|
|
|
- } else if (buf == "$Elements") {
|
|
|
|
|
- parse_elements(fin);
|
|
|
|
|
- fin >> buf;
|
|
|
|
|
- if (buf != "$EndElements") { return invalid_format(); }
|
|
|
|
|
- } else if (buf == "$NodeData") {
|
|
|
|
|
- parse_node_field(fin);
|
|
|
|
|
- fin >> buf;
|
|
|
|
|
- if (buf != "$EndNodeData") { return invalid_format(); }
|
|
|
|
|
- } else if (buf == "$ElementData") {
|
|
|
|
|
- parse_element_field(fin);
|
|
|
|
|
- fin >> buf;
|
|
|
|
|
- if (buf != "$EndElementData") { return invalid_format(); }
|
|
|
|
|
- } else if (fin.eof()) {
|
|
|
|
|
- break;
|
|
|
|
|
- } else {
|
|
|
|
|
- parse_unknown_field(fin, buf);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- fin.close();
|
|
|
|
|
- V.resize(m_nodes.rows()/3,3);
|
|
|
|
|
- for (int i = 0; i < m_nodes.rows() / 3; i++)
|
|
|
|
|
- {
|
|
|
|
|
- for (int j = 0; j < 3; j++)
|
|
|
|
|
- {
|
|
|
|
|
- V(i,j) = m_nodes(i * 3 + j);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- int ss = num_nodes_per_elem_type(m_element_type);
|
|
|
|
|
- T.resize(m_elements.rows()/ss,ss);
|
|
|
|
|
- for (int i = 0; i < m_elements.rows() / ss; i++)
|
|
|
|
|
- {
|
|
|
|
|
- for (int j = 0; j < ss; j++)
|
|
|
|
|
- {
|
|
|
|
|
- T(i, j) = m_elements(i * ss + j);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return true;
|
|
|
|
|
|
|
+ return igl::readMSH(msh,X,Tri,Tet,TriTag,TetTag,XFields,XF,EFields,TriF,TetF);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+IGL_INLINE bool igl::readMSH(const std::string &msh,
|
|
|
|
|
+ Eigen::MatrixXd &X,
|
|
|
|
|
+ Eigen::MatrixXi &Tri
|
|
|
|
|
+ )
|
|
|
|
|
+{
|
|
|
|
|
+ Eigen::MatrixXi Tet;
|
|
|
|
|
+ Eigen::VectorXi TetTag;
|
|
|
|
|
+ Eigen::VectorXi TriTag;
|
|
|
|
|
+
|
|
|
|
|
+ std::vector<std::string> XFields;
|
|
|
|
|
+ std::vector<Eigen::MatrixXd> XF;
|
|
|
|
|
+ std::vector<std::string> EFields;
|
|
|
|
|
+ std::vector<Eigen::MatrixXd> TriF;
|
|
|
|
|
+ std::vector<Eigen::MatrixXd> TetF;
|
|
|
|
|
|
|
|
-#ifdef IGL_STATIC_LIBRARY
|
|
|
|
|
-// Explicit template instantiation
|
|
|
|
|
-// generated by autoexplicit.sh
|
|
|
|
|
-template bool igl::readMSH<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
|
|
|
|
-#endif
|
|
|
|
|
|
|
+ return igl::readMSH(msh,X,Tri,Tet,TriTag,TetTag,XFields,XF,EFields,TriF,TetF);
|
|
|
|
|
+}
|