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 = static_cast<Index>((int)std::stoi( vtxinfo[ 0 ] )-1);
100 if (v < 0 ){ // special case of relative indices (ie negative index);
101 v = vertices.size() + v+1;
104 Index vn = vtxinfo.size() >= 3 ? std::stoi( vtxinfo[ 2 ] ) : v-1;
105 face_normals.push_back( vn - 1 );
108 if ( ! face.empty() && verifyIndicesUniqueness( face ) )
110 faces.push_back( face );
111 faces_normals_idx.push_back( face_normals );
114 // Weird: necessary to clear them.
115 keyword = ""; linestr = "";
117 // Creating SurfaceMesh
118 trace.info() << "[SurfaceMeshReader::readOBJ] Read"
120 << " #V=" << vertices.size()
121 << " #VN=" << normals.size()
122 << " #F=" << faces.size() << std::endl;
124 trace.warning() << "[SurfaceMeshReader::readOBJ] Some I/O error occured."
125 << " Proceeding but the mesh may be damaged." << std::endl;
126 bool ok = smesh.init( vertices.begin(), vertices.end(),
127 faces.begin(), faces.end() );
129 trace.warning() << "[SurfaceMeshReader::readOBJ]"
130 << " Error initializing mesh." << std::endl;
131 if ( ( ! normals.empty() ) && ( normals.size() == vertices.size() ) )
132 { // Build vertex normal map
133 bool ok_vtx_normals = smesh.setVertexNormals( normals.begin(), normals.end() );
134 if ( ! ok_vtx_normals )
135 trace.warning() << "[SurfaceMeshReader::readOBJ]"
136 << " Error setting vertex normals." << std::endl;
137 ok = ok && ok_vtx_normals;
139 if ( ! normals.empty() )
140 { // Build face normal map
141 std::vector< RealVector > faces_normals;
142 for ( auto face_n_indices : faces_normals_idx )
145 for ( auto k : face_n_indices ) _n += normals[ k ];
146 _n /= face_n_indices.size();
147 faces_normals.push_back( _n );
149 bool ok_face_normals = smesh.setFaceNormals( faces_normals.begin(),
150 faces_normals.end() );
151 if ( ! ok_face_normals )
152 trace.warning() << "[SurfaceMeshReader::readOBJ]"
153 << " Error setting face normals." << std::endl;
154 ok = ok && ok_face_normals;
156 return ( ! input.bad() ) && ok;
159 ///////////////////////////////////////////////////////////////////////////////
160 ///////////////////////////////////////////////////////////////////////////////