import2tablesSurface.hpp 47.7 KB
Newer Older
Pierre Kraemer's avatar
Pierre Kraemer committed
1
2
3
/*******************************************************************************
* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps  *
* version 0.1                                                                  *
4
* Copyright (C) 2009-2012, IGG Team, LSIIT, University of Strasbourg           *
Pierre Kraemer's avatar
Pierre Kraemer committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
*                                                                              *
* This library is free software; you can redistribute it and/or modify it      *
* under the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, or (at your     *
* option) any later version.                                                   *
*                                                                              *
* This library is distributed in the hope that it will be useful, but WITHOUT  *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or        *
* FITNESS FOR A PARTICULAR PURVEC3E. See the GNU Lesser General Public License  *
* for more details.                                                            *
*                                                                              *
* You should have received a copy of the GNU Lesser General Public License     *
* along with this library; if not, write to the Free Software Foundation,      *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.           *
*                                                                              *
20
* Web site: http://cgogn.unistra.fr/                                           *
Pierre Kraemer's avatar
Pierre Kraemer committed
21
22
23
24
25
* Contact information: cgogn@unistra.fr                                        *
*                                                                              *
*******************************************************************************/

#include "Algo/Import/importPlyData.h"
26
27
#include "Algo/Geometry/boundingbox.h"
#include "Topology/generic/autoAttributeHandler.h"
Pierre Kraemer's avatar
Pierre Kraemer committed
28

29
#include "Algo/Import/AHEM.h"
Pierre Kraemer's avatar
Pierre Kraemer committed
30

Sylvain Thery's avatar
Sylvain Thery committed
31
#ifdef WITH_ASSIMP
Pierre Kraemer's avatar
Pierre Kraemer committed
32
33
34
#include "assimp.h"
#include "aiPostProcess.h"
#include "aiScene.h"
Sylvain Thery's avatar
Sylvain Thery committed
35
#endif
Pierre Kraemer's avatar
Pierre Kraemer committed
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

namespace CGoGN
{

namespace Algo
{

namespace Import
{

template<typename PFP>
ImportSurfacique::ImportType MeshTablesSurface<PFP>::getFileType(const std::string& filename)
{
	if ((filename.rfind(".trianbgz")!=std::string::npos) || (filename.rfind(".TRIANBGZ")!=std::string::npos))
		return ImportSurfacique::TRIANBGZ;
Pierre Kraemer's avatar
Pierre Kraemer committed
51

Pierre Kraemer's avatar
Pierre Kraemer committed
52
53
54
	if ((filename.rfind(".trian")!=std::string::npos) || (filename.rfind(".TRIAN")!=std::string::npos))
		return ImportSurfacique::TRIAN;

55
56
57
	if ((filename.rfind(".meshbin")!=std::string::npos) || (filename.rfind(".MESHBIN")!=std::string::npos))
		return ImportSurfacique::MESHBIN;

58
/*	if ((filename.rfind(".plyptm")!=std::string::npos) || (filename.rfind(".PLYGEN")!=std::string::npos))
Pierre Kraemer's avatar
Pierre Kraemer committed
59
		return ImportSurfacique::PLYPTM;
60
*/
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
61
	if ((filename.rfind(".plyPTMextBin")!=std::string::npos) || (filename.rfind(".plySHrealBin")!=std::string::npos))
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
62
		return ImportSurfacique::PLYSLFgenericBin;
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
63

Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
64
65
	if ((filename.rfind(".plyPTMext")!=std::string::npos) || (filename.rfind(".plySHreal")!=std::string::npos))
		return ImportSurfacique::PLYSLFgeneric;
66

Pierre Kraemer's avatar
Pierre Kraemer committed
67
68
	if ((filename.rfind(".ply")!=std::string::npos) || (filename.rfind(".PLY")!=std::string::npos))
		return ImportSurfacique::PLY;
Pierre Kraemer's avatar
Pierre Kraemer committed
69

Pierre Kraemer's avatar
Pierre Kraemer committed
70
71
	if ((filename.rfind(".off")!=std::string::npos) || (filename.rfind(".OFF")!=std::string::npos))
		return ImportSurfacique::OFF;
Pierre Kraemer's avatar
Pierre Kraemer committed
72

Pierre Kraemer's avatar
Pierre Kraemer committed
73
74
	if ((filename.rfind(".obj")!=std::string::npos) || (filename.rfind(".OBJ")!=std::string::npos))
		return ImportSurfacique::OBJ;
Pierre Kraemer's avatar
Pierre Kraemer committed
75

76
77
78
	if ((filename.rfind(".ahem")!=std::string::npos) || (filename.rfind(".AHEM")!=std::string::npos))
		return ImportSurfacique::AHEM;

Pierre Kraemer's avatar
Pierre Kraemer committed
79
80
81
82
	return ImportSurfacique::UNKNOWNSURFACE;
}

template<typename PFP>
Pierre Kraemer's avatar
Pierre Kraemer committed
83
bool MeshTablesSurface<PFP>::importMesh(const std::string& filename, std::vector<std::string>& attrNames)
Pierre Kraemer's avatar
Pierre Kraemer committed
84
{
Pierre Kraemer's avatar
Pierre Kraemer committed
85
	ImportSurfacique::ImportType kind = getFileType(filename);
Pierre Kraemer's avatar
Pierre Kraemer committed
86

Pierre Kraemer's avatar
Pierre Kraemer committed
87
	attrNames.clear() ;
Pierre Kraemer's avatar
Pierre Kraemer committed
88
89
90
91

	switch (kind)
	{
	case ImportSurfacique::TRIAN:
92
		CGoGNout << "TYPE: TRIAN" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
93
		return importTrian(filename, attrNames);
Pierre Kraemer's avatar
Pierre Kraemer committed
94
95
		break;
	case ImportSurfacique::TRIANBGZ:
96
		CGoGNout << "TYPE: TRIANBGZ" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
97
		return importTrianBinGz(filename, attrNames);
Pierre Kraemer's avatar
Pierre Kraemer committed
98
99
		break;
	case ImportSurfacique::OFF:
100
		CGoGNout << "TYPE: OFF" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
101
		return importOff(filename, attrNames);
Pierre Kraemer's avatar
Pierre Kraemer committed
102
		break;
103
104
105
106
	case ImportSurfacique::MESHBIN:
		CGoGNout << "TYPE: MESHBIN" << CGoGNendl;
		return importMeshBin(filename, attrNames);
		break;
Pierre Kraemer's avatar
Pierre Kraemer committed
107
	case ImportSurfacique::PLY:
108
		CGoGNout << "TYPE: PLY" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
109
		return importPly(filename, attrNames);
Pierre Kraemer's avatar
Pierre Kraemer committed
110
		break;
111
/*	case ImportSurfacique::PLYPTM:
112
		CGoGNout << "TYPE: PLYPTM" << CGoGNendl;
113
114
		return importPlyPTM(filename, attrNames);
		break;
115
*/	case ImportSurfacique::PLYSLFgeneric:
116
117
		CGoGNout << "TYPE: PLYSLFgeneric" << CGoGNendl;
		return importPlySLFgeneric(filename, attrNames);
Pierre Kraemer's avatar
Pierre Kraemer committed
118
		break;
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
119
120
121
122
	case ImportSurfacique::PLYSLFgenericBin:
		CGoGNout << "TYPE: PLYSLFgenericBin" << CGoGNendl;
		return importPlySLFgenericBin(filename, attrNames);
		break;
Pierre Kraemer's avatar
Pierre Kraemer committed
123
	case ImportSurfacique::OBJ:
124
		CGoGNout << "TYPE: OBJ" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
125
		return importObj(filename, attrNames);
Pierre Kraemer's avatar
Pierre Kraemer committed
126
		break;
127
128
129
130
	case ImportSurfacique::AHEM:
		CGoGNout << "TYPE: AHEM" << CGoGNendl;
		return importAHEM(filename, attrNames);
		break;
Pierre Kraemer's avatar
Pierre Kraemer committed
131
	default:
Sylvain Thery's avatar
Sylvain Thery committed
132
	#ifdef WITH_ASSIMP
133
		CGoGNout << "TYPE: ASSIMP" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
134
		return importASSIMP(filename, attrNames);
Sylvain Thery's avatar
Sylvain Thery committed
135
136
137
	#else
		CGoGNout << "unsupported file type"<< CGoGNendl;		
	#endif
Pierre Kraemer's avatar
Pierre Kraemer committed
138
139
140
141
142
143
		break;
	}
	return false;
}

template<typename PFP>
Pierre Kraemer's avatar
Pierre Kraemer committed
144
bool MeshTablesSurface<PFP>::importTrian(const std::string& filename, std::vector<std::string>& attrNames)
Pierre Kraemer's avatar
Pierre Kraemer committed
145
{
146
	VertexAttribute<typename PFP::VEC3> positions =  m_map.template getAttribute<typename PFP::VEC3, VERTEX>("position") ;
147
148

	if (!positions.isValid())
149
		positions = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("position") ;
150

Pierre Kraemer's avatar
Pierre Kraemer committed
151
152
	attrNames.push_back(positions.name()) ;

153
	AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ;
154

Pierre Kraemer's avatar
Pierre Kraemer committed
155
156
157
158
	// open file
	std::ifstream fp(filename.c_str(), std::ios::in);
	if (!fp.good())
	{
159
		CGoGNerr << "Unable to open file " << filename << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
160
161
162
		return false;
	}

Pierre Kraemer's avatar
Pierre Kraemer committed
163
	// read nb of points
Pierre Kraemer's avatar
Pierre Kraemer committed
164
165
	fp >> m_nbVertices;

Pierre Kraemer's avatar
Pierre Kraemer committed
166
	// read points
Pierre Kraemer's avatar
Pierre Kraemer committed
167
168
169
	std::vector<unsigned int> verticesID;
	verticesID.reserve(m_nbVertices);

Pierre Kraemer's avatar
Pierre Kraemer committed
170
	for (unsigned int i = 0; i < m_nbVertices; ++i)
Pierre Kraemer's avatar
Pierre Kraemer committed
171
172
173
174
175
	{
		VEC3 pos;
		fp >> pos[0];
		fp >> pos[1];
		fp >> pos[2];
Pierre Kraemer's avatar
Pierre Kraemer committed
176
177
		unsigned int id = container.insertLine();
		positions[id] = pos;
Pierre Kraemer's avatar
Pierre Kraemer committed
178
179
180
181
182
183
184
185
		verticesID.push_back(id);
	}

	// read nb of faces
	fp >> m_nbFaces;
	m_nbEdges.reserve(m_nbFaces);
	m_emb.reserve(3*m_nbFaces);

Pierre Kraemer's avatar
Pierre Kraemer committed
186
187
	// read indices of faces
	for (unsigned int i = 0; i < m_nbFaces; ++i)
Pierre Kraemer's avatar
Pierre Kraemer committed
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
	{
		m_nbEdges.push_back(3);
		// read the three vertices of triangle
		int pt;
		fp >> pt;
		m_emb.push_back(verticesID[pt]);
		fp >> pt;
		m_emb.push_back(verticesID[pt]);
		fp >> pt;
		m_emb.push_back(verticesID[pt]);

		// neighbour not always good in files !!
		int neigh;
		fp >> neigh;
		fp >> neigh;
		fp >> neigh;
	}

	fp.close();
	return true;
}

template<typename PFP>
Pierre Kraemer's avatar
Pierre Kraemer committed
211
bool MeshTablesSurface<PFP>::importTrianBinGz(const std::string& filename, std::vector<std::string>& attrNames)
Pierre Kraemer's avatar
Pierre Kraemer committed
212
{
213
	VertexAttribute<typename PFP::VEC3> positions =  m_map.template getAttribute<typename PFP::VEC3, VERTEX>("position") ;
214
215

	if (!positions.isValid())
216
		positions = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("position") ;
217

Pierre Kraemer's avatar
Pierre Kraemer committed
218
219
	attrNames.push_back(positions.name()) ;

220
	AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ;
221

Pierre Kraemer's avatar
Pierre Kraemer committed
222
223
224
225
226
	// open file
	igzstream fs(filename.c_str(), std::ios::in|std::ios::binary);

	if (!fs.good())
	{
227
		CGoGNerr << "Unable to open file " << filename << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
228
229
		return false;
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
230

Pierre Kraemer's avatar
Pierre Kraemer committed
231
232
233
234
235
	// read nb of points
	fs.read(reinterpret_cast<char*>(&m_nbVertices), sizeof(int));

	// read points
	std::vector<unsigned int> verticesID;
Pierre Kraemer's avatar
Pierre Kraemer committed
236
	{	// juste pour limiter la portee des variables
Pierre Kraemer's avatar
Pierre Kraemer committed
237
238
		verticesID.reserve(m_nbVertices);
		float* buffer = new float[m_nbVertices*3];
Pierre Kraemer's avatar
Pierre Kraemer committed
239
		fs.read(reinterpret_cast<char*>(buffer), 3*m_nbVertices*sizeof(float));
Pierre Kraemer's avatar
Pierre Kraemer committed
240
		float *ptr = buffer;
Pierre Kraemer's avatar
Pierre Kraemer committed
241
		for (unsigned int i = 0; i < m_nbVertices; ++i)
Pierre Kraemer's avatar
Pierre Kraemer committed
242
243
244
245
246
247
		{
			VEC3 pos;
			pos[0]= *ptr++;
			pos[1]= *ptr++;
			pos[2]= *ptr++;

Pierre Kraemer's avatar
Pierre Kraemer committed
248
249
			unsigned int id = container.insertLine();
			positions[id] = pos;
Pierre Kraemer's avatar
Pierre Kraemer committed
250
251
252
253
254
255
256
257
258
259
260
261

			verticesID.push_back(id);
		}
		delete[] buffer;
	}

	// read nb of faces
	fs.read(reinterpret_cast<char*>(&m_nbFaces), sizeof(int));
	m_nbEdges.reserve(m_nbFaces);
	m_emb.reserve(3*m_nbFaces);

	// read indices of faces
Pierre Kraemer's avatar
Pierre Kraemer committed
262
	{	// juste pour limiter la portee des variables
Pierre Kraemer's avatar
Pierre Kraemer committed
263
264
265
266
		int* buffer = new int[m_nbFaces*6];
		fs.read(reinterpret_cast<char*>(buffer),6*m_nbFaces*sizeof(float));
		int *ptr = buffer;

Pierre Kraemer's avatar
Pierre Kraemer committed
267
		for (unsigned int i = 0; i < m_nbFaces; i++)
Pierre Kraemer's avatar
Pierre Kraemer committed
268
269
270
271
272
273
274
275
276
277
278
279
280
		{
			m_nbEdges.push_back(3);
			m_emb.push_back(verticesID[*ptr++]);
			m_emb.push_back(verticesID[*ptr++]);
			m_emb.push_back(verticesID[*ptr++]);
		}
	}
	
	fs.close();
	return true;
}

template<typename PFP>
Pierre Kraemer's avatar
Pierre Kraemer committed
281
bool MeshTablesSurface<PFP>::importOff(const std::string& filename, std::vector<std::string>& attrNames)
Pierre Kraemer's avatar
Pierre Kraemer committed
282
{
283
	VertexAttribute<typename PFP::VEC3> positions = m_map.template getAttribute<typename PFP::VEC3, VERTEX>("position") ;
284
285

	if (!positions.isValid())
286
		positions = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("position") ;
287

Pierre Kraemer's avatar
Pierre Kraemer committed
288
289
	attrNames.push_back(positions.name()) ;

290
	AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ;
291

Pierre Kraemer's avatar
Pierre Kraemer committed
292
293
294
295
	// open file
	std::ifstream fp(filename.c_str(), std::ios::in);
	if (!fp.good())
	{
296
		CGoGNerr << "Unable to open file " << filename << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
297
298
299
300
301
302
303
304
305
		return false;
	}

    std::string ligne;

    // lecture de OFF
    std::getline (fp, ligne);
    if (ligne.rfind("OFF") == std::string::npos)
    {
306
307
		CGoGNerr << "Problem reading off file: not an off file" << CGoGNendl;
		CGoGNerr << ligne << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
308
		return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
309
310
311
312
313
314
315
316
    }

    // lecture des nombres de sommets/faces/aretes
	int nbe;
    {
    	do
    	{
    		std::getline (fp, ligne);
Pierre Kraemer's avatar
Pierre Kraemer committed
317
    	} while (ligne.size() == 0);
Pierre Kraemer's avatar
Pierre Kraemer committed
318
319
320
321
322
323
324
325
326
327

	    std::stringstream oss(ligne);
		oss >> m_nbVertices;
		oss >> m_nbFaces;
		oss >> nbe;
    }

	//lecture sommets
	std::vector<unsigned int> verticesID;
	verticesID.reserve(m_nbVertices);
Pierre Kraemer's avatar
Pierre Kraemer committed
328
	for (unsigned int i = 0; i < m_nbVertices;++i)
Pierre Kraemer's avatar
Pierre Kraemer committed
329
330
331
332
	{
    	do
    	{
    		std::getline (fp, ligne);
Pierre Kraemer's avatar
Pierre Kraemer committed
333
    	} while (ligne.size() == 0);
Pierre Kraemer's avatar
Pierre Kraemer committed
334
335
336
337
338
339
340
341
342
343

		std::stringstream oss(ligne);

		float x,y,z;
		oss >> x;
		oss >> y;
		oss >> z;
		// on peut ajouter ici la lecture de couleur si elle existe
		VEC3 pos(x,y,z);

Pierre Kraemer's avatar
Pierre Kraemer committed
344
345
		unsigned int id = container.insertLine();
		positions[id] = pos;
Pierre Kraemer's avatar
Pierre Kraemer committed
346
347
348
349
350
351
352
353
354

		verticesID.push_back(id);
	}

	// lecture faces
	// normalement nbVertices*8 devrait suffire largement
	m_nbEdges.reserve(m_nbFaces);
	m_emb.reserve(m_nbVertices*8);

Pierre Kraemer's avatar
Pierre Kraemer committed
355
	for (unsigned int i = 0; i < m_nbFaces; ++i)
Pierre Kraemer's avatar
Pierre Kraemer committed
356
357
358
359
	{
    	do
    	{
    		std::getline (fp, ligne);
Pierre Kraemer's avatar
Pierre Kraemer committed
360
    	} while (ligne.size() == 0);
Pierre Kraemer's avatar
Pierre Kraemer committed
361
362

		std::stringstream oss(ligne);
Pierre Kraemer's avatar
Pierre Kraemer committed
363
		unsigned int n;
Pierre Kraemer's avatar
Pierre Kraemer committed
364
365
		oss >> n;
		m_nbEdges.push_back(n);
Pierre Kraemer's avatar
Pierre Kraemer committed
366
		for (unsigned int j = 0; j < n; ++j)
Pierre Kraemer's avatar
Pierre Kraemer committed
367
368
369
370
371
372
373
374
375
376
377
378
		{
			int index; // index du plongement
			oss >> index;
			m_emb.push_back(verticesID[index]);
		}
		// on peut ajouter ici la lecture de couleur si elle existe
	}

	fp.close();
	return true;
}

379
380
381
template<typename PFP>
bool MeshTablesSurface<PFP>::importMeshBin(const std::string& filename, std::vector<std::string>& attrNames)
{
382
	VertexAttribute<typename PFP::VEC3> positions = m_map.template getAttribute<typename PFP::VEC3, VERTEX>("position") ;
383
384

	if (!positions.isValid())
385
	{
386
		positions = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("position") ;
387
	}
388
389
390

	attrNames.push_back(positions.name()) ;

391
	AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ;
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415

	// open file
	std::ifstream fp(filename.c_str(), std::ios::in | std::ios::binary);
	if (!fp.good())
	{
		CGoGNerr << "Unable to open file " << filename << CGoGNendl;
		return false;
	}

	// Read header
    unsigned int Fmin, Fmax ;
    fp.read((char*)&m_nbVertices, sizeof(unsigned int)) ;
    fp.read((char*)&m_nbFaces, sizeof(unsigned int)) ;
    fp.read((char*)&Fmin, sizeof(unsigned int)) ;
    fp.read((char*)&Fmax, sizeof(unsigned int)) ;

    assert((Fmin == 3 && Fmax == 3) || !"Only triangular faces are handled yet") ;

    // Read foreach vertex
	std::vector<unsigned int> verticesID ;
	verticesID.reserve(m_nbVertices) ;

    for (unsigned int vxNum = 0 ; vxNum < m_nbVertices ; ++vxNum)
    {
416
    	Geom::Vec3f pos ;
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
    	fp.read((char*) &pos[0], sizeof(float)) ;
    	fp.read((char*) &pos[1], sizeof(float)) ;
    	fp.read((char*) &pos[2], sizeof(float)) ;

		unsigned int id = container.insertLine() ;
		positions[id] = pos ;

		verticesID.push_back(id) ;
    }

    // Read foreach face
	m_nbEdges.reserve(m_nbFaces) ;
	m_emb.reserve(m_nbVertices * 8) ;

	for (unsigned int fNum = 0; fNum < m_nbFaces; ++fNum)
	{
		const unsigned int faceSize = 3 ;
		fp.read((char*) &faceSize, sizeof(float)) ;
		m_nbEdges.push_back(faceSize) ;

		for (unsigned int i = 0 ; i < faceSize; ++i)
		{
			unsigned int index ; // index of embedding
			fp.read((char*) &index, sizeof(unsigned int)) ;
			m_emb.push_back(verticesID[index]) ;
		}
	}

	fp.close() ;
	return true ;
}


Pierre Kraemer's avatar
Pierre Kraemer committed
450
template <typename PFP>
Pierre Kraemer's avatar
Pierre Kraemer committed
451
bool MeshTablesSurface<PFP>::importObj(const std::string& filename, std::vector<std::string>& attrNames)
Pierre Kraemer's avatar
Pierre Kraemer committed
452
{
453
	VertexAttribute<typename PFP::VEC3> positions =  m_map.template getAttribute<typename PFP::VEC3, VERTEX>("position") ;
454
455

	if (!positions.isValid())
456
		positions = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("position") ;
457

Pierre Kraemer's avatar
Pierre Kraemer committed
458
459
	attrNames.push_back(positions.name()) ;

460
	AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ;
461

Pierre Kraemer's avatar
Pierre Kraemer committed
462
463
464
465
	// open file
	std::ifstream fp(filename.c_str(), std::ios::binary);
	if (!fp.good())
	{
466
		CGoGNerr << "Unable to open file " << filename << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
467
468
469
		return false;
	}

Pierre Kraemer's avatar
Pierre Kraemer committed
470
//	fp.seekg(0, std::ios::end);
Pierre Kraemer's avatar
Pierre Kraemer committed
471
//	int ab = fp.tellg();
Pierre Kraemer's avatar
Pierre Kraemer committed
472
//	fp.seekg(0, std::ios::beg);
Pierre Kraemer's avatar
Pierre Kraemer committed
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
//	int ac = fp.tellg();

    std::string ligne;
    std::string tag;

    do
    {
    	fp >> tag;
    	std::getline (fp, ligne);
    }while (tag != std::string("v"));

    // lecture des sommets
	std::vector<unsigned int> verticesID;
	verticesID.reserve(102400); // on tape large (400Ko wahouuuuu !!)

Pierre Kraemer's avatar
Pierre Kraemer committed
488
	unsigned int i = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
489
490
491
492
493
494
495
496
497
498
499
500
501
    do
    {
		if (tag == std::string("v"))
		{
			std::stringstream oss(ligne);
		
			float x,y,z;
			oss >> x;
			oss >> y;
			oss >> z;

			VEC3 pos(x,y,z);

Pierre Kraemer's avatar
Pierre Kraemer committed
502
503
			unsigned int id = container.insertLine();
			positions[id] = pos;
Pierre Kraemer's avatar
Pierre Kraemer committed
504
505
506
507
508
509

			verticesID.push_back(id);
			i++;
		}

		fp >> tag;
Pierre Kraemer's avatar
Pierre Kraemer committed
510
    	std::getline(fp, ligne);
Pierre Kraemer's avatar
Pierre Kraemer committed
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
    } while (!fp.eof());

	m_nbVertices = verticesID.size();

	// close/clear/open only way to go back to beginning of file
	fp.close();
	fp.clear();
	fp.open(filename.c_str());

	do
    {
    	fp >> tag;
    	std::getline (fp, ligne);
    } while (tag != std::string("f"));

	m_nbEdges.reserve(verticesID.size()*2);
	m_emb.reserve(verticesID.size()*8);

	std::vector<int> table;
530
	table.reserve(64); // NBV cotes pour une face devrait suffire
Pierre Kraemer's avatar
Pierre Kraemer committed
531
532
533
	m_nbFaces = 0;
    do
    {
Pierre Kraemer's avatar
Pierre Kraemer committed
534
    	if (tag == std::string("f")) // lecture d'une face
Pierre Kraemer's avatar
Pierre Kraemer committed
535
536
537
538
539
540
541
542
    	{
    		std::stringstream oss(ligne);
     		table.clear();
    		while (!oss.eof())  // lecture de tous les indices
    		{
    			std::string str;
    			oss >> str;

Pierre Kraemer's avatar
Pierre Kraemer committed
543
    			unsigned int ind = 0;
Sylvain Thery's avatar
Sylvain Thery committed
544

Pierre Kraemer's avatar
Pierre Kraemer committed
545
    			while ((ind<str.length()) && (str[ind]!='/'))
Pierre Kraemer's avatar
Pierre Kraemer committed
546
547
    				ind++;

Pierre Kraemer's avatar
Pierre Kraemer committed
548
				if (ind > 0)
Pierre Kraemer's avatar
Pierre Kraemer committed
549
550
				{
    				long index;
Pierre Kraemer's avatar
Pierre Kraemer committed
551
					std::stringstream iss(str.substr(0, ind));
Pierre Kraemer's avatar
Pierre Kraemer committed
552
553
554
555
556
					iss >> index;
		   			table.push_back(index);
				}
    		}

Pierre Kraemer's avatar
Pierre Kraemer committed
557
    		unsigned int n = table.size();
Pierre Kraemer's avatar
Pierre Kraemer committed
558
			m_nbEdges.push_back(short(n));
Pierre Kraemer's avatar
Pierre Kraemer committed
559
    		for (unsigned int j = 0; j < n; ++j)
Pierre Kraemer's avatar
Pierre Kraemer committed
560
    		{
Pierre Kraemer's avatar
Pierre Kraemer committed
561
    			int index = table[j] - 1; // les index commencent a 1 (boufonnerie d'obj ;)
Pierre Kraemer's avatar
Pierre Kraemer committed
562
563
564
565
566
				m_emb.push_back(verticesID[index]);
    		}
			m_nbFaces++;
    	}
		fp >> tag;
Pierre Kraemer's avatar
Pierre Kraemer committed
567
    	std::getline(fp, ligne);
Pierre Kraemer's avatar
Pierre Kraemer committed
568
569
570
571
572
573
574
     } while (!fp.eof());

	fp.close ();
	return true;
}

template<typename PFP>
Pierre Kraemer's avatar
Pierre Kraemer committed
575
bool MeshTablesSurface<PFP>::importPly(const std::string& filename, std::vector<std::string>& attrNames)
Pierre Kraemer's avatar
Pierre Kraemer committed
576
{
577
	VertexAttribute<typename PFP::VEC3> positions =  m_map.template getAttribute<typename PFP::VEC3, VERTEX>("position") ;
578
579

	if (!positions.isValid())
580
		positions = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("position") ;
581

Pierre Kraemer's avatar
Pierre Kraemer committed
582
583
	attrNames.push_back(positions.name()) ;

584
	AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ;
585

Pierre Kraemer's avatar
Pierre Kraemer committed
586
587
588
589
	PlyImportData pid;

	if (! pid.read_file(filename) )
	{
590
		CGoGNerr << "Unable to open file " << filename << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
591
592
		return false;
	}
593

594
	VertexAttribute<typename PFP::VEC3> colors = m_map.template getAttribute<typename PFP::VEC3, VERTEX>("color") ;
595
596
597
	if (pid.hasColors())
	{
		if(!colors.isValid())
598
			colors = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("color") ;
599
600
601
		attrNames.push_back(colors.name()) ;
	}

Pierre Kraemer's avatar
Pierre Kraemer committed
602
603
604
605
606
607
608
    // lecture des nombres de sommets/aretes/faces
	m_nbVertices = pid.nbVertices();
	m_nbFaces = pid.nbFaces();
 
	//lecture sommets
	std::vector<unsigned int> verticesID;
	verticesID.reserve(m_nbVertices);
Pierre Kraemer's avatar
Pierre Kraemer committed
609
	for (unsigned int i = 0; i < m_nbVertices; ++i)
Pierre Kraemer's avatar
Pierre Kraemer committed
610
611
	{
		VEC3 pos;
Pierre Kraemer's avatar
Pierre Kraemer committed
612
		pid.vertexPosition(i, pos);
Pierre Kraemer's avatar
Pierre Kraemer committed
613

Pierre Kraemer's avatar
Pierre Kraemer committed
614
615
		unsigned int id = container.insertLine();
		positions[id] = pos;
Pierre Kraemer's avatar
Pierre Kraemer committed
616

617
		if (pid.hasColorsUint8())
618
619
620
621
622
623
624
625
626
		{
			Geom::Vector<3, unsigned char> col ;
			pid.vertexColorUint8(i, col) ;
			colors[id][0] = col[0] ;
			colors[id][1] = col[1] ;
			colors[id][2] = col[2] ;
			colors[id] /= 255.0 ;
		}

627
628
629
630
631
632
633
634
635
636
		if (pid.hasColorsFloat32())
		{
			Geom::Vector<3, float> col ;
			pid.vertexColorFloat32(i, col) ;
			colors[id][0] = col[0] ;
			colors[id][1] = col[1] ;
			colors[id][2] = col[2] ;
		}


Pierre Kraemer's avatar
Pierre Kraemer committed
637
638
639
640
641
642
		verticesID.push_back(id);
	}

	m_nbEdges.reserve(m_nbFaces);
	m_emb.reserve(m_nbVertices*8);

643
	for (unsigned int i = 0 ; i < m_nbFaces ; ++i)
Pierre Kraemer's avatar
Pierre Kraemer committed
644
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
645
		unsigned int n = pid.getFaceValence(i);
Pierre Kraemer's avatar
Pierre Kraemer committed
646
647
		m_nbEdges.push_back(n);
		int* indices = pid.getFaceIndices(i);
Pierre Kraemer's avatar
Pierre Kraemer committed
648
		for (unsigned int j = 0; j < n; ++j)
Pierre Kraemer's avatar
Pierre Kraemer committed
649
		{
Pierre Kraemer's avatar
Pierre Kraemer committed
650
			m_emb.push_back(verticesID[indices[j]]);
Pierre Kraemer's avatar
Pierre Kraemer committed
651
652
653
654
655
656
		}
	}

	return true;
}

657
/**
658
659
 * Import plySLF (K Vanhoey generic format).
 * It can handle bivariable polynomials and spherical harmonics of any degree and returns the appropriate attrNames
660
661
 * @param filename the file to import;
 * @param attrNames reference that will be filled with the attribute names
662
 * the number of attrNames returned depends on the degree of the polynomials / level of the SH :
663
 *  - 1 attrName for geometric position (VEC3) : name = "position" ;
664
 *  - 3 attrNames for local frame (3xVEC3) : names are "frameT" (Tangent), "frameB" (Binormal) and "frameN" (Normal) ;
665
 *  - N attrNames for the function coefficients (NxVEC3) : N RGB coefficients being successively the constants, the linears (v then u), the quadratics, etc. :  : a0 + a1*v + a2*u + a3*u*v + a4*v^2 + a5*u^2.
666
 *  Their names are : "SLFcoefs<i>" (where <i> is a number from 0 to N-1).
667
668
669
670
671
 * N = 1 for constant polynomial,
 * N = 3 for linear polynomial,
 * N = 6 for quadratic polynomial,
 * N = 10 for cubic degree polynomial,
 * N = 15 for 4th degree polynomial,
672
673
 *
 * N = l*l for SH of level l,
674
 * ...
675
 *  - K remaining attrNames named "remainderNo<k>" where k is an integer from 0 to K-1.
676
 * @return bool : success.
Pierre Kraemer's avatar
Pierre Kraemer committed
677
 */
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
template <typename PFP>
bool MeshTablesSurface<PFP>::importPlySLFgeneric(const std::string& filename, std::vector<std::string>& attrNames)
{
	// Open file
	std::ifstream fp(filename.c_str(), std::ios::in) ;
	if (!fp.good())
	{
		CGoGNerr << "Unable to open file " << filename << CGoGNendl ;
		return false ;
	}

	// Read quantities : #vertices, #faces, #properties, degree of polynomials
    std::string tag ;

    fp >> tag;
	if (tag != std::string("ply")) // verify file type
	{
		CGoGNerr << filename << " is not a ply file !" <<  CGoGNout ;
		return false ;
	}

	do // go to #vertices
	{
		fp >> tag ;
	} while (tag != std::string("vertex")) ;
	unsigned int nbVertices ;
	fp >> nbVertices ; // Read #vertices

	bool position = false ;
	bool tangent = false ;
	bool binormal = false ;
	bool normal = false ;
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
710
711
712
713
	bool PTM = false ;
	bool SH = false ;
	unsigned int nbProps = 0 ;		// # properties
	unsigned int nbCoefs = 0 ; 	// # coefficients
714
715
716
717
718
	do // go to #faces and count #properties
	{
		fp >> tag ;
		if (tag == std::string("property"))
			++nbProps ;
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
719
		else if (tag == std::string("x") || tag == std::string("y") || tag == std::string("z"))
720
			position = true ;
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
721
722
		//else if (tag == std::string("tx") || tag == std::string("ty") || tag == std::string("tz"))
		else if (tag == std::string("frameT_0") || tag == std::string("frameT_1") || tag == std::string("frameT_2"))
723
724
			tangent = true ;
		//else if (tag == std::string("bx") || tag == std::string("by") || tag == std::string("bz"))
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
725
		else if (tag == std::string("frameB_0") || tag == std::string("frameB_1") || tag == std::string("frameB_2"))
726
727
			binormal = true ;
		//else if (tag == std::string("nx") || tag == std::string("ny") || tag == std::string("nz"))
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
728
		else if (tag == std::string("frameN_0") || tag == std::string("frameN_1") || tag == std::string("frameN_2"))
729
			normal = true ;
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
730
731
732
		// else if (tag.substr(0,1) == std::string("C") && tag.substr(2,1) == std::string("_"))
		else if ((tag.length() > 8) && tag.find("_") != std::string::npos)
		{
733
			if (tag.substr(0,7) == std::string("PBcoefs"))
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
734
735
736
737
738
739
740
741
742
743
			{
				PTM = true ;
				++nbCoefs ;
			}
			else if (tag.substr(0,7) == std::string("SHcoefs"))
			{
				SH = true ;
				++nbCoefs ;
			}
		}
744
745
746
747
748
749
750
751
752
753
754
755
756
	} while (tag != std::string("face")) ;
	unsigned int nbRemainders = nbProps ;		// # remaining properties
	nbRemainders -= nbCoefs + 3*(position==true) + 3*(tangent==true) + 3*(binormal==true) + 3*(normal==true) ;
	nbCoefs /= 3 ;

	fp >> m_nbFaces ; // Read #vertices

	do // go to end of header
	{
		fp >> tag ;
	} while (tag != std::string("end_header")) ;

	// Define containers
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
757
758
	VertexAttribute<typename PFP::VEC3> positions =  m_map.template getAttribute<typename PFP::VEC3, VERTEX>("position") ;
;
759
	if (!positions.isValid())
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
760
		positions = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("position") ;
761
762
	attrNames.push_back(positions.name()) ;

Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
763
764
765
766
	VertexAttribute<typename PFP::VEC3> *frame = new VertexAttribute<typename PFP::VEC3>[3] ;
	frame[0] = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("frameT") ; // Tangent
	frame[0] = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("frameB") ; // Binormal
	frame[0] = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("frameN") ; // Normal
767
768
769
770
	attrNames.push_back(frame[0].name()) ;
	attrNames.push_back(frame[1].name()) ;
	attrNames.push_back(frame[2].name()) ;

771
	VertexAttribute<typename PFP::VEC3> *PBcoefs = NULL, *SHcoefs = NULL ;
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
772
	if (PTM)
773
	{
774
		PBcoefs = new VertexAttribute<typename PFP::VEC3>[nbCoefs] ;
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
775
776
777
		for (unsigned int i = 0 ; i < nbCoefs ; ++i)
		{
			std::stringstream name ;
778
779
780
			name << "PBcoefs" << i ;
			PBcoefs[i] = m_map.template addAttribute<typename PFP::VEC3, VERTEX>(name.str()) ;
			attrNames.push_back(PBcoefs[i].name()) ;
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
781
		}
782
783
	}

Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
784
785
786
787
788
789
790
791
792
793
794
795
796
	if (SH)
	{
		SHcoefs = new VertexAttribute<typename PFP::VEC3>[nbCoefs] ;
		for (unsigned int i = 0 ; i < nbCoefs ; ++i)
		{
			std::stringstream name ;
			name << "SHcoefs" << i ;
			SHcoefs[i] = m_map.template addAttribute<typename PFP::VEC3, VERTEX>(name.str()) ;
			attrNames.push_back(SHcoefs[i].name()) ;
		}
	}

	VertexAttribute<typename PFP::REAL> *remainders = new VertexAttribute<typename PFP::REAL>[nbRemainders] ;
797
798
799
800
	for (unsigned int i = 0 ; i < nbRemainders ; ++i)
	{
		std::stringstream name ;
		name << "remainderNo" << i ;
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
801
		remainders[i] = m_map.template addAttribute<typename PFP::REAL, VERTEX>(name.str()) ;
802
803
804
805
806
807
808
809
		attrNames.push_back(remainders[i].name()) ;
	}

	// Read vertices
	std::vector<unsigned int> verticesID ;
	verticesID.reserve(nbVertices) ;

	float* properties = new float[nbProps] ;
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
810
	AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ;
811
812
813
814
815
816
817
818
819
820
821
822
	for (unsigned int i = 0 ; i < nbVertices ; ++i) // Read and store properties for current vertex
	{
		unsigned int id = container.insertLine() ;
		verticesID.push_back(id) ;

		for (unsigned int j = 0 ; j < nbProps ; ++j) // get all properties
			fp >> properties[j] ;

		positions[id] = VEC3(properties[0],properties[1],properties[2]) ; // position
		for (unsigned int k = 0 ; k < 3 ; ++k) // frame
			for (unsigned int l = 0 ; l < 3 ; ++l)
				frame[k][id][l] = properties[3+(3*k+l)] ;
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
823
824
825
826
		for (unsigned int l = 0 ; l < nbCoefs ; ++l) // coefficients
			for (unsigned int k = 0 ; k < 3 ; ++k)
			{
				if (PTM)
827
					PBcoefs[l][id][k] = (typename PFP::REAL)(properties[12+(3*l+k)]) ;
Kenneth Vanhoey's avatar
Kenneth Vanhoey committed
828
829
830
				else /* if SH */
					SHcoefs[l][id][k] = (typename PFP::REAL)(properties[12+(3*l+k)]) ;
			}
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
		unsigned int cur = 12+3*nbCoefs ;
		for (unsigned int k = 0 ; k < nbRemainders ; ++k) // remaining data
			remainders[k][id] = properties[cur + k] ;
	}
	m_nbVertices = verticesID.size() ;
	delete[] properties ;

	// Read faces index
	m_nbEdges.reserve(m_nbFaces) ;
	m_emb.reserve(3 * m_nbFaces) ;
	for (unsigned int i = 0 ; i < m_nbFaces ; ++i)
	{
		// read the indices of vertices for current face
		unsigned int nbEdgesForFace ;
		fp >> nbEdgesForFace ;
		m_nbEdges.push_back(nbEdgesForFace);

		unsigned int vertexID ;
		for (unsigned int j=0 ; j < nbEdgesForFace ; ++j)
		{
			fp >> vertexID ;
			m_emb.push_back(verticesID[vertexID]);
		}
	}

	// Close file
	fp.close() ;

	return true ;
}

template <typename PFP>
bool MeshTablesSurface<PFP>::importPlySLFgenericBin(const std::string& filename, std::vector<std::string>& attrNames)
{
	// Open file
	std::ifstream fp(filename.c_str(), std::ios::in | std::ios::binary) ;
	if (!fp.good())
	{
		CGoGNerr << "Unable to open file " << filename << CGoGNendl ;
		return false ;
	}

	// Read quantities : #vertices, #faces, #properties, degree of polynomials
    std::string tag ;

    fp >> tag;
	if (tag != std::string("ply")) // verify file type
	{
		CGoGNerr << filename << " is not a ply file !" <<  CGoGNout ;
		return false ;
	}

	do // go to #vertices
	{
		fp >> tag ;
	} while (tag != std::string("vertex")) ;
	unsigned int nbVertices ;
	fp >> nbVertices ; // Read #vertices

	bool position = false ;
	bool tangent = false ;
	bool binormal = false ;
	bool normal = false ;
	bool PTM = false ;
	bool SH = false ;
896
	unsigned int propSize = 0 ;
897
898
899
900
901
902
903
	unsigned int nbProps = 0 ;		// # properties
	unsigned int nbCoefs = 0 ; 	// # coefficients
	do // go to #faces and count #properties
	{
		fp >> tag ;
		if (tag == std::string("property"))
			++nbProps ;
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
		else if (tag == std::string("int8") || tag == std::string("uint8"))
		{
			if (propSize < 2)
			{
				propSize = 1 ;
				std::cerr << "MeshTablesSurface<PFP>::importPlySLFgenericBin: only float64 is yet handled" << std::endl ;
				assert(!"MeshTablesSurface<PFP>::importPlySLFgenericBin: only float64 is yet handled") ;			}
			else
			{
				std::cerr << "MeshTablesSurface<PFP>::importPlySLFgenericBin: all properties should be same size: otherwise not handled" << std::endl ;
				assert(!"MeshTablesSurface<PFP>::importPlySLFgenericBin: all properties should be same size: otherwise not handled") ;
			}
		}
		else if (tag == std::string("int16") || tag == std::string("uint16"))
		{
			if (propSize == 0 || propSize == 2)
			{
				propSize = 2 ;
				std::cerr << "MeshTablesSurface<PFP>::importPlySLFgenericBin: only float64 is yet handled" << std::endl ;
				assert(!"MeshTablesSurface<PFP>::importPlySLFgenericBin: only float64 is yet handled") ;			}
			else
			{
				std::cerr << "MeshTablesSurface<PFP>::importPlySLFgenericBin: all properties should be same size: otherwise not handled" << std::endl ;
				assert(!"MeshTablesSurface<PFP>::importPlySLFgenericBin: all properties should be same size: otherwise not handled") ;
			}
		}
		else if (tag == std::string("int32") || tag == std::string("float32") || tag == std::string("uint32"))
		{
			if (propSize == 0 || propSize == 4)
			{
				propSize = 4 ;
				std::cerr << "MeshTablesSurface<PFP>::importPlySLFgenericBin: only float64 is yet handled" << std::endl ;
				assert(!"MeshTablesSurface<PFP>::importPlySLFgenericBin: only float64 is yet handled") ;
			}
			else
			{
				std::cerr << "MeshTablesSurface<PFP>::importPlySLFgenericBin: all properties should be same size: otherwise not handled" << std::endl ;
				assert(!"MeshTablesSurface<PFP>::importPlySLFgenericBin: all properties should be same size: otherwise not handled") ;
			}
		}
		else if (tag == std::string("int64") || tag == std::string("float64"))
		{
			if (propSize == 0 || propSize == 8)
			{
				propSize = 8 ;
				//std::cerr << "MeshTablesSurface<PFP>::importPlySLFgenericBin: only float32 is yet handled" << std::endl ;
				//assert(!"MeshTablesSurface<PFP>::importPlySLFgenericBin: only float32 is yet handled") ;
			}
			else
			{
				std::cerr << "MeshTablesSurface<PFP>::importPlySLFgenericBin: all properties should be same size: otherwise not handled" << std::endl ;
				assert(!"MeshTablesSurface<PFP>::importPlySLFgenericBin: all properties should be same size: otherwise not handled") ;
			}
		}
958
959
960
961
962
963
964
965
966
967
968
969
970
971
		else if (tag == std::string("x") || tag == std::string("y") || tag == std::string("z"))
			position = true ;
		//else if (tag == std::string("tx") || tag == std::string("ty") || tag == std::string("tz"))
		else if (tag == std::string("frameT_0") || tag == std::string("frameT_1") || tag == std::string("frameT_2"))
			tangent = true ;
		//else if (tag == std::string("bx") || tag == std::string("by") || tag == std::string("bz"))
		else if (tag == std::string("frameB_0") || tag == std::string("frameB_1") || tag == std::string("frameB_2"))
			binormal = true ;
		//else if (tag == std::string("nx") || tag == std::string("ny") || tag == std::string("nz"))
		else if (tag == std::string("frameN_0") || tag == std::string("frameN_1") || tag == std::string("frameN_2"))
			normal = true ;
		// else if (tag.substr(0,1) == std::string("C") && tag.substr(2,1) == std::string("_"))
		else if ((tag.length() > 8) && tag.find("_") != std::string::npos)
		{
972
			if (tag.substr(0,7) == std::string("PBcoefs"))
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
			{
				PTM = true ;
				++nbCoefs ;
			}
			else if (tag.substr(0,7) == std::string("SHcoefs"))
			{
				SH = true ;
				++nbCoefs ;
			}
		}
	} while (tag != std::string("face")) ;
	unsigned int nbRemainders = nbProps ;		// # remaining properties
	nbRemainders -= nbCoefs + 3*(position==true) + 3*(tangent==true) + 3*(binormal==true) + 3*(normal==true) ;
	nbCoefs /= 3 ;

	assert(!(SH && PTM) || !"MeshTablesSurface<PFP>::importPlySLFgenericBin: Confusing functional colors since both SLF and RF are defined.") ;
	if (SH && PTM)
		std::cerr << "MeshTablesSurface<PFP>::importPlySLFgenericBin: Confusing functional colors since both SLF and RF are defined." << std::endl ;

	fp >> m_nbFaces ; // Read #vertices

	do // go to end of header
	{
		fp >> tag ;
	} while (tag != std::string("end_header")) ;

	char* endline = new char[1] ;
	fp.read(endline, sizeof(char)) ;