DGtal 1.4.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 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;
73 std::string linestr;
74 std::string keyword;
75 std::string indices;
76 RealPoint p;
77 RealVector n;
78 std::getline( input, linestr );
79 Index l = 0;
80 for ( ; input.good() && ! input.eof(); std::getline( input, linestr ), l++ )
81 {
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;
102 }
103 face.push_back(v);
104 Index vn = vtxinfo.size() >= 3 ? std::stoi( vtxinfo[ 2 ] ) : v-1;
105 face_normals.push_back( vn - 1 );
106 indices = "";
107 }
108 if ( ! face.empty() && verifyIndicesUniqueness( face ) )
109 {
110 faces.push_back( face );
111 faces_normals_idx.push_back( face_normals );
112 }
113 }
114 // Weird: necessary to clear them.
115 keyword = ""; linestr = "";
116 }
117 // Creating SurfaceMesh
118 trace.info() << "[SurfaceMeshReader::readOBJ] Read"
119 << " #lines=" << l
120 << " #V=" << vertices.size()
121 << " #VN=" << normals.size()
122 << " #F=" << faces.size() << std::endl;
123 if ( input.bad() )
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() );
128 if ( ! ok )
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;
138 }
139 if ( ! normals.empty() )
140 { // Build face normal map
141 std::vector< RealVector > faces_normals;
142 for ( auto face_n_indices : faces_normals_idx )
143 {
144 RealVector _n;
145 for ( auto k : face_n_indices ) _n += normals[ k ];
146 _n /= face_n_indices.size();
147 faces_normals.push_back( _n );
148 }
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;
155 }
156 return ( ! input.bad() ) && ok;
157}
158
159///////////////////////////////////////////////////////////////////////////////
160///////////////////////////////////////////////////////////////////////////////