2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU Lesser General Public License as
4 * published by the Free Software Foundation, either version 3 of the
5 * License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * @file SurfaceMeshReader.ih
19 * @author Jacques-Olivier Lachaud (\c jacques-olivier.lachaud@univ-savoie.fr )
20 * Laboratory of Mathematics (CNRS, UMR 5127), University of Savoie, France
24 * Implementation of inline methods defined in SurfaceMeshReader.h
26 * This file is part of the DGtal library.
30 //////////////////////////////////////////////////////////////////////////////
33 //////////////////////////////////////////////////////////////////////////////
36 ///////////////////////////////////////////////////////////////////////////////
37 // IMPLEMENTATION of inline methods.
38 ///////////////////////////////////////////////////////////////////////////////
40 //-----------------------------------------------------------------------------
41 template <typename TRealPoint, typename TRealVector>
43 DGtal::SurfaceMeshReader<TRealPoint, TRealVector>::
44 verifyIndicesUniqueness( const std::vector< Index > &indices )
46 std::set<Index> sindices( indices.begin(), indices.end() );
47 return sindices.size() == indices.size();
50 //-----------------------------------------------------------------------------
51 template <typename TRealPoint, typename TRealVector>
52 std::vector< std::string >
53 DGtal::SurfaceMeshReader<TRealPoint, TRealVector>::
54 split( const std::string& str, char delim )
56 std::stringstream ss(str);
58 std::vector< std::string > cont;
59 while ( std::getline( ss, token, delim ) ) cont.push_back(token);
63 //-----------------------------------------------------------------------------
64 template <typename TRealPoint, typename TRealVector>
66 DGtal::SurfaceMeshReader<TRealPoint, TRealVector>::
67 readOBJ( std::istream & input, SurfaceMesh & smesh )
69 std::vector<RealPoint> vertices;
70 std::vector<RealVector> normals;
71 std::vector< std::vector< Index > > faces;
72 std::vector< std::vector< Index > > faces_normals_idx;
78 std::getline( input, linestr );
80 for ( ; input.good() && ! input.eof(); std::getline( input, linestr ), l++ )
82 if ( linestr.empty() ) continue; // skip empty line
83 if ( linestr[0] == '#' ) continue; // skip comment line
84 std::istringstream lineinput( linestr );
85 std::operator>>( lineinput, keyword ); // lineinput >> keyword;
86 if ( keyword == "v" ) {
87 lineinput >> p[ 0 ] >> p[ 1 ] >> p[ 2 ];
88 vertices.push_back( p );
89 } else if ( keyword == "vn" ) {
90 lineinput >> n[ 0 ] >> n[ 1 ] >> n[ 2 ];
91 normals.push_back( n );
92 } else if ( keyword == "f" ) {
93 std::vector< Index > face, face_normals;
94 while ( ! lineinput.eof() ) {
95 std::operator>>( lineinput, indices ); // lineinput >> indices;
96 if ( indices.empty() ) break;
97 auto vtxinfo = split( indices, '/' );
98 if ( vtxinfo.size() == 0 ) break;
99 Index v = std::stoi( vtxinfo[ 0 ] );
100 Index vn = vtxinfo.size() >= 3 ? std::stoi( vtxinfo[ 2 ] ) : v;
101 face.push_back( v - 1 );
102 face_normals.push_back( vn - 1 );
105 if ( ! face.empty() && verifyIndicesUniqueness( face ) )
107 faces.push_back( face );
108 faces_normals_idx.push_back( face_normals );
111 // Weird: necessary to clear them.
112 keyword = ""; linestr = "";
114 // Creating SurfaceMesh
115 trace.info() << "[SurfaceMeshReader::readOBJ] Read"
117 << " #V=" << vertices.size()
118 << " #VN=" << normals.size()
119 << " #F=" << faces.size() << std::endl;
121 trace.warning() << "[SurfaceMeshReader::readOBJ] Some I/O error occured."
122 << " Proceeding but the mesh may be damaged." << std::endl;
123 bool ok = smesh.init( vertices.begin(), vertices.end(),
124 faces.begin(), faces.end() );
126 trace.warning() << "[SurfaceMeshReader::readOBJ]"
127 << " Error initializing mesh." << std::endl;
128 if ( ( ! normals.empty() ) && ( normals.size() == vertices.size() ) )
129 { // Build vertex normal map
130 bool ok_vtx_normals = smesh.setVertexNormals( normals.begin(), normals.end() );
131 if ( ! ok_vtx_normals )
132 trace.warning() << "[SurfaceMeshReader::readOBJ]"
133 << " Error setting vertex normals." << std::endl;
134 ok = ok && ok_vtx_normals;
136 if ( ! normals.empty() )
137 { // Build face normal map
138 std::vector< RealVector > faces_normals;
140 for ( auto face_n_indices : faces_normals_idx )
143 for ( auto k : face_n_indices ) n += normals[ k ];
144 n /= face_n_indices.size();
145 faces_normals.push_back( n );
147 bool ok_face_normals = smesh.setFaceNormals( faces_normals.begin(),
148 faces_normals.end() );
149 if ( ! ok_face_normals )
150 trace.warning() << "[SurfaceMeshReader::readOBJ]"
151 << " Error setting face normals." << std::endl;
152 ok = ok && ok_face_normals;
154 return ( ! input.bad() ) && ok;
157 ///////////////////////////////////////////////////////////////////////////////
158 ///////////////////////////////////////////////////////////////////////////////