/******************************************************** * ██████╗ ██████╗████████╗██╗ * ██╔════╝ ██╔════╝╚══██╔══╝██║ * ██║ ███╗██║ ██║ ██║ * ██║ ██║██║ ██║ ██║ * ╚██████╔╝╚██████╗ ██║ ███████╗ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ * Geophysical Computational Tools & Library (GCTL) * * Copyright (c) 2023 Yi Zhang (yizhang-geo@zju.edu.cn) * * GCTL is distributed under a dual licensing scheme. You can redistribute * it and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 2 * of the License, or (at your option) any later version. You should have * received a copy of the GNU Lesser General Public License along with this * program. If not, see . * * If the terms and conditions of the LGPL v.2. would prevent you from using * the GCTL, please consider the option to obtain a commercial license for a * fee. These licenses are offered by the GCTL's original author. As a rule, * licenses are provided "as-is", unlimited in time for a one time fee. Please * send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget * to include some description of your company and the realm of its activities. * Also add information on how to contact you by electronic and paper mail. ******************************************************/ #ifndef _GCTL_STL_IO_H #define _GCTL_STL_IO_H // library's head file #include "../core.h" #include "../utility.h" #include "../geometry.h" namespace gctl { /** * @brief Read stl file ascii format * * @tparam E vertex attribute type * @tparam A element attribute type * @param filename File name * @param nodes return nodes * @param facets return facets * @param solid solid name ('null' will read the first solid) * @param eps epsilon for node comparison */ template void read_stl_ascii(std::string filename, array> &nodes, array> &facets, std::string solid = "null", double eps = 1e-8) { std::ifstream infile; open_infile(infile, filename, ".stl"); vertex3dc tmp_node; std::vector tmp_nodes; _1i_vector one_tri(3); _2i_vector tmp_tris; bool inside_solid, new_node; point3dc nor, vt[3]; char solid_name[256], solid_endname[256]; std::string line; while (std::getline(infile, line)) { if (sscanf(line.c_str(), "solid %s", solid_name) == 1 && (!strcmp(solid_name, solid.c_str()) || solid == "null")) { inside_solid = true; while (inside_solid) { std::getline(infile, line); if (sscanf(line.c_str(), "endsolid %s", solid_endname) == 1) { if (strcmp(solid_endname, solid_name)) throw std::runtime_error("[gctl::read_stl_ascii] Invalid solid names."); inside_solid = false; } else { sscanf(line.c_str(), "facet normal %lf %lf %lf", &nor.x, &nor.y, &nor.z); std::getline(infile, line); // outer loop for (int i = 0; i < 3; i++) { std::getline(infile, line); line.erase(0, line.find_first_not_of(" \t")); line.erase(line.find_last_not_of(" \t") + 1); sscanf(line.c_str(), "vertex %lf %lf %lf", &vt[i].x, &vt[i].y, &vt[i].z); } std::getline(infile, line); // endloop std::getline(infile, line); // endfacet for (size_t i = 0; i < 3; i++) { tmp_node.id = tmp_nodes.size(); tmp_node.x = vt[i].x; tmp_node.y = vt[i].y; tmp_node.z = vt[i].z; new_node = true; for (size_t v = 0; v < tmp_nodes.size(); v++) { if (isequal(tmp_nodes[v], tmp_node, eps)) { tmp_node.id = tmp_nodes[v].id; new_node = false; break; } } if (new_node) tmp_nodes.push_back(tmp_node); one_tri[i] = tmp_node.id; } tmp_tris.push_back(one_tri); } } } } infile.close(); nodes.resize(tmp_nodes.size()); for (size_t i = 0; i < tmp_nodes.size(); i++) { nodes[i].id = tmp_nodes[i].id; nodes[i].x = tmp_nodes[i].x; nodes[i].y = tmp_nodes[i].y; nodes[i].z = tmp_nodes[i].z; } facets.resize(tmp_tris.size()); for (size_t i = 0; i < tmp_tris.size(); i++) { facets[i].set(nodes[tmp_tris[i][0]], nodes[tmp_tris[i][1]], nodes[tmp_tris[i][2]], i); } destroy_vector(tmp_nodes); destroy_vector(tmp_tris); destroy_vector(one_tri); return; } /** * @brief Save stl file ascii format * * @tparam E Vertex attribute type * @tparam A Element attribute type * @param filename File name * @param facets Input facets * @param solid Solid name */ template void save_stl_ascii(std::string filename, const array> &facets, std::string solid = "STL generated by GCTL") { std::ofstream outfile; open_outfile(outfile, filename, ".stl"); point3dc nor; outfile << "solid " << solid << "\n"; for (size_t i = 0; i < facets.size(); i++) { nor = cross(*facets[i].vert[1] - *facets[i].vert[0], *facets[i].vert[2] - *facets[i].vert[0]).normal(); outfile << "facet normal " << nor.x << " " << nor.y << " " << nor.z << "\n"; outfile << " outer loop\n"; outfile << " vertex " << facets[i].vert[0]->x << " " << facets[i].vert[0]->y << " " << facets[i].vert[0]->z << "\n"; outfile << " vertex " << facets[i].vert[1]->x << " " << facets[i].vert[1]->y << " " << facets[i].vert[1]->z << "\n"; outfile << " vertex " << facets[i].vert[2]->x << " " << facets[i].vert[2]->y << " " << facets[i].vert[2]->z << "\n"; outfile << " endloop\n"; outfile << "endfacet\n"; } outfile << "endsolid " << solid << "\n"; outfile.close(); return; } /** * @brief Read stl file binary format * * @tparam E vertex attribute type * @tparam A element attribute type * @param filename File name * @param nodes return nodes * @param facets return facets * @param eps epsilon for node comparison * * @return solid name */ template std::string read_stl_binary(std::string filename, array> &nodes, array> &facets, double eps = 1e-8) { std::ifstream infile; open_infile(infile, filename, ".stl", std::ios::binary); char blank[2], header[80]; infile.read(header, 80); int n_facets; infile.read((char*)&n_facets, 4); vertex3dc tmp_node; std::vector tmp_nodes; _1i_vector one_tri(3); _2i_vector tmp_tris; tmp_tris.reserve(n_facets); bool new_node; point3fc nor, vt[3]; for (size_t i = 0; i < n_facets; i++) { infile.read((char*)&nor.x, 4); infile.read((char*)&nor.y, 4); infile.read((char*)&nor.z, 4); for (size_t j = 0; j < 3; j++) { infile.read((char*)&vt[j].x, 4); infile.read((char*)&vt[j].y, 4); infile.read((char*)&vt[j].z, 4); } infile.read((char*)&blank, 2); for (size_t j = 0; j < 3; j++) { tmp_node.id = tmp_nodes.size(); tmp_node.x = vt[j].x; tmp_node.y = vt[j].y; tmp_node.z = vt[j].z; new_node = true; for (size_t v = 0; v < tmp_nodes.size(); v++) { if (isequal(tmp_nodes[v], tmp_node, eps)) { tmp_node.id = tmp_nodes[v].id; new_node = false; break; } } if (new_node) tmp_nodes.push_back(tmp_node); one_tri[j] = tmp_node.id; } tmp_tris.push_back(one_tri); } infile.close(); nodes.resize(tmp_nodes.size()); for (size_t i = 0; i < tmp_nodes.size(); i++) { nodes[i].id = tmp_nodes[i].id; nodes[i].x = tmp_nodes[i].x; nodes[i].y = tmp_nodes[i].y; nodes[i].z = tmp_nodes[i].z; } facets.resize(tmp_tris.size()); for (size_t i = 0; i < tmp_tris.size(); i++) { facets[i].set(nodes[tmp_tris[i][0]], nodes[tmp_tris[i][1]], nodes[tmp_tris[i][2]], i); } destroy_vector(tmp_nodes); destroy_vector(tmp_tris); destroy_vector(one_tri); std::string solid_name(header); return solid_name; } /** * @brief Save stl file binary format * * @tparam E vertex attribute type * @tparam A element attribute type * @param filename File name * @param facets return facets * @param solid solid name */ template void save_stl_binary(std::string filename, const array> &facets, std::string solid = "STL generated by GCTL") { std::ofstream outfile; open_outfile(outfile, filename, ".stl", std::ios::binary); char blank[2] = {'\0', '\0'}; char header[80]; for (size_t i = 0; i < 80; i++) header[i] = '\0'; for (size_t i = 0; i < solid.size(); i++) header[i] = solid[i]; outfile.write(header, 80); int n_facets = facets.size(); outfile.write((char*)&n_facets, 4); point3dc nor; point3fc nor_fl; point3fc vt[3]; for (size_t i = 0; i < facets.size(); i++) { nor = cross(*facets[i].vert[1] - *facets[i].vert[0], *facets[i].vert[2] - *facets[i].vert[0]).normal(); // convert from double to float nor_fl.x = nor.x; nor_fl.y = nor.y; nor_fl.z = nor.z; for (size_t j = 0; j < 3; j++) { vt[j].x = facets[i].vert[j]->x; vt[j].y = facets[i].vert[j]->y; vt[j].z = facets[i].vert[j]->z; } outfile.write((char*)&nor_fl.x, 4); outfile.write((char*)&nor_fl.y, 4); outfile.write((char*)&nor_fl.z, 4); for (size_t j = 0; j < 3; j++) { outfile.write((char*)&vt[j].x, 4); outfile.write((char*)&vt[j].y, 4); outfile.write((char*)&vt[j].z, 4); } outfile.write(blank, 2); } outfile.close(); } }; #endif // _GCTL_STL_IO_H