DGtal 2.0.0
Loading...
Searching...
No Matches
SurfaceMeshReader.ih
1/**
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.
6 *
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.
11 *
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/>.
14 *
15 **/
16
17/**
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
21 *
22 * @date 2020/02/18
23 *
24 * Implementation of inline methods defined in SurfaceMeshReader.h
25 *
26 * This file is part of the DGtal library.
27 */
28
29
30//////////////////////////////////////////////////////////////////////////////
31#include <cstdlib>
32#include <limits>
33//////////////////////////////////////////////////////////////////////////////
34
35
36///////////////////////////////////////////////////////////////////////////////
37// IMPLEMENTATION of inline methods.
38///////////////////////////////////////////////////////////////////////////////
39
40//-----------------------------------------------------------------------------
41template <typename TRealPoint, typename TRealVector>
42bool
43DGtal::SurfaceMeshReader<TRealPoint, TRealVector>::
44verifyIndicesUniqueness( const std::vector< Index > &indices )
45{
46 std::set<Index> sindices( indices.begin(), indices.end() );
47 return sindices.size() == indices.size();
48}
49
50//-----------------------------------------------------------------------------
51template <typename TRealPoint, typename TRealVector>
52std::vector< std::string >
53DGtal::SurfaceMeshReader<TRealPoint, TRealVector>::
54split( const std::string& str, char delim )
55{
56 std::stringstream ss(str);
57 std::string token;
58 std::vector< std::string > cont;
59 while ( std::getline( ss, token, delim ) ) cont.push_back(token);
60 return cont;
61}
62
63//-----------------------------------------------------------------------------
64template <typename TRealPoint, typename TRealVector>
65bool
66DGtal::SurfaceMeshReader<TRealPoint, TRealVector>::
67readOBJ( std::istream & input, SurfaceMesh & smesh )
68{
69 Materials materials;
70 return readOBJ( input, smesh, materials );
71}
72//-----------------------------------------------------------------------------
73template <typename TRealPoint, typename TRealVector>
74bool
75DGtal::SurfaceMeshReader<TRealPoint, TRealVector>::
76readOBJ( std::istream & input, SurfaceMesh & smesh, Materials& materials )
77{
78 std::vector<RealPoint> vertices;
79 std::vector<RealVector> normals;
80 std::vector< std::vector< Index > > faces;
81 std::vector< std::vector< Index > > faces_normals_idx;
82 std::string linestr;
83 std::string keyword;
84 std::string indices;
85 RealPoint p;
86 RealVector n;
87 std::getline( input, linestr );
88 Index l = 0;
89 int mat = 0; // current material
90 for ( ; input.good() && ! input.eof(); std::getline( input, linestr ), l++ )
91 {
92 if ( linestr.empty() ) continue; // skip empty line
93 if ( linestr[0] == '#' ) continue; // skip comment line
94 std::istringstream lineinput( linestr );
95 std::operator>>( lineinput, keyword ); // lineinput >> keyword;
96 if ( keyword == "v" )
97 {
98 lineinput >> p[ 0 ] >> p[ 1 ] >> p[ 2 ];
99 vertices.push_back( p );
100 }
101 else if ( keyword == "vn" )
102 {
103 lineinput >> n[ 0 ] >> n[ 1 ] >> n[ 2 ];
104 normals.push_back( n );
105 }
106 else if ( keyword == "usemtl" )
107 {
108 std::string strmat;
109 std::operator>>( lineinput, strmat ); // lineinput >> keyword;
110 auto matinfo = split( strmat, '_' );
111 mat = matinfo.size() >= 2 ? std::stoi( matinfo[ 1 ] ) : 0;
112 }
113 else if ( keyword == "f" )
114 {
115 std::vector< Index > face, face_normals;
116 while ( ! lineinput.eof() )
117 {
118 std::operator>>( lineinput, indices ); // lineinput >> indices;
119 if ( indices.empty() ) break;
120 auto vtxinfo = split( indices, '/' );
121 if ( vtxinfo.size() == 0 ) break;
122 Index v = static_cast<Index>((int)std::stoi( vtxinfo[ 0 ] )-1);
123 if (v < 0 )
124 { // special case of relative indices (ie negative index);
125 v = vertices.size() + v+1;
126 }
127 face.push_back(v);
128 Index vn = vtxinfo.size() >= 3 ? std::stoi( vtxinfo[ 2 ] ) : v-1;
129 face_normals.push_back( vn - 1 );
130 indices = "";
131 }
132 if ( ! face.empty() && verifyIndicesUniqueness( face ) )
133 {
134 faces.push_back( face );
135 faces_normals_idx.push_back( face_normals );
136 materials.push_back( mat );
137 }
138 }
139 // Weird: necessary to clear them.
140 keyword = ""; linestr = "";
141 }
142 // Creating SurfaceMesh
143 trace.info() << "[SurfaceMeshReader::readOBJ] Read"
144 << " #lines=" << l
145 << " #V=" << vertices.size()
146 << " #VN=" << normals.size()
147 << " #F=" << faces.size() << std::endl;
148 if ( input.bad() )
149 trace.warning() << "[SurfaceMeshReader::readOBJ] Some I/O error occured."
150 << " Proceeding but the mesh may be damaged." << std::endl;
151 bool ok = smesh.init( vertices.begin(), vertices.end(),
152 faces.begin(), faces.end() );
153 if ( ! ok )
154 trace.warning() << "[SurfaceMeshReader::readOBJ]"
155 << " Error initializing mesh." << std::endl;
156 if ( ( ! normals.empty() ) && ( normals.size() == vertices.size() ) )
157 { // Build vertex normal map
158 bool ok_vtx_normals = smesh.setVertexNormals( normals.begin(), normals.end() );
159 if ( ! ok_vtx_normals )
160 trace.warning() << "[SurfaceMeshReader::readOBJ]"
161 << " Error setting vertex normals." << std::endl;
162 ok = ok && ok_vtx_normals;
163 }
164 if ( ! normals.empty() )
165 { // Build face normal map
166 std::vector< RealVector > faces_normals;
167 for ( auto face_n_indices : faces_normals_idx )
168 {
169 RealVector _n;
170 for ( auto k : face_n_indices ) _n += normals[ k ];
171 _n /= face_n_indices.size();
172 faces_normals.push_back( _n );
173 }
174 bool ok_face_normals = smesh.setFaceNormals( faces_normals.begin(),
175 faces_normals.end() );
176 if ( ! ok_face_normals )
177 trace.warning() << "[SurfaceMeshReader::readOBJ]"
178 << " Error setting face normals." << std::endl;
179 ok = ok && ok_face_normals;
180 }
181 return ( ! input.bad() ) && ok;
182}
183
184///////////////////////////////////////////////////////////////////////////////
185///////////////////////////////////////////////////////////////////////////////