DGtal 1.3.0
Loading...
Searching...
No Matches
MeshReader.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 MeshReader.ih
19 * @author Bertrand Kerautret (\c kerautre@loria.fr )
20 * LORIA (CNRS, UMR 7503), University of Nancy, France
21 *
22 * @date 2012/06/29
23 *
24 * Implementation of inline methods defined in MeshReader.h
25 *
26 * This file is part of the DGtal library.
27 */
28
29///////////////////////////////////////////////////////////////////////////////
30// IMPLEMENTATION of inline methods.
31///////////////////////////////////////////////////////////////////////////////
32
33//////////////////////////////////////////////////////////////////////////////
34#include <cstdlib>
35#include <cstdlib>
36#include <iostream>
37#include <fstream>
38#include <sstream>
39#include <map>
40#include <string>
41//////////////////////////////////////////////////////////////////////////////
42
43#include "DGtal/helpers/StdDefs.h"
44#include "DGtal/io/readers/SurfaceMeshReader.h"
45
46///////////////////////////////////////////////////////////////////////////////
47// Implementation of inline methods //
48
49
50
51
52template <typename TPoint>
53inline
54bool
55DGtal::MeshReader<TPoint>::importOFFFile(const std::string & aFilename,
56 DGtal::Mesh<TPoint> & aMesh,
57 bool invertVertexOrder)
58{
59 std::ifstream infile;
60 DGtal::IOException dgtalio;
61 try
62 {
63 infile.open (aFilename.c_str(), std::ifstream::in);
64 }
65 catch( ... )
66 {
67 trace.error() << "MeshReader : can't open " << aFilename << std::endl;
68 throw dgtalio;
69 }
70 std::string str;
71 getline( infile, str );
72
73 if ( ! infile.good() )
74 {
75 trace.error() << "MeshReader : can't read " << aFilename << std::endl;
76 throw dgtalio;
77 }
78 if ( str.substr(0,3) != "OFF" && str.substr(0,4) != "NOFF" && str.substr(0,5) != "CNOFF")
79 {
80 std::cerr <<"*" <<str<<"*"<< std::endl;
81 trace.error() << "MeshReader : No OFF, NOFF or CNOFF format in " << aFilename << std::endl;
82 throw dgtalio;
83 }
84 if ( str.substr(0,4) == "NOFF")
85 {
86 trace.warning() << "MeshReader : reading NOFF format from importOFFFile (normal vectors will be ignored)..." << std::endl;
87 }
88
89 // Processing comments
90 do
91 {
92 getline( infile, str );
93 if ( ! infile.good() )
94 {
95 trace.error() << "MeshReader : Invalid format in " << aFilename << std::endl;
96 throw dgtalio;
97 }
98 }
99 while ( str[ 0 ] == '#' || str=="" || str=="\r" || str=="\n" );
100 std::istringstream str_in( str );
101 int nbPoints, nbFaces, nbEdges;
102 str_in >> nbPoints;
103 str_in >> nbFaces;
104 str_in >> nbEdges;
105 do
106 {
107 getline( infile, str );
108 if ( ! infile.good() )
109 {
110 trace.error() << "MeshReader : Invalid format in " << aFilename << std::endl;
111 throw dgtalio;
112 }
113 }
114 while ( str[ 0 ] == '#' || str=="" || str=="\r" || str=="\n" );
115 str_in = std::istringstream ( str );
116 // Reading mesh vertex
117 for(int i=0; i<nbPoints; i++)
118 {
119 TPoint p;
120 str_in >> p[0];
121 str_in >> p[1];
122 str_in >> p[2];
123 aMesh.addVertex(p);
124 // Needed since a line can also contain vertex colors
125 getline(infile, str);
126 str_in = std::istringstream ( str );
127 }
128
129 // Reading mesh faces
130 for(int i=0; i<nbFaces; i++)
131 {
132 // Reading the number of face vertex
133 unsigned int aNbFaceVertex;
134 str_in >> aNbFaceVertex;
135 std::vector<typename Mesh<TPoint>::Index> aFace;
136 for (unsigned int j=0; j< aNbFaceVertex; j++)
137 {
138 unsigned int anIndex;
139 str_in >> anIndex;
140 aFace.push_back(anIndex);
141 }
142 if( invertVertexOrder )
143 {
144 for(unsigned int j=0; j < aFace.size()/2; j++)
145 {
146 const auto tmp=aFace.at(j);
147 aFace.at(j)=aFace.at(aFace.size()-1-j);
148 aFace.at(aFace.size()-1-j)=tmp;
149 }
150 }
151
152 // Contains colors:
153 bool findValidColor=true;
154
155 if(str_in.good())
156 {
157 double colorR, colorG, colorB, colorT;
158 findValidColor=str_in.good();
159 if(findValidColor && str_in.good())
160 {
161 str_in >> colorR;
162 }
163 findValidColor &=!str_in.fail();
164 if(findValidColor && str_in.good())
165 {
166 str_in >> colorG;
167 }
168 findValidColor &=!str_in.fail();
169 if(findValidColor && str_in.good())
170 {
171 str_in >> colorB;
172 }
173 findValidColor &=!str_in.fail();
174
175 if(findValidColor && str_in.good()){
176 str_in >> colorT;
177 // Since alpha is optional:
178 if(str_in.fail()){
179 colorT=1.0;
180 }
181 }
182 else
183 {
184 colorT=1.0;
185 }
186 if(findValidColor)
187 {
188 DGtal::Color c((unsigned int)(colorR*255.0), (unsigned int)(colorG*255.0),
189 (unsigned int)(colorB*255.0), (unsigned int)(colorT*255.0));
190 aMesh.addFace(aFace, c);
191 }
192 else
193 {
194 aMesh.addFace(aFace);
195 }
196 }
197 else
198 {
199 aMesh.addFace(aFace);
200 }
201 getline(infile, str);
202 str_in = std::istringstream ( str );
203
204
205 }
206
207 return true;
208}
209
210
211
212
213
214
215template <typename TPoint>
216inline
217bool
218DGtal::MeshReader<TPoint>::importOFSFile(const std::string & aFilename,
219 DGtal::Mesh<TPoint> & aMesh,
220 bool invertVertexOrder, double scale)
221{
222 std::ifstream infile;
223 DGtal::IOException dgtalio;
224 try
225 {
226 infile.open (aFilename.c_str(), std::ifstream::in);
227 }
228 catch( ... )
229 {
230 trace.error() << "MeshReader : can't open " << aFilename << std::endl;
231 throw dgtalio;
232 }
233 std::string str;
234 getline( infile, str );
235
236 if ( ! infile.good() )
237 {
238 trace.error() << "MeshReader : can't read " << aFilename << std::endl;
239 throw dgtalio;
240 }
241 if ( str.substr(0,3) != "OFS")
242 {
243 trace.error() << "MeshReader : No OFS format in " << aFilename << std::endl;
244 throw dgtalio;
245 }
246
247 // Processing comments
248 do
249 {
250 getline( infile, str );
251 if ( ! infile.good() ){
252 trace.error() << "MeshReader : Invalid format in " << aFilename << std::endl;
253 throw dgtalio;
254 }
255 }
256 while ( str[ 0 ] == '#' || str=="");
257 std::istringstream str_in( str );
258 int nbPoints;
259 str_in >> nbPoints;
260
261 // Reading mesh vertex
262 for(int i=0; i<nbPoints; i++)
263 {
264 TPoint p;
265 infile >> p[0];
266 infile >> p[1];
267 infile >> p[2];
268 p[0]*=scale;
269 p[1]*=scale;
270 p[2]*=scale;
271 aMesh.addVertex(p);
272 // Needed since a line can also contain vertex colors
273 getline(infile, str);
274 }
275 do
276 {
277 getline( infile, str );
278 if ( ! infile.good() ){
279 trace.error() << "MeshReader : Invalid format in " << aFilename << std::endl;
280 throw dgtalio;
281 }
282 }
283 while ( str[ 0 ] == '#' || str=="");
284 std::istringstream str_in2( str );
285 unsigned int nbFaces;
286 str_in2 >> nbFaces;
287 // Reading mesh faces
288 for(unsigned int i=0; i<nbFaces; i++)
289 {
290 // Reading the number of face vertex
291 std::vector<typename Mesh<TPoint>::Index> aFace;
292 for (unsigned int j=0; j< 3; j++)
293 {
294 unsigned int anIndex;
295 infile >> anIndex;
296 aFace.push_back(anIndex);
297 }
298 if( invertVertexOrder )
299 {
300 const auto tmp=aFace.at(0);
301 aFace.at(0)=aFace.at(2);
302 aFace.at(2)=tmp;
303 }
304 aMesh.addFace(aFace);
305 getline(infile, str);
306 }
307 return true;
308}
309
310//-----------------------------------------------------------------------------
311template <typename TPoint>
312inline
313bool
314DGtal::MeshReader<TPoint>::
315importOBJFile( const std::string & filename, DGtal::Mesh<TPoint> & mesh )
316{
317 typedef typename Mesh<TPoint>::Index Index;
318 std::vector<TPoint> vertices;
319 std::vector<DGtal::Color> colors;
320 std::vector< std::vector< Index > > faces;
321 std::map<std::string, DGtal::Color> material;
322 std::string linestr;
323 std::string keyword;
324 std::string indices;
325 bool useMtllib = false;
326 DGtal::Color currentMtlCol = DGtal::Color::White;
327 TPoint p;
328 std::ifstream input;
329 DGtal::IOException dgtalio;
330 try
331 {
332 input.open (filename.c_str(), std::ifstream::in);
333 }
334 catch( ... )
335 {
336 trace.error() << "MeshReader : can't open " << filename << std::endl;
337 throw dgtalio;
338 }
339 std::getline( input, linestr );
340 Index l = 0;
341 for ( ; input.good() && ! input.eof(); std::getline( input, linestr ), l++ )
342 {
343 if ( linestr.empty() ) continue; // skip empty line
344 if ( linestr[0] == '#' ) continue; // skip comment line
345 std::istringstream lineinput( linestr );
346 std::operator>>( lineinput, keyword ); // lineinput >> keyword;
347 if ( keyword == "v" )
348 {
349 lineinput >> p[ 0 ] >> p[ 1 ] >> p[ 2 ];
350 vertices.push_back( p );
351 }
352 else if ( keyword == "f" )
353 {
354 std::vector< Index > face;
355 while ( ! lineinput.eof() )
356 {
357 std::operator>>( lineinput, indices ); // lineinput >> indices;
358 if ( indices.empty() ) break;
359 auto vtxinfo = SurfaceMeshReader<TPoint, Z3i::RealVector >::split( indices, '/' );
360 if ( vtxinfo.size() == 0 ) break;
361 int v = std::stoi( vtxinfo[ 0 ] )-1;
362 if (v < 0 )
363 { // special case of relative indices (ie negative index);
364 v = (int)vertices.size() + v+1;
365 }
366 face.push_back( v);
367 indices = "";
368 }
369 if ( ! face.empty() && verifyIndicesUniqueness( face ) )
370 {
371 faces.push_back( face );
372 if (useMtllib)
373 {
374 colors.push_back(currentMtlCol );
375 }
376 }
377
378 } else if (keyword == "mtllib")
379 {
380 std::string name;
381 std::operator>>( lineinput, name );
382 std::string base = name.substr(0,name.find_last_of("."));
383 auto iSep = filename.find_last_of('/');
384 if (iSep == -1)
385 { // special for windows.
386 iSep = filename.find_last_of('\\');
387 }
388 std::string path = filename.substr(0, iSep+1);
389 std::stringstream matPathName ;
390 matPathName << path << name;
391 std::ifstream is (matPathName.str());
392 material = MeshReader<TPoint>::readMaterial(is);
393 useMtllib = true;
394 }
395 else if (keyword == "usemtl")
396 {
397 std::string name;
398 std::operator>>( lineinput, name );
399 if (material.count(name) !=0 )
400 {
401 currentMtlCol = material[name];
402 }
403 }
404 // Weird: necessary to clear them.
405 keyword = ""; linestr = "";
406 }
407 // Creating Mesh
408 trace.info() << "[MeshReader::readOBJ] Read"
409 << " #lines=" << l
410 << " #V=" << vertices.size()
411 << " #F=" << faces.size() << std::endl;
412 if ( input.bad() )
413 trace.warning() << "[MeshReader::readOBJ] Some I/O error occured."
414 << " Proceeding but the mesh may be damaged." << std::endl;
415 for (auto const &s : vertices)
416 {
417 mesh.addVertex(s);
418 }
419 for (auto const &f : faces)
420 {
421 mesh.addFace(f);
422 }
423
424 if (!colors.empty()){
425 for (Index i = 0; i < colors.size(); i++){
426 mesh.setFaceColor(i, colors[i]);
427 }
428 }
429 return ( ! input.bad() );
430}
431
432template <typename TPoint>
433bool
434DGtal::operator<< ( Mesh<TPoint> & mesh, const std::string &filename )
435{
436 std::string extension = filename.substr(filename.find_last_of(".") + 1);
437 if(extension== "off")
438 {
439 DGtal::MeshReader< TPoint >::importOFFFile(filename, mesh);
440 return true;
441 }
442 else if(extension== "ofs")
443 {
444 DGtal::MeshReader< TPoint >::importOFSFile(filename, mesh);
445 return true;
446 }
447 else if(extension== "obj")
448 {
449 DGtal::MeshReader< TPoint >::importOBJFile(filename, mesh);
450 return true;
451 }
452
453 return false;
454}
455
456
457
458//-----------------------------------------------------------------------------
459template <typename TPoint>
460bool
461DGtal::MeshReader<TPoint>::
462verifyIndicesUniqueness( const std::vector< typename DGtal::Mesh<TPoint>::Index > &indices )
463{
464 std::unordered_set<typename DGtal::Mesh<TPoint>::Index> sindices( indices.begin(), indices.end() );
465 return sindices.size() == indices.size();
466}
467
468//-----------------------------------------------------------------------------
469template <typename TPoint>
470std::map<std::string, DGtal::Color>
471DGtal::MeshReader<TPoint>::readMaterial( std::istream & input)
472{
473 typedef unsigned int Index;
474 std::string linestr;
475 std::string keyword;
476 std::map<std::string, DGtal::Color> resultMap;
477 std::getline( input, linestr );
478 double r, g, b;
479 Index l = 0;
480 std::string currentMtlName="";
481 for ( ; input.good() && ! input.eof(); std::getline( input, linestr ), l++ )
482 {
483 if ( linestr.empty() ) continue; // skip empty line
484 if ( linestr[0] == '#' ) continue; // skip comment line
485 std::istringstream lineinput( linestr );
486 std::operator>>( lineinput, keyword ); // lineinput >> keyword;
487 if ( keyword == "newmtl" )
488 {
489 std::string nameMtl;
490 std::operator>>( lineinput, nameMtl );
491 if (nameMtl != "")
492 {
493 currentMtlName = nameMtl;
494 }
495 }
496 else if (keyword == "Kd" && currentMtlName != "" )
497 {
498 lineinput >> r >> g >> b;
499 DGtal::Color c (static_cast<unsigned char>(r*255.0),
500 static_cast<unsigned char>(g*255),
501 static_cast<unsigned char>(b*255));
502 resultMap[currentMtlName] = c;
503 currentMtlName = "";
504 }
505 }
506 return resultMap;
507}
508
509
510
511// //
512///////////////////////////////////////////////////////////////////////////////
513
514
515
516
517