readSTL.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2014 Alec Jacobson <[email protected]>
  4. // Copyright (C) 2018 Qingnan Zhou <[email protected]>
  5. // Copyright (C) 2020 Jérémie Dumas <[email protected]>
  6. //
  7. // This Source Code Form is subject to the terms of the Mozilla Public License
  8. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  9. // obtain one at http://mozilla.org/MPL/2.0/.
  10. #include "readSTL.h"
  11. #include "list_to_matrix.h"
  12. #include "string_utils.h"
  13. #include "file_utils.h"
  14. #include <iostream>
  15. namespace igl {
  16. template <typename DerivedV, typename DerivedF, typename DerivedN>
  17. IGL_INLINE bool readSTL(std::istream &input,
  18. Eigen::PlainObjectBase<DerivedV> &V,
  19. Eigen::PlainObjectBase<DerivedF> &F,
  20. Eigen::PlainObjectBase<DerivedN> &N) {
  21. std::vector<std::array<typename DerivedV::Scalar, 3>> vV;
  22. std::vector<std::array<typename DerivedN::Scalar, 3>> vN;
  23. std::vector<std::array<typename DerivedF::Scalar, 3>> vF;
  24. if (!readSTL(input, vV, vF, vN)) {
  25. return false;
  26. }
  27. if (!list_to_matrix(vV, V)) {
  28. return false;
  29. }
  30. if (!list_to_matrix(vF, F)) {
  31. return false;
  32. }
  33. if (!list_to_matrix(vN, N)) {
  34. return false;
  35. }
  36. return true;
  37. }
  38. IGL_INLINE bool is_stl_binary(std::istream &input) {
  39. std::streampos start_pos = input.tellg();
  40. constexpr size_t HEADER_SIZE = 80;
  41. char header[HEADER_SIZE];
  42. input.read(header, HEADER_SIZE);
  43. if (!starts_with(header, "solid")) {
  44. input.seekg(start_pos);
  45. return true;
  46. }
  47. if (!input.good()) {
  48. input.seekg(start_pos);
  49. return false;
  50. }
  51. // Check if filesize matches the number of faces claimed.
  52. char buf[4];
  53. input.read(buf, 4);
  54. size_t num_faces = *reinterpret_cast<uint32_t *>(buf);
  55. input.seekg(0, input.end);
  56. size_t file_size = input.tellg();
  57. input.seekg(start_pos);
  58. if (file_size == 80 + 4 + (4 * 12 + 2) * num_faces) {
  59. return true;
  60. } else {
  61. return false;
  62. }
  63. }
  64. template <typename TypeV, typename TypeF, typename TypeN>
  65. IGL_INLINE bool read_stl_ascii(std::istream &input,
  66. std::vector<std::array<TypeV, 3>> &V,
  67. std::vector<std::array<TypeF, 3>> &F,
  68. std::vector<std::array<TypeN, 3>> &N) {
  69. constexpr size_t LINE_SIZE = 256;
  70. char line[LINE_SIZE];
  71. bool success = true;
  72. if (!input) {
  73. throw std::runtime_error("Failed to open file");
  74. }
  75. // skip header line.
  76. input.getline(line, LINE_SIZE);
  77. auto parse_ascii_normal = [&N](const char *line) {
  78. double x, y, z;
  79. size_t n = sscanf(line, " facet normal %lf %lf %lf", &x, &y, &z);
  80. assert(n == 3);
  81. if (n != 3) {
  82. return false;
  83. }
  84. N.push_back({{static_cast<TypeN>(x), static_cast<TypeN>(y),
  85. static_cast<TypeN>(z)}});
  86. return true;
  87. };
  88. auto parse_ascii_vertex = [&V](const char *line) {
  89. double x, y, z;
  90. size_t n = sscanf(line, " vertex %lf %lf %lf", &x, &y, &z);
  91. assert(n == 3);
  92. if (n != 3) {
  93. return false;
  94. }
  95. V.push_back({{static_cast<TypeV>(x), static_cast<TypeV>(y),
  96. static_cast<TypeV>(z)}});
  97. return true;
  98. };
  99. auto parse_ascii_facet = [&parse_ascii_vertex, &parse_ascii_normal](std::istream &fin) {
  100. constexpr size_t LINE_SIZE = 256;
  101. constexpr size_t WORD_SIZE = 128;
  102. char line[LINE_SIZE];
  103. char first_word[WORD_SIZE];
  104. const char *face_begin = "facet";
  105. const char *face_end = "endfacet";
  106. const char *loop_begin = "outer";
  107. const char *loop_end = "endloop";
  108. const char *vertex_flag = "vertex";
  109. bool reading_facet = false;
  110. bool reading_loop = false;
  111. bool success = true;
  112. size_t num_vts = 0;
  113. while (!fin.eof()) {
  114. fin.getline(line, LINE_SIZE);
  115. size_t n = sscanf(line, " %s", first_word);
  116. if (n == 0)
  117. continue;
  118. if (starts_with(first_word, face_begin)) {
  119. success = parse_ascii_normal(line);
  120. assert(success);
  121. reading_facet = true;
  122. } else if (starts_with(first_word, face_end)) {
  123. assert(reading_facet);
  124. reading_facet = false;
  125. } else if (starts_with(first_word, loop_begin)) {
  126. reading_loop = true;
  127. } else if (starts_with(first_word, loop_end)) {
  128. assert(reading_loop);
  129. reading_loop = false;
  130. } else if (starts_with(first_word, vertex_flag)) {
  131. assert(reading_facet);
  132. assert(reading_loop);
  133. success = parse_ascii_vertex(line);
  134. assert(success);
  135. num_vts += 1;
  136. }
  137. if (!success) {
  138. return false;
  139. }
  140. if (!reading_facet) {
  141. break;
  142. }
  143. }
  144. if (num_vts == 0) {
  145. return true;
  146. }
  147. assert(num_vts == 3);
  148. if (num_vts != 3) {
  149. std::cerr << "Warning: mesh contain face made of " << num_vts
  150. << " vertices" << std::endl;
  151. return false;
  152. }
  153. return true;
  154. };
  155. while (!input.eof()) {
  156. success = parse_ascii_facet(input);
  157. if (!success) {
  158. return false;
  159. }
  160. }
  161. F.resize(V.size() / 3);
  162. for (size_t f = 0; f < F.size(); ++f) {
  163. auto v = static_cast<TypeF>(f * 3);
  164. F[f] = {{v, v + 1, v + 2}};
  165. }
  166. return success;
  167. }
  168. template <typename TypeV, typename TypeF, typename TypeN>
  169. IGL_INLINE bool read_stl_binary(std::istream &input,
  170. std::vector<std::array<TypeV, 3>> &V,
  171. std::vector<std::array<TypeF, 3>> &F,
  172. std::vector<std::array<TypeN, 3>> &N) {
  173. if (!input) {
  174. throw std::runtime_error("Failed to open file");
  175. }
  176. constexpr size_t FLOAT_SIZE = sizeof(float);
  177. static_assert(FLOAT_SIZE == 4, "float type is not 4 bytes");
  178. constexpr size_t LINE_SIZE = 256;
  179. char buf[LINE_SIZE];
  180. // 80 bytes header, no data significance.
  181. input.read(buf, 80);
  182. if (!input.good()) {
  183. throw std::runtime_error("Unable to parse STL header.");
  184. }
  185. input.read(buf, 4);
  186. const size_t num_faces = *reinterpret_cast<uint32_t *>(buf);
  187. if (!input.good()) {
  188. throw std::runtime_error("Unable to parse STL number of faces.");
  189. }
  190. for (size_t i = 0; i < num_faces; i++) {
  191. // Parse normal
  192. input.read(buf, FLOAT_SIZE * 3);
  193. auto nx = static_cast<TypeN>(*reinterpret_cast<float *>(buf));
  194. auto ny = static_cast<TypeN>(*reinterpret_cast<float *>(buf + FLOAT_SIZE));
  195. auto nz =
  196. static_cast<TypeN>(*reinterpret_cast<float *>(buf + FLOAT_SIZE * 2));
  197. assert(input.good());
  198. // vertex 1
  199. input.read(buf, FLOAT_SIZE * 3);
  200. auto v1x = static_cast<TypeV>(*reinterpret_cast<float *>(buf));
  201. auto v1y = static_cast<TypeV>(*reinterpret_cast<float *>(buf + FLOAT_SIZE));
  202. auto v1z =
  203. static_cast<TypeV>(*reinterpret_cast<float *>(buf + FLOAT_SIZE * 2));
  204. assert(input.good());
  205. // vertex 2
  206. input.read(buf, FLOAT_SIZE * 3);
  207. auto v2x = static_cast<TypeV>(*reinterpret_cast<float *>(buf));
  208. auto v2y = static_cast<TypeV>(*reinterpret_cast<float *>(buf + FLOAT_SIZE));
  209. auto v2z =
  210. static_cast<TypeV>(*reinterpret_cast<float *>(buf + FLOAT_SIZE * 2));
  211. assert(input.good());
  212. // vertex 3
  213. input.read(buf, FLOAT_SIZE * 3);
  214. auto v3x = static_cast<TypeV>(*reinterpret_cast<float *>(buf));
  215. auto v3y = static_cast<TypeV>(*reinterpret_cast<float *>(buf + FLOAT_SIZE));
  216. auto v3z =
  217. static_cast<TypeV>(*reinterpret_cast<float *>(buf + FLOAT_SIZE * 2));
  218. assert(input.good());
  219. // attribute (2 bytes), not sure what purpose they serve.
  220. input.read(buf, 2);
  221. N.push_back({{nx, ny, nz}});
  222. V.push_back({{v1x, v1y, v1z}});
  223. V.push_back({{v2x, v2y, v2z}});
  224. V.push_back({{v3x, v3y, v3z}});
  225. assert(input.good());
  226. if (!input.good()) {
  227. std::stringstream err_msg;
  228. err_msg << "Failed to parse face " << i << " from STL file";
  229. throw std::runtime_error(err_msg.str());
  230. }
  231. }
  232. std::for_each(V.begin(), V.end(), [](const std::array<TypeV, 3> &v) {
  233. for (auto x : v) {
  234. if (!std::isfinite(x)) {
  235. throw std::runtime_error("NaN or Inf detected in input file.");
  236. }
  237. }
  238. });
  239. if (!V.empty()) {
  240. F.resize(V.size() / 3);
  241. for (size_t f = 0; f < F.size(); ++f) {
  242. auto v = static_cast<TypeF>(f * 3);
  243. F[f] = {{v, v + 1, v + 2}};
  244. }
  245. }
  246. return true;
  247. }
  248. template <typename TypeV, typename TypeF, typename TypeN>
  249. IGL_INLINE bool readSTL(std::istream &input,
  250. std::vector<std::array<TypeV, 3>> &V,
  251. std::vector<std::array<TypeF, 3>> &F,
  252. std::vector<std::array<TypeN, 3>> &N) {
  253. bool success = false;
  254. if (is_stl_binary(input)) {
  255. success = read_stl_binary(input, V, F, N);
  256. } else {
  257. success = read_stl_ascii(input, V, F, N);
  258. }
  259. return success;
  260. }
  261. template <typename DerivedV, typename DerivedF, typename DerivedN>
  262. IGL_INLINE bool readSTL(
  263. FILE * fp,
  264. Eigen::PlainObjectBase<DerivedV> & V,
  265. Eigen::PlainObjectBase<DerivedF> & F,
  266. Eigen::PlainObjectBase<DerivedN> & N)
  267. {
  268. std::vector<uint8_t> fileBufferBytes;
  269. read_file_binary(fp,fileBufferBytes);
  270. file_memory_stream stream((char*)fileBufferBytes.data(), fileBufferBytes.size());
  271. return readSTL(stream, V, F, N);
  272. }
  273. } // namespace igl
  274. #ifdef IGL_STATIC_LIBRARY
  275. // Explicit template instantiation
  276. template bool igl::readSTL<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  277. template bool igl::readSTL<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  278. template bool igl::readSTL<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  279. template bool igl::readSTL<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  280. template bool igl::readSTL<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  281. template bool igl::readSTL<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  282. template bool igl::readSTL<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  283. template bool igl::readSTL<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  284. template bool igl::readSTL<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  285. #endif