1 // This file is part of libigl, a simple c++ geometry processing library.
2 //
3 // Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public License
6 // v. 2.0. If a copy of the MPL was not distributed with this file, You can
7 // obtain one at http://mozilla.org/MPL/2.0/.
8 #include "writePLY.h"
9 #include <vector>
10
11 #include <igl/ply.h>
12 #include <vector>
13
14 namespace
15 {
16 template <typename Scalar> int ply_type();
ply_type()17 template <> int ply_type<char>(){ return PLY_CHAR; }
ply_type()18 template <> int ply_type<short>(){ return PLY_SHORT; }
ply_type()19 template <> int ply_type<int>(){ return PLY_INT; }
ply_type()20 template <> int ply_type<unsigned char>(){ return PLY_UCHAR; }
ply_type()21 template <> int ply_type<unsigned short>(){ return PLY_SHORT; }
ply_type()22 template <> int ply_type<unsigned int>(){ return PLY_UINT; }
ply_type()23 template <> int ply_type<float>(){ return PLY_FLOAT; }
ply_type()24 template <> int ply_type<double>(){ return PLY_DOUBLE; }
25 }
26
27 template <
28 typename DerivedV,
29 typename DerivedF,
30 typename DerivedN,
31 typename DerivedUV>
writePLY(const std::string & filename,const Eigen::MatrixBase<DerivedV> & V,const Eigen::MatrixBase<DerivedF> & F,const Eigen::MatrixBase<DerivedN> & N,const Eigen::MatrixBase<DerivedUV> & UV,const bool ascii)32 IGL_INLINE bool igl::writePLY(
33 const std::string & filename,
34 const Eigen::MatrixBase<DerivedV> & V,
35 const Eigen::MatrixBase<DerivedF> & F,
36 const Eigen::MatrixBase<DerivedN> & N,
37 const Eigen::MatrixBase<DerivedUV> & UV,
38 const bool ascii)
39 {
40 // Largely based on obj2ply.c
41 typedef typename DerivedV::Scalar VScalar;
42 typedef typename DerivedN::Scalar NScalar;
43 typedef typename DerivedUV::Scalar UVScalar;
44 typedef typename DerivedF::Scalar FScalar;
45
46 typedef struct Vertex
47 {
48 VScalar x,y,z,w; /* position */
49 NScalar nx,ny,nz; /* surface normal */
50 UVScalar s,t; /* texture coordinates */
51 } Vertex;
52
53 typedef struct Face
54 {
55 unsigned char nverts; /* number of vertex indices in list */
56 FScalar *verts; /* vertex index list */
57 } Face;
58
59 igl::ply::PlyProperty vert_props[] =
60 { /* list of property information for a vertex */
61 {"x", ply_type<VScalar>(), ply_type<VScalar>(),offsetof(Vertex,x),0,0,0,0},
62 {"y", ply_type<VScalar>(), ply_type<VScalar>(),offsetof(Vertex,y),0,0,0,0},
63 {"z", ply_type<VScalar>(), ply_type<VScalar>(),offsetof(Vertex,z),0,0,0,0},
64 {"nx",ply_type<NScalar>(), ply_type<NScalar>(),offsetof(Vertex,nx),0,0,0,0},
65 {"ny",ply_type<NScalar>(), ply_type<NScalar>(),offsetof(Vertex,ny),0,0,0,0},
66 {"nz",ply_type<NScalar>(), ply_type<NScalar>(),offsetof(Vertex,nz),0,0,0,0},
67 {"s", ply_type<UVScalar>(),ply_type<UVScalar>(),offsetof(Vertex,s),0,0,0,0},
68 {"t", ply_type<UVScalar>(),ply_type<UVScalar>(),offsetof(Vertex,t),0,0,0,0},
69 };
70
71 igl::ply::PlyProperty face_props[] =
72 { /* list of property information for a face */
73 {"vertex_indices", ply_type<FScalar>(), ply_type<FScalar>(),
74 offsetof(Face,verts), 1, PLY_UCHAR, PLY_UCHAR, offsetof(Face,nverts)},
75 };
76 const bool has_normals = N.rows() > 0;
77 const bool has_texture_coords = UV.rows() > 0;
78 std::vector<Vertex> vlist(V.rows());
79 std::vector<Face> flist(F.rows());
80 for(size_t i = 0;i<(size_t)V.rows();i++)
81 {
82 vlist[i].x = V(i,0);
83 vlist[i].y = V(i,1);
84 vlist[i].z = V(i,2);
85 if(has_normals)
86 {
87 vlist[i].nx = N(i,0);
88 vlist[i].ny = N(i,1);
89 vlist[i].nz = N(i,2);
90 }
91 if(has_texture_coords)
92 {
93 vlist[i].s = UV(i,0);
94 vlist[i].t = UV(i,1);
95 }
96 }
97 for(size_t i = 0;i<(size_t)F.rows();i++)
98 {
99 flist[i].nverts = F.cols();
100 flist[i].verts = new FScalar[F.cols()];
101 for(size_t c = 0;c<(size_t)F.cols();c++)
102 {
103 flist[i].verts[c] = F(i,c);
104 }
105 }
106
107 const char * elem_names[] = {"vertex","face"};
108 FILE * fp = fopen(filename.c_str(),"w");
109 if(fp==NULL)
110 {
111 return false;
112 }
113 igl::ply::PlyFile * ply = igl::ply::ply_write(fp, 2,elem_names,
114 (ascii ? PLY_ASCII : PLY_BINARY_LE));
115 if(ply==NULL)
116 {
117 return false;
118 }
119
120 std::vector<igl::ply::PlyProperty> plist;
121 plist.push_back(vert_props[0]);
122 plist.push_back(vert_props[1]);
123 plist.push_back(vert_props[2]);
124 if (has_normals)
125 {
126 plist.push_back(vert_props[3]);
127 plist.push_back(vert_props[4]);
128 plist.push_back(vert_props[5]);
129 }
130 if (has_texture_coords)
131 {
132 plist.push_back(vert_props[6]);
133 plist.push_back(vert_props[7]);
134 }
135 ply_describe_element(ply, "vertex", V.rows(),plist.size(),
136 &plist[0]);
137
138 ply_describe_element(ply, "face", F.rows(),1,&face_props[0]);
139 ply_header_complete(ply);
140 int native_binary_type = igl::ply::get_native_binary_type2();
141 ply_put_element_setup(ply, "vertex");
142 for(const auto v : vlist)
143 {
144 ply_put_element(ply, (void *) &v, &native_binary_type);
145 }
146 ply_put_element_setup(ply, "face");
147 for(const auto f : flist)
148 {
149 ply_put_element(ply, (void *) &f, &native_binary_type);
150 }
151
152 ply_close(ply);
153 for(size_t i = 0;i<(size_t)F.rows();i++)
154 {
155 delete[] flist[i].verts;
156 }
157 return true;
158 }
159
160 template <
161 typename DerivedV,
162 typename DerivedF>
writePLY(const std::string & filename,const Eigen::MatrixBase<DerivedV> & V,const Eigen::MatrixBase<DerivedF> & F,const bool ascii)163 IGL_INLINE bool igl::writePLY(
164 const std::string & filename,
165 const Eigen::MatrixBase<DerivedV> & V,
166 const Eigen::MatrixBase<DerivedF> & F,
167 const bool ascii)
168 {
169 Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic> N,UV;
170 return writePLY(filename,V,F,N,UV,ascii);
171 }
172
173 #ifdef IGL_STATIC_LIBRARY
174 // Explicit template instantiation
175 // generated by autoexplicit.sh
176 template bool igl::writePLY<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, bool);
177 // generated by autoexplicit.sh
178 template bool igl::writePLY<Eigen::Matrix<double, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, bool);
179 template bool igl::writePLY<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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, bool);
180 template bool igl::writePLY<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, bool);
181 template bool igl::writePLY<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, bool);
182 #endif
183