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/>.
19 * @author Bertrand Kerautret (\c kerautre@loria.fr )
20 * LORIA (CNRS, UMR 7503), University of Nancy, France
24 * Implementation of inline methods defined in MeshReader.h
26 * This file is part of the DGtal library.
29///////////////////////////////////////////////////////////////////////////////
30// IMPLEMENTATION of inline methods.
31///////////////////////////////////////////////////////////////////////////////
33//////////////////////////////////////////////////////////////////////////////
41//////////////////////////////////////////////////////////////////////////////
43#include "DGtal/helpers/StdDefs.h"
44#include "DGtal/io/readers/SurfaceMeshReader.h"
46///////////////////////////////////////////////////////////////////////////////
47// Implementation of inline methods //
52template <typename TPoint>
55DGtal::MeshReader<TPoint>::importOFFFile(const std::string & aFilename,
56 DGtal::Mesh<TPoint> & aMesh,
57 bool invertVertexOrder)
60 DGtal::IOException dgtalio;
63 infile.open (aFilename.c_str(), std::ifstream::in);
67 trace.error() << "MeshReader : can't open " << aFilename << std::endl;
71 getline( infile, str );
73 if ( ! infile.good() )
75 trace.error() << "MeshReader : can't read " << aFilename << std::endl;
78 if ( str.substr(0,3) != "OFF" && str.substr(0,4) != "NOFF" && str.substr(0,5) != "CNOFF")
80 std::cerr <<"*" <<str<<"*"<< std::endl;
81 trace.error() << "MeshReader : No OFF, NOFF or CNOFF format in " << aFilename << std::endl;
84 if ( str.substr(0,4) == "NOFF")
86 trace.warning() << "MeshReader : reading NOFF format from importOFFFile (normal vectors will be ignored)..." << std::endl;
89 // Processing comments
92 getline( infile, str );
93 if ( ! infile.good() )
95 trace.error() << "MeshReader : Invalid format in " << aFilename << std::endl;
99 while ( str[ 0 ] == '#' || str=="" || str=="\r" || str=="\n" );
100 std::istringstream str_in( str );
101 int nbPoints, nbFaces, nbEdges;
107 getline( infile, str );
108 if ( ! infile.good() )
110 trace.error() << "MeshReader : Invalid format in " << aFilename << std::endl;
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++)
124 // Needed since a line can also contain vertex colors
125 getline(infile, str);
126 str_in = std::istringstream ( str );
129 // Reading mesh faces
130 for(int i=0; i<nbFaces; i++)
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++)
138 unsigned int anIndex;
140 aFace.push_back(anIndex);
142 if( invertVertexOrder )
144 for(unsigned int j=0; j < aFace.size()/2; j++)
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;
153 bool findValidColor=true;
157 double colorR, colorG, colorB, colorT;
158 findValidColor=str_in.good();
159 if(findValidColor && str_in.good())
163 findValidColor &=!str_in.fail();
164 if(findValidColor && str_in.good())
168 findValidColor &=!str_in.fail();
169 if(findValidColor && str_in.good())
173 findValidColor &=!str_in.fail();
175 if(findValidColor && str_in.good()){
177 // Since alpha is optional:
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);
194 aMesh.addFace(aFace);
199 aMesh.addFace(aFace);
201 getline(infile, str);
202 str_in = std::istringstream ( str );
215template <typename TPoint>
218DGtal::MeshReader<TPoint>::importOFSFile(const std::string & aFilename,
219 DGtal::Mesh<TPoint> & aMesh,
220 bool invertVertexOrder, double scale)
222 std::ifstream infile;
223 DGtal::IOException dgtalio;
226 infile.open (aFilename.c_str(), std::ifstream::in);
230 trace.error() << "MeshReader : can't open " << aFilename << std::endl;
234 getline( infile, str );
236 if ( ! infile.good() )
238 trace.error() << "MeshReader : can't read " << aFilename << std::endl;
241 if ( str.substr(0,3) != "OFS")
243 trace.error() << "MeshReader : No OFS format in " << aFilename << std::endl;
247 // Processing comments
250 getline( infile, str );
251 if ( ! infile.good() ){
252 trace.error() << "MeshReader : Invalid format in " << aFilename << std::endl;
256 while ( str[ 0 ] == '#' || str=="");
257 std::istringstream str_in( str );
261 // Reading mesh vertex
262 for(int i=0; i<nbPoints; i++)
272 // Needed since a line can also contain vertex colors
273 getline(infile, str);
277 getline( infile, str );
278 if ( ! infile.good() ){
279 trace.error() << "MeshReader : Invalid format in " << aFilename << std::endl;
283 while ( str[ 0 ] == '#' || str=="");
284 std::istringstream str_in2( str );
285 unsigned int nbFaces;
287 // Reading mesh faces
288 for(unsigned int i=0; i<nbFaces; i++)
290 // Reading the number of face vertex
291 std::vector<typename Mesh<TPoint>::Index> aFace;
292 for (unsigned int j=0; j< 3; j++)
294 unsigned int anIndex;
296 aFace.push_back(anIndex);
298 if( invertVertexOrder )
300 const auto tmp=aFace.at(0);
301 aFace.at(0)=aFace.at(2);
304 aMesh.addFace(aFace);
305 getline(infile, str);
310//-----------------------------------------------------------------------------
311template <typename TPoint>
314DGtal::MeshReader<TPoint>::
315importOBJFile( const std::string & filename, DGtal::Mesh<TPoint> & mesh )
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;
325 bool useMtllib = false;
326 DGtal::Color currentMtlCol = DGtal::Color::White;
329 DGtal::IOException dgtalio;
332 input.open (filename.c_str(), std::ifstream::in);
336 trace.error() << "MeshReader : can't open " << filename << std::endl;
339 std::getline( input, linestr );
341 for ( ; input.good() && ! input.eof(); std::getline( input, linestr ), l++ )
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" )
349 lineinput >> p[ 0 ] >> p[ 1 ] >> p[ 2 ];
350 vertices.push_back( p );
352 else if ( keyword == "f" )
354 std::vector< Index > face;
355 while ( ! lineinput.eof() )
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;
363 { // special case of relative indices (ie negative index);
364 v = (int)vertices.size() + v+1;
369 if ( ! face.empty() && verifyIndicesUniqueness( face ) )
371 faces.push_back( face );
374 colors.push_back(currentMtlCol );
378 } else if (keyword == "mtllib")
381 std::operator>>( lineinput, name );
382 std::string base = name.substr(0,name.find_last_of("."));
383 auto iSep = filename.find_last_of('/');
385 { // special for windows.
386 iSep = filename.find_last_of('\\');
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);
395 else if (keyword == "usemtl")
398 std::operator>>( lineinput, name );
399 if (material.count(name) !=0 )
401 currentMtlCol = material[name];
404 // Weird: necessary to clear them.
405 keyword = ""; linestr = "";
408 trace.info() << "[MeshReader::readOBJ] Read"
410 << " #V=" << vertices.size()
411 << " #F=" << faces.size() << std::endl;
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)
419 for (auto const &f : faces)
424 if (!colors.empty()){
425 for (Index i = 0; i < colors.size(); i++){
426 mesh.setFaceColor(i, colors[i]);
429 return ( ! input.bad() );
432template <typename TPoint>
434DGtal::operator<< ( Mesh<TPoint> & mesh, const std::string &filename )
436 std::string extension = filename.substr(filename.find_last_of(".") + 1);
437 if(extension== "off")
439 DGtal::MeshReader< TPoint >::importOFFFile(filename, mesh);
442 else if(extension== "ofs")
444 DGtal::MeshReader< TPoint >::importOFSFile(filename, mesh);
447 else if(extension== "obj")
449 DGtal::MeshReader< TPoint >::importOBJFile(filename, mesh);
458//-----------------------------------------------------------------------------
459template <typename TPoint>
461DGtal::MeshReader<TPoint>::
462verifyIndicesUniqueness( const std::vector< typename DGtal::Mesh<TPoint>::Index > &indices )
464 std::unordered_set<typename DGtal::Mesh<TPoint>::Index> sindices( indices.begin(), indices.end() );
465 return sindices.size() == indices.size();
468//-----------------------------------------------------------------------------
469template <typename TPoint>
470std::map<std::string, DGtal::Color>
471DGtal::MeshReader<TPoint>::readMaterial( std::istream & input)
473 typedef unsigned int Index;
476 std::map<std::string, DGtal::Color> resultMap;
477 std::getline( input, linestr );
480 std::string currentMtlName="";
481 for ( ; input.good() && ! input.eof(); std::getline( input, linestr ), l++ )
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" )
490 std::operator>>( lineinput, nameMtl );
493 currentMtlName = nameMtl;
496 else if (keyword == "Kd" && currentMtlName != "" )
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;
512///////////////////////////////////////////////////////////////////////////////