// This file is part of libigl, a simple c++ geometry processing library. // // Copyright (C) 2014 Alec Jacobson // // 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 "writePLY.h" #include #include #include namespace { template int ply_type(); template <> int ply_type(){ return PLY_CHAR; } template <> int ply_type(){ return PLY_SHORT; } template <> int ply_type(){ return PLY_INT; } template <> int ply_type(){ return PLY_UCHAR; } template <> int ply_type(){ return PLY_SHORT; } template <> int ply_type(){ return PLY_UINT; } template <> int ply_type(){ return PLY_FLOAT; } template <> int ply_type(){ return PLY_DOUBLE; } } template < typename DerivedV, typename DerivedF, typename DerivedN, typename DerivedUV> IGL_INLINE bool igl::writePLY( const std::string & filename, const Eigen::MatrixBase & V, const Eigen::MatrixBase & F, const Eigen::MatrixBase & N, const Eigen::MatrixBase & UV, const bool ascii) { // Largely based on obj2ply.c typedef typename DerivedV::Scalar VScalar; typedef typename DerivedN::Scalar NScalar; typedef typename DerivedUV::Scalar UVScalar; typedef typename DerivedF::Scalar FScalar; typedef struct Vertex { VScalar x,y,z,w; /* position */ NScalar nx,ny,nz; /* surface normal */ UVScalar s,t; /* texture coordinates */ } Vertex; typedef struct Face { unsigned char nverts; /* number of vertex indices in list */ FScalar *verts; /* vertex index list */ } Face; igl::ply::PlyProperty vert_props[] = { /* list of property information for a vertex */ {"x", ply_type(), ply_type(),offsetof(Vertex,x),0,0,0,0}, {"y", ply_type(), ply_type(),offsetof(Vertex,y),0,0,0,0}, {"z", ply_type(), ply_type(),offsetof(Vertex,z),0,0,0,0}, {"nx",ply_type(), ply_type(),offsetof(Vertex,nx),0,0,0,0}, {"ny",ply_type(), ply_type(),offsetof(Vertex,ny),0,0,0,0}, {"nz",ply_type(), ply_type(),offsetof(Vertex,nz),0,0,0,0}, {"s", ply_type(),ply_type(),offsetof(Vertex,s),0,0,0,0}, {"t", ply_type(),ply_type(),offsetof(Vertex,t),0,0,0,0}, }; igl::ply::PlyProperty face_props[] = { /* list of property information for a face */ {"vertex_indices", ply_type(), ply_type(), offsetof(Face,verts), 1, PLY_UCHAR, PLY_UCHAR, offsetof(Face,nverts)}, }; const bool has_normals = N.rows() > 0; const bool has_texture_coords = UV.rows() > 0; std::vector vlist(V.rows()); std::vector flist(F.rows()); for(size_t i = 0;i<(size_t)V.rows();i++) { vlist[i].x = V(i,0); vlist[i].y = V(i,1); vlist[i].z = V(i,2); if(has_normals) { vlist[i].nx = N(i,0); vlist[i].ny = N(i,1); vlist[i].nz = N(i,2); } if(has_texture_coords) { vlist[i].s = UV(i,0); vlist[i].t = UV(i,1); } } for(size_t i = 0;i<(size_t)F.rows();i++) { flist[i].nverts = F.cols(); flist[i].verts = new FScalar[F.cols()]; for(size_t c = 0;c<(size_t)F.cols();c++) { flist[i].verts[c] = F(i,c); } } const char * elem_names[] = {"vertex","face"}; FILE * fp = fopen(filename.c_str(),"w"); if(fp==NULL) { return false; } igl::ply::PlyFile * ply = igl::ply::ply_write(fp, 2,elem_names, (ascii ? PLY_ASCII : PLY_BINARY_LE)); if(ply==NULL) { return false; } std::vector plist; plist.push_back(vert_props[0]); plist.push_back(vert_props[1]); plist.push_back(vert_props[2]); if (has_normals) { plist.push_back(vert_props[3]); plist.push_back(vert_props[4]); plist.push_back(vert_props[5]); } if (has_texture_coords) { plist.push_back(vert_props[6]); plist.push_back(vert_props[7]); } ply_describe_element(ply, "vertex", V.rows(),plist.size(), &plist[0]); ply_describe_element(ply, "face", F.rows(),1,&face_props[0]); ply_header_complete(ply); int native_binary_type = igl::ply::get_native_binary_type2(); ply_put_element_setup(ply, "vertex"); for(const auto v : vlist) { ply_put_element(ply, (void *) &v, &native_binary_type); } ply_put_element_setup(ply, "face"); for(const auto f : flist) { ply_put_element(ply, (void *) &f, &native_binary_type); } ply_close(ply); for(size_t i = 0;i<(size_t)F.rows();i++) { delete[] flist[i].verts; } return true; } template < typename DerivedV, typename DerivedF> IGL_INLINE bool igl::writePLY( const std::string & filename, const Eigen::MatrixBase & V, const Eigen::MatrixBase & F, const bool ascii) { Eigen::Matrix N,UV; return writePLY(filename,V,F,N,UV,ascii); } #ifdef IGL_STATIC_LIBRARY // Explicit template instantiation // generated by autoexplicit.sh template bool igl::writePLY, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, bool); // generated by autoexplicit.sh template bool igl::writePLY, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, bool); template bool igl::writePLY, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, bool); template bool igl::writePLY, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, bool); template bool igl::writePLY, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, bool); #endif