readPLY.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. #include "readPLY.h"
  2. #include <string>
  3. #include <set>
  4. #include <fstream>
  5. #include <iostream>
  6. #include <Eigen/Core>
  7. #include "tinyply.h"
  8. #include "file_utils.h"
  9. namespace igl
  10. {
  11. template <typename T, typename Derived>
  12. IGL_INLINE bool _tinyply_buffer_to_matrix(
  13. tinyply::PlyData & D,
  14. Eigen::PlainObjectBase<Derived> & M,
  15. size_t rows,
  16. size_t cols )
  17. {
  18. Eigen::Map< Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> >
  19. _map( reinterpret_cast<T *>( D.buffer.get()), rows, cols );
  20. M = _map.template cast<typename Derived::Scalar>();
  21. return true;
  22. }
  23. template <typename Derived>
  24. IGL_INLINE bool tinyply_buffer_to_matrix(
  25. tinyply::PlyData & D,
  26. Eigen::PlainObjectBase<Derived> & M,
  27. size_t rows,
  28. size_t cols )
  29. {
  30. switch(D.t)
  31. {
  32. case tinyply::Type::INT8 :
  33. return _tinyply_buffer_to_matrix<int8_t,Derived>(D, M,rows,cols);
  34. case tinyply::Type::UINT8 :
  35. return _tinyply_buffer_to_matrix<uint8_t,Derived>(D, M,rows,cols);
  36. case tinyply::Type::INT16 :
  37. return _tinyply_buffer_to_matrix<int16_t,Derived>(D, M,rows,cols);
  38. case tinyply::Type::UINT16 :
  39. return _tinyply_buffer_to_matrix<uint16_t,Derived>(D, M,rows,cols);
  40. case tinyply::Type::INT32 :
  41. return _tinyply_buffer_to_matrix<int32_t,Derived>(D, M,rows,cols);
  42. case tinyply::Type::UINT32 :
  43. return _tinyply_buffer_to_matrix<uint32_t,Derived>(D, M,rows,cols);
  44. case tinyply::Type::FLOAT32 :
  45. return _tinyply_buffer_to_matrix<float,Derived>(D, M,rows,cols);
  46. case tinyply::Type::FLOAT64 :
  47. return _tinyply_buffer_to_matrix<double,Derived>(D, M,rows,cols);
  48. default:
  49. return false;
  50. }
  51. }
  52. template <typename T, typename Derived>
  53. IGL_INLINE bool _tinyply_tristrips_to_trifaces(
  54. tinyply::PlyData & D,
  55. Eigen::PlainObjectBase<Derived> & M,
  56. size_t el,
  57. size_t el_len )
  58. {
  59. Eigen::Map< Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> >
  60. _map( reinterpret_cast<T *>( D.buffer.get()), el, el_len );
  61. // to make it more interesting, triangles in triangle strip can be separated by negative index elements
  62. // 1. count all triangles
  63. size_t triangles=0;
  64. // TODO: it's possible to optimize this , i suppose
  65. for(size_t i=0; i<el; i++)
  66. for(size_t j=0; j<(el_len-2); j++)
  67. {
  68. if(_map(i,j)>=0 && _map(i,j+1)>=0 && _map(i,j+2)>=0)
  69. triangles++;
  70. }
  71. // 2. convert triangles to faces, skipping over the negative indeces, indicating separate strips
  72. M.resize(triangles, 3);
  73. size_t k=0;
  74. for(size_t i=0; i<el; i++)
  75. {
  76. int flip=0;
  77. for(size_t j=0; j<(el_len-2); j++)
  78. {
  79. if(_map(i,j)>=0 && _map(i,j+1)>=0 && _map(i,j+2)>=0)
  80. {
  81. // consequtive faces on the same strip have to be flip-flopped, to preserve orientation
  82. M( k,0 ) = static_cast<typename Derived::Scalar>( _map(i, j ) );
  83. M( k,1 ) = static_cast<typename Derived::Scalar>( _map(i, j+1+flip ) );
  84. M( k,2 ) = static_cast<typename Derived::Scalar>( _map(i, j+1+(flip^1) ) );
  85. k++;
  86. flip ^= 1;
  87. } else {
  88. // reset flip on new strip start
  89. flip = 0;
  90. }
  91. }
  92. }
  93. assert(k==triangles);
  94. return true;
  95. }
  96. template <typename Derived>
  97. IGL_INLINE bool tinyply_tristrips_to_faces(
  98. tinyply::PlyData & D,
  99. Eigen::PlainObjectBase<Derived> & M,
  100. size_t el,
  101. size_t el_len )
  102. {
  103. switch(D.t)
  104. {
  105. case tinyply::Type::INT8 :
  106. return _tinyply_tristrips_to_trifaces<int8_t,Derived>(D, M,el,el_len);
  107. case tinyply::Type::UINT8 :
  108. return _tinyply_tristrips_to_trifaces<uint8_t,Derived>(D, M,el,el_len);
  109. case tinyply::Type::INT16 :
  110. return _tinyply_tristrips_to_trifaces<int16_t,Derived>(D, M,el,el_len);
  111. case tinyply::Type::UINT16 :
  112. return _tinyply_tristrips_to_trifaces<uint16_t,Derived>(D, M,el,el_len);
  113. case tinyply::Type::INT32 :
  114. return _tinyply_tristrips_to_trifaces<int32_t,Derived>(D, M,el,el_len);
  115. case tinyply::Type::UINT32 :
  116. return _tinyply_tristrips_to_trifaces<uint32_t,Derived>(D, M,el,el_len);
  117. case tinyply::Type::FLOAT32 :
  118. return _tinyply_tristrips_to_trifaces<float,Derived>(D, M,el,el_len);
  119. case tinyply::Type::FLOAT64 :
  120. return _tinyply_tristrips_to_trifaces<double,Derived>(D, M,el,el_len);
  121. default:
  122. return false;
  123. }
  124. }
  125. template <
  126. typename DerivedV,
  127. typename DerivedF,
  128. typename DerivedE,
  129. typename DerivedN,
  130. typename DerivedUV,
  131. typename DerivedVD,
  132. typename DerivedFD,
  133. typename DerivedED
  134. >
  135. IGL_INLINE bool readPLY(
  136. FILE *fp,
  137. Eigen::PlainObjectBase<DerivedV> & V,
  138. Eigen::PlainObjectBase<DerivedF> & F,
  139. Eigen::PlainObjectBase<DerivedE> & E,
  140. Eigen::PlainObjectBase<DerivedN> & N,
  141. Eigen::PlainObjectBase<DerivedUV> & UV,
  142. Eigen::PlainObjectBase<DerivedVD> & VD,
  143. std::vector<std::string> & Vheader,
  144. Eigen::PlainObjectBase<DerivedFD> & FD,
  145. std::vector<std::string> & Fheader,
  146. Eigen::PlainObjectBase<DerivedED> & ED,
  147. std::vector<std::string> & Eheader,
  148. std::vector<std::string> & comments
  149. )
  150. {
  151. // buffer the whole file in memory
  152. // then read from memory buffer
  153. try
  154. {
  155. std::vector<uint8_t> fileBufferBytes;
  156. read_file_binary(fp,fileBufferBytes);
  157. file_memory_stream stream((char*)fileBufferBytes.data(), fileBufferBytes.size());
  158. return readPLY(stream,V,F,E,N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments);
  159. }
  160. catch(const std::exception& e)
  161. {
  162. std::cerr << "ReadPLY error: " << e.what() << std::endl;
  163. }
  164. return false;
  165. }
  166. template <
  167. typename DerivedV,
  168. typename DerivedF
  169. >
  170. IGL_INLINE bool readPLY(
  171. FILE *fp,
  172. Eigen::PlainObjectBase<DerivedV> & V,
  173. Eigen::PlainObjectBase<DerivedF> & F
  174. )
  175. {
  176. Eigen::MatrixXd N,UV,VD,FD,ED;
  177. Eigen::MatrixXi E;
  178. std::vector<std::string> Vheader,Eheader,Fheader,comments;
  179. return readPLY(fp,V,F,E,N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments);
  180. }
  181. template <
  182. typename DerivedV,
  183. typename DerivedF,
  184. typename DerivedE
  185. >
  186. IGL_INLINE bool readPLY(
  187. FILE *fp,
  188. Eigen::PlainObjectBase<DerivedV> & V,
  189. Eigen::PlainObjectBase<DerivedF> & F,
  190. Eigen::PlainObjectBase<DerivedE> & E
  191. )
  192. {
  193. Eigen::MatrixXd N,UV,VD,FD,ED;
  194. std::vector<std::string> Vheader,Eheader,Fheader,comments;
  195. return readPLY(fp,V,F,E,N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments);
  196. }
  197. template <
  198. typename DerivedV,
  199. typename DerivedF,
  200. typename DerivedE,
  201. typename DerivedN,
  202. typename DerivedUV,
  203. typename DerivedVD,
  204. typename DerivedFD,
  205. typename DerivedED
  206. >
  207. IGL_INLINE bool readPLY(
  208. std::istream & ply_stream,
  209. Eigen::PlainObjectBase<DerivedV> & V,
  210. Eigen::PlainObjectBase<DerivedF> & F,
  211. Eigen::PlainObjectBase<DerivedE> & E,
  212. Eigen::PlainObjectBase<DerivedN> & N,
  213. Eigen::PlainObjectBase<DerivedUV> & UV,
  214. Eigen::PlainObjectBase<DerivedVD> & VD,
  215. std::vector<std::string> & Vheader,
  216. Eigen::PlainObjectBase<DerivedFD> & FD,
  217. std::vector<std::string> & Fheader,
  218. Eigen::PlainObjectBase<DerivedED> & ED,
  219. std::vector<std::string> & Eheader,
  220. std::vector<std::string> & comments
  221. )
  222. {
  223. tinyply::PlyFile file;
  224. file.parse_header(ply_stream);
  225. std::set<std::string> vertex_std{ "x","y","z", "nx","ny","nz", "u","v", "texture_u", "texture_v", "s", "t"};
  226. std::set<std::string> face_std { "vertex_index", "vertex_indices"};
  227. std::set<std::string> edge_std { "vertex1", "vertex2"}; //non-standard edge indexes
  228. // Tinyply treats parsed data as untyped byte buffers.
  229. std::shared_ptr<tinyply::PlyData> vertices, normals, faces, texcoords, edges;
  230. // Some ply files contain tristrips instead of faces
  231. std::shared_ptr<tinyply::PlyData> tristrips;
  232. std::shared_ptr<tinyply::PlyData> _vertex_data;
  233. std::vector<std::string> _vertex_header;
  234. std::shared_ptr<tinyply::PlyData> _face_data;
  235. std::vector<std::string> _face_header;
  236. std::shared_ptr<tinyply::PlyData> _edge_data;
  237. std::vector<std::string> _edge_header;
  238. for (auto c : file.get_comments())
  239. comments.push_back(c);
  240. for (auto e : file.get_elements())
  241. {
  242. if(e.name == "vertex" ) // found a vertex
  243. {
  244. for (auto p : e.properties)
  245. {
  246. if(vertex_std.find(p.name) == vertex_std.end())
  247. {
  248. _vertex_header.push_back(p.name);
  249. }
  250. }
  251. }
  252. else if(e.name == "face" ) // found face
  253. {
  254. for (auto p : e.properties)
  255. {
  256. if(face_std.find(p.name) == face_std.end())
  257. {
  258. _face_header.push_back(p.name);
  259. }
  260. }
  261. }
  262. else if(e.name == "edge" ) // found edge
  263. {
  264. for (auto p : e.properties)
  265. {
  266. if(edge_std.find(p.name) == edge_std.end())
  267. {
  268. _edge_header.push_back(p.name);
  269. }
  270. }
  271. }
  272. // skip the unknown entries
  273. }
  274. // The header information can be used to programmatically extract properties on elements
  275. // known to exist in the header prior to reading the data. For brevity of this sample, properties
  276. // like vertex position are hard-coded:
  277. try {
  278. vertices = file.request_properties_from_element("vertex", { "x", "y", "z" });
  279. }
  280. catch (const std::exception & ) { }
  281. try {
  282. normals = file.request_properties_from_element("vertex", { "nx", "ny", "nz" });
  283. }
  284. catch (const std::exception & ) { }
  285. //Try texture coordinates with several names
  286. try {
  287. //texture_u texture_v are the names used by meshlab to store textures
  288. texcoords = file.request_properties_from_element("vertex", { "texture_u", "texture_v" });
  289. }
  290. catch (const std::exception & ) { }
  291. if (!texcoords)
  292. {
  293. try {
  294. //u v are the naive names
  295. texcoords = file.request_properties_from_element("vertex", { "u", "v" });
  296. }
  297. catch (const std::exception & ) { }
  298. }
  299. if (!texcoords)
  300. {
  301. try {
  302. //s t were the names used by blender and the previous libigl PLY reader.
  303. texcoords = file.request_properties_from_element("vertex", { "s", "t" });
  304. }
  305. catch (const std::exception & ) { }
  306. }
  307. // Providing a list size hint (the last argument) is a 2x performance improvement. If you have
  308. // arbitrary ply files, it is best to leave this 0.
  309. try {
  310. faces = file.request_properties_from_element( "face", { "vertex_indices" }, 0);
  311. }
  312. catch (const std::exception & ) { }
  313. if (!faces)
  314. {
  315. try {
  316. // alternative name of the elements
  317. faces = file.request_properties_from_element( "face", { "vertex_index" },0);
  318. }
  319. catch (const std::exception & ) { }
  320. }
  321. if (!faces)
  322. {
  323. try {
  324. // try using tristrips
  325. tristrips = file.request_properties_from_element( "tristrips", { "vertex_indices" }, 0);
  326. }
  327. catch (const std::exception & ) { }
  328. if (!tristrips)
  329. {
  330. try {
  331. // alternative name of the elements
  332. tristrips = file.request_properties_from_element( "tristrips", { "vertex_index" }, 0);
  333. }
  334. catch (const std::exception & ) { }
  335. }
  336. }
  337. try {
  338. edges = file.request_properties_from_element("edge", { "vertex1", "vertex2" });
  339. }
  340. catch (const std::exception & ) { }
  341. if(! _vertex_header.empty())
  342. _vertex_data = file.request_properties_from_element( "vertex", _vertex_header);
  343. if(! _face_header.empty())
  344. _face_data = file.request_properties_from_element( "face", _face_header);
  345. if(! _edge_header.empty())
  346. _edge_data = file.request_properties_from_element( "edge", _edge_header);
  347. // Parse the geometry data
  348. file.read(ply_stream);
  349. if (!vertices || !tinyply_buffer_to_matrix(*vertices,V,vertices->count,3) ) {
  350. V.resize(0,0);
  351. }
  352. if (!normals || !tinyply_buffer_to_matrix(*normals,N,normals->count,3) ) {
  353. N.resize(0,0);
  354. }
  355. if (!texcoords || !tinyply_buffer_to_matrix(*texcoords,UV,texcoords->count,2) ) {
  356. UV.resize(0,0);
  357. }
  358. //HACK: Unfortunately, tinyply doesn't store list size as a separate variable
  359. if (!faces || !tinyply_buffer_to_matrix(*faces, F, faces->count, faces->buffer.size_bytes()/(tinyply::PropertyTable[faces->t].stride*faces->count) )) {
  360. if(tristrips) { // need to convert to faces
  361. // code based on blender importer for ply
  362. // converting triangle strips into triangles
  363. // tinyply supports tristrips of the same length only
  364. size_t el_count = tristrips->buffer.size_bytes()/(tinyply::PropertyTable[tristrips->t].stride*tristrips->count);
  365. // all strips should have tristrips->count elements
  366. if(!tinyply_tristrips_to_faces(*tristrips, F , tristrips->count, el_count))
  367. F.resize(0,0);
  368. } else {
  369. F.resize(0,0);
  370. }
  371. }
  372. if(!edges || !tinyply_buffer_to_matrix(*edges,E, edges->count,2)) {
  373. E.resize(0,0);
  374. }
  375. /// convert vertex data:
  376. Vheader=_vertex_header;
  377. if(_vertex_header.empty())
  378. {
  379. VD.resize(0,0);
  380. }
  381. else
  382. {
  383. VD.resize(vertices->count,_vertex_header.size());
  384. tinyply_buffer_to_matrix(*_vertex_data, VD, vertices->count, _vertex_header.size());
  385. }
  386. /// convert face data:
  387. Fheader=_face_header;
  388. if(_face_header.empty())
  389. {
  390. FD.resize(0,0);
  391. }
  392. else
  393. {
  394. FD.resize(faces->count, _face_header.size());
  395. tinyply_buffer_to_matrix(*_face_data, FD, faces->count, 1);
  396. }
  397. /// convert edge data:
  398. Eheader=_edge_header;
  399. if(_edge_header.empty())
  400. {
  401. ED.resize(0,0);
  402. }
  403. else
  404. {
  405. ED.resize(_edge_data->count, _edge_header.size());
  406. tinyply_buffer_to_matrix(*_edge_data, ED, _edge_data->count, _edge_header.size());
  407. }
  408. return true;
  409. }
  410. template <
  411. typename DerivedV,
  412. typename DerivedF,
  413. typename DerivedE,
  414. typename DerivedN,
  415. typename DerivedUV,
  416. typename DerivedVD,
  417. typename DerivedFD,
  418. typename DerivedED
  419. >
  420. IGL_INLINE bool readPLY(
  421. const std::string& ply_file,
  422. Eigen::PlainObjectBase<DerivedV> & V,
  423. Eigen::PlainObjectBase<DerivedF> & F,
  424. Eigen::PlainObjectBase<DerivedE> & E,
  425. Eigen::PlainObjectBase<DerivedN> & N,
  426. Eigen::PlainObjectBase<DerivedUV> & UV,
  427. Eigen::PlainObjectBase<DerivedVD> & VD,
  428. std::vector<std::string> & VDheader,
  429. Eigen::PlainObjectBase<DerivedFD> & FD,
  430. std::vector<std::string> & FDheader,
  431. Eigen::PlainObjectBase<DerivedED> & ED,
  432. std::vector<std::string> & EDheader,
  433. std::vector<std::string> & comments
  434. )
  435. {
  436. std::ifstream ply_stream(ply_file, std::ios::binary);
  437. if (ply_stream.fail())
  438. {
  439. std::cerr << "ReadPLY: Error opening file " << ply_file << std::endl;
  440. return false;
  441. }
  442. try
  443. {
  444. return readPLY(ply_stream, V, F, E, N, UV, VD, VDheader, FD,FDheader, ED, EDheader, comments );
  445. } catch (const std::exception& e) {
  446. std::cerr << "ReadPLY error: " << ply_file << e.what() << std::endl;
  447. }
  448. return false;
  449. }
  450. template <
  451. typename DerivedV,
  452. typename DerivedF,
  453. typename DerivedE,
  454. typename DerivedN,
  455. typename DerivedUV,
  456. typename DerivedD
  457. >
  458. IGL_INLINE bool readPLY(
  459. const std::string & filename,
  460. Eigen::PlainObjectBase<DerivedV> & V,
  461. Eigen::PlainObjectBase<DerivedF> & F,
  462. Eigen::PlainObjectBase<DerivedE> & E,
  463. Eigen::PlainObjectBase<DerivedN> & N,
  464. Eigen::PlainObjectBase<DerivedUV> & UV,
  465. Eigen::PlainObjectBase<DerivedD> & VD,
  466. std::vector<std::string> & Vheader
  467. )
  468. {
  469. Eigen::MatrixXd FD,ED;
  470. std::vector<std::string> Fheader,Eheader;
  471. std::vector<std::string> comments;
  472. return readPLY(filename,V,F,E,N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments);
  473. }
  474. template <
  475. typename DerivedV,
  476. typename DerivedF,
  477. typename DerivedE,
  478. typename DerivedN,
  479. typename DerivedUV
  480. >
  481. IGL_INLINE bool readPLY(
  482. const std::string & filename,
  483. Eigen::PlainObjectBase<DerivedV> & V,
  484. Eigen::PlainObjectBase<DerivedF> & F,
  485. Eigen::PlainObjectBase<DerivedE> & E,
  486. Eigen::PlainObjectBase<DerivedN> & N,
  487. Eigen::PlainObjectBase<DerivedUV> & UV
  488. )
  489. {
  490. Eigen::MatrixXd VD,FD,ED;
  491. std::vector<std::string> Vheader,Fheader,Eheader;
  492. std::vector<std::string> comments;
  493. return readPLY(filename,V,F,E, N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments);
  494. }
  495. template <
  496. typename DerivedV,
  497. typename DerivedF,
  498. typename DerivedN,
  499. typename DerivedUV
  500. >
  501. IGL_INLINE bool readPLY(
  502. const std::string & filename,
  503. Eigen::PlainObjectBase<DerivedV> & V,
  504. Eigen::PlainObjectBase<DerivedF> & F,
  505. Eigen::PlainObjectBase<DerivedN> & N,
  506. Eigen::PlainObjectBase<DerivedUV> & UV
  507. )
  508. {
  509. Eigen::MatrixXd VD,FD,ED;
  510. Eigen::MatrixXi E;
  511. std::vector<std::string> Vheader,Fheader,Eheader;
  512. std::vector<std::string> comments;
  513. return readPLY(filename,V,F,E, N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments);
  514. }
  515. template <
  516. typename DerivedV,
  517. typename DerivedF
  518. >
  519. IGL_INLINE bool readPLY(
  520. const std::string & filename,
  521. Eigen::PlainObjectBase<DerivedV> & V,
  522. Eigen::PlainObjectBase<DerivedF> & F
  523. )
  524. {
  525. Eigen::MatrixXd N,UV;
  526. Eigen::MatrixXd VD,FD,ED;
  527. Eigen::MatrixXi E;
  528. std::vector<std::string> Vheader,Fheader,Eheader;
  529. std::vector<std::string> comments;
  530. return readPLY(filename,V,F,E,N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments);
  531. }
  532. template <
  533. typename DerivedV,
  534. typename DerivedF,
  535. typename DerivedE
  536. >
  537. IGL_INLINE bool readPLY(
  538. const std::string & filename,
  539. Eigen::PlainObjectBase<DerivedV> & V,
  540. Eigen::PlainObjectBase<DerivedF> & F,
  541. Eigen::PlainObjectBase<DerivedE> & E
  542. )
  543. {
  544. Eigen::MatrixXd N,UV;
  545. Eigen::MatrixXd VD,FD,ED;
  546. std::vector<std::string> Vheader,Fheader,Eheader;
  547. std::vector<std::string> comments;
  548. return readPLY(filename,V,F,E,N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments);
  549. }
  550. } //igl namespace
  551. #ifdef IGL_STATIC_LIBRARY
  552. // Explicit template instantiation
  553. template bool igl::readPLY<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -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> >&);
  554. template bool igl::readPLY<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
  555. template bool igl::readPLY<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
  556. template bool igl::readPLY<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -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> >&);
  557. template bool igl::readPLY<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -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> >&);
  558. template bool igl::readPLY<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> >&);
  559. template bool igl::readPLY<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
  560. template bool igl::readPLY<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&);
  561. template bool igl::readPLY<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
  562. template bool igl::readPLY<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -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> >&);
  563. template bool igl::readPLY<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -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> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&);
  564. template bool igl::readPLY<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&);
  565. #endif