embeddedGMap2.cpp 13.9 KB
Newer Older
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           *
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 PURPOSE. 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/                                           *
21 22 23 24 25 26 27 28
* Contact information: cgogn@unistra.fr                                        *
*                                                                              *
*******************************************************************************/

#include <vector>
#include <algorithm>

#include "Topology/gmap/embeddedGMap2.h"
29 30
#include "Topology/generic/traversor/traversor2.h"
#include "Algo/Topo/basic.h"
31 32 33 34

namespace CGoGN
{

Thery Sylvain's avatar
Thery Sylvain committed
35 36 37 38 39 40 41 42 43 44
Dart EmbeddedGMap2::newFace(unsigned int nbEdges, bool withBoundary)
{
	Dart d = GMap2::newFace(nbEdges, withBoundary);

	if(withBoundary)
	{
		if (isOrbitEmbedded<VERTEX>())
		{
			Traversor2FV<EmbeddedGMap2> t(*this, d);
			for(Dart it = t.begin(); it != t.end(); it = t.next())
Pierre Kraemer's avatar
Pierre Kraemer committed
45
				initOrbitEmbeddingOnNewCell<VERTEX>(it) ;
Thery Sylvain's avatar
Thery Sylvain committed
46 47 48 49 50 51
		}

		if(isOrbitEmbedded<EDGE>())
		{
			Traversor2FE<EmbeddedGMap2> t(*this, d);
			for(Dart it = t.begin(); it != t.end(); it = t.next())
Pierre Kraemer's avatar
Pierre Kraemer committed
52
				initOrbitEmbeddingOnNewCell<EDGE>(it) ;
Thery Sylvain's avatar
Thery Sylvain committed
53 54 55 56
		}

		if(isOrbitEmbedded<FACE>())
		{
Pierre Kraemer's avatar
Pierre Kraemer committed
57 58
			initOrbitEmbeddingOnNewCell<FACE>(d) ;
			initOrbitEmbeddingOnNewCell<FACE>(phi2(d)) ;
Thery Sylvain's avatar
Thery Sylvain committed
59 60 61
		}
	}

Sylvain Thery's avatar
Sylvain Thery committed
62 63 64 65 66 67 68 69
//	else
//	{
//		if (isOrbitEmbedded<VERTEX>())
//		{
//			Traversor2FV<EmbeddedGMap2> t(*this, d);
//			for(Dart it = t.begin(); it != t.end(); it = t.next())
//				initOrbitEmbeddingNewCell<VERTEX>(it) ;
//		}
Thery Sylvain's avatar
Thery Sylvain committed
70

Sylvain Thery's avatar
Sylvain Thery committed
71 72 73 74
//		if(isOrbitEmbedded<FACE>())
//			initOrbitEmbeddingNewCell<FACE>(d) ;

//	}
Thery Sylvain's avatar
Thery Sylvain committed
75 76 77 78
	return d ;
}


79 80 81 82 83 84 85
void EmbeddedGMap2::splitVertex(Dart d, Dart e)
{
	Dart dd = phi2(d) ;
	Dart ee = phi2(e) ;

	GMap2::splitVertex(d, e) ;

86
	if (isOrbitEmbedded<VERTEX>())
87
	{
88 89 90 91
		unsigned int vEmb = getEmbedding<VERTEX>(d) ;
		setDartEmbedding<VERTEX>(phi1(dd), vEmb) ;
		setDartEmbedding<VERTEX>(beta2(phi1(dd)), vEmb) ;
		setDartEmbedding<VERTEX>(beta0(dd), vEmb) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
92

93
		setOrbitEmbeddingOnNewCell<VERTEX>(e) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
94
		copyCellAttributes<VERTEX>(e, d) ;
95 96
	}

97 98
	if(isOrbitEmbedded<EDGE>())
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
99
		initOrbitEmbeddingOnNewCell<EDGE>(phi1(dd)) ;
100 101
	}

102
	if(isOrbitEmbedded<FACE>())
103
	{
104
		unsigned int f1Emb = getEmbedding<FACE>(dd) ;
105 106
		setDartEmbedding<FACE>(phi1(dd), f1Emb) ;
		setDartEmbedding<FACE>(beta0(phi1(dd)), f1Emb) ;
107
		unsigned int f2Emb = getEmbedding<FACE>(ee) ;
108 109
		setDartEmbedding<FACE>(phi1(ee), f2Emb) ;
		setDartEmbedding<FACE>(beta0(phi1(ee)), f2Emb) ;
110 111 112
	}
}

113
Dart EmbeddedGMap2::deleteVertex(Dart d)
114
{
115 116
	Dart f = GMap2::deleteVertex(d) ;
	if(f != NIL)
117
	{
118
		if (isOrbitEmbedded<FACE>())
119
		{
120
			setOrbitEmbedding<FACE>(f, getEmbedding<FACE>(f)) ;
121
		}
122
	}
123
	return f ;
124
}
125

126
Dart EmbeddedGMap2::cutEdge(Dart d)
127
{
128
	Dart nd = GMap2::cutEdge(d) ;
129

130 131
	if(isOrbitEmbedded<VERTEX>())
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
132
		initOrbitEmbeddingOnNewCell<VERTEX>(nd) ;
133 134
	}

135
	if (isOrbitEmbedded<EDGE>())
136
	{
137 138 139
		unsigned int eEmb = getEmbedding<EDGE>(d) ;
		setDartEmbedding<EDGE>(phi2(d), eEmb) ;
		setDartEmbedding<EDGE>(beta0(d), eEmb) ;
140
		setOrbitEmbeddingOnNewCell<EDGE>(nd) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
141
		copyCellAttributes<EDGE>(nd, d) ;
142
	}
Thomas's avatar
Thomas committed
143

144
	if(isOrbitEmbedded<FACE>())
145
	{
146 147 148
		unsigned int f1Emb = getEmbedding<FACE>(d) ;
		setDartEmbedding<FACE>(phi1(d), f1Emb) ;
		setDartEmbedding<FACE>(beta0(d), f1Emb) ;
149
		Dart e = phi2(nd) ;
150 151 152
		unsigned int f2Emb = getEmbedding<FACE>(d) ;
		setDartEmbedding<FACE>(phi1(e), f2Emb) ;
		setDartEmbedding<FACE>(beta0(e), f2Emb) ;
153
	}
154 155

	return nd ;
156 157
}

158
bool EmbeddedGMap2::uncutEdge(Dart d)
159
{
160 161
	if(GMap2::uncutEdge(d))
	{
162
		if(isOrbitEmbedded<EDGE>())
163
		{
164 165 166
			unsigned int eEmb = getEmbedding<EDGE>(d) ;
			setDartEmbedding<EDGE>(phi2(d), eEmb) ;
			setDartEmbedding<EDGE>(beta0(d), eEmb) ;
167 168 169 170
		}
		return true ;
	}
	return false ;
171
}
172 173 174 175 176 177 178 179 180 181 182 183

bool EmbeddedGMap2::edgeCanCollapse(Dart d)
{
	if(isBoundaryVertex(d) || isBoundaryVertex(phi1(d)))
		return false ;

	unsigned int val_v1 = vertexDegree(d) ;
	unsigned int val_v2 = vertexDegree(phi1(d)) ;

	if(val_v1 + val_v2 < 8 || val_v1 + val_v2 > 14)
		return false ;

184
	if(faceDegree(d) == 3)
185 186 187 188 189 190
	{
		if(vertexDegree(phi_1(d)) < 4)
			return false ;
	}

	Dart dd = phi2(d) ;
191
	if(faceDegree(dd) == 3)
192 193 194 195 196 197 198 199 200 201 202 203
	{
		if(vertexDegree(phi_1(dd)) < 4)
			return false ;
	}

	// Check vertex sharing condition
	std::vector<unsigned int> vu1 ;
	vu1.reserve(32) ;
	Dart vit1 = alpha1(alpha1(d)) ;
	Dart end = phi1(dd) ;
	do
	{
204
		unsigned int ve = getEmbedding<VERTEX>(phi2(vit1)) ;
205 206 207 208 209 210 211
		vu1.push_back(ve) ;
		vit1 = alpha1(vit1) ;
	} while(vit1 != end) ;
	end = phi1(d) ;
	Dart vit2 = alpha1(alpha1(dd)) ;
	do
	{
212
		unsigned int ve = getEmbedding<VERTEX>(phi2(vit2)) ;
213 214 215 216 217 218 219 220 221 222 223 224
		std::vector<unsigned int>::iterator it = std::find(vu1.begin(), vu1.end(), ve) ;
		if(it != vu1.end())
			return false ;
		vit2 = alpha1(vit2) ;
	} while(vit2 != end) ;

	return true ;
}

Dart EmbeddedGMap2::collapseEdge(Dart d, bool delDegenerateFaces)
{
	unsigned int vEmb = EMBNULL ;
225
	if (isOrbitEmbedded<VERTEX>())
226
	{
227
		vEmb = getEmbedding<VERTEX>(d) ;
228 229 230 231
	}

	Dart dV = GMap2::collapseEdge(d, delDegenerateFaces);

232
	if (isOrbitEmbedded<VERTEX>())
233
	{
234
		setOrbitEmbedding<VERTEX>(dV, vEmb) ;
235 236 237 238 239 240 241 242 243 244 245
	}

	return dV ;
}

bool EmbeddedGMap2::flipEdge(Dart d)
{
	if(GMap2::flipEdge(d))
	{
		Dart e = phi2(d) ;

246
		if (isOrbitEmbedded<VERTEX>())
247
		{
248 249 250 251 252 253
			unsigned int v1Emb = getEmbedding<VERTEX>(beta1(d)) ;
			setDartEmbedding<VERTEX>(d, v1Emb) ;
			setDartEmbedding<VERTEX>(beta2(d), v1Emb) ;
			unsigned int v2Emb = getEmbedding<VERTEX>(beta1(e)) ;
			setDartEmbedding<VERTEX>(e, v2Emb) ;
			setDartEmbedding<VERTEX>(beta2(e), v2Emb) ;
254
		}
255
		if (isOrbitEmbedded<FACE>())
256
		{
257 258 259 260 261 262
			unsigned int f1Emb = getEmbedding<FACE>(d) ;
			setDartEmbedding<FACE>(phi_1(d), f1Emb) ;
			setDartEmbedding<FACE>(beta1(d), f1Emb) ;
			unsigned int f2Emb = getEmbedding<FACE>(e) ;
			setDartEmbedding<FACE>(phi_1(e), f2Emb) ;
			setDartEmbedding<FACE>(beta1(e), f2Emb) ;
263 264 265 266 267 268 269 270 271 272 273 274
		}
		return true ;
	}
	return false ;
}

bool EmbeddedGMap2::flipBackEdge(Dart d)
{
	if(GMap2::flipBackEdge(d))
	{
		Dart e = phi2(d) ;

275
		if (isOrbitEmbedded<VERTEX>())
276
		{
277 278 279 280 281 282
			unsigned int v1Emb = getEmbedding<VERTEX>(beta1(d)) ;
			setDartEmbedding<VERTEX>(d, v1Emb) ;
			setDartEmbedding<VERTEX>(beta2(d), v1Emb) ;
			unsigned int v2Emb = getEmbedding<VERTEX>(beta1(e)) ;
			setDartEmbedding<VERTEX>(e, v2Emb) ;
			setDartEmbedding<VERTEX>(beta2(e), v2Emb) ;
283
		}
Thomas's avatar
Thomas committed
284

285
		if (isOrbitEmbedded<FACE>())
286
		{
287 288 289 290 291 292
			unsigned int f1Emb = getEmbedding<FACE>(d) ;
			setDartEmbedding<FACE>(phi1(d), f1Emb) ;
			setDartEmbedding<FACE>(beta0(phi1(d)), f1Emb) ;
			unsigned int f2Emb = getEmbedding<FACE>(e) ;
			setDartEmbedding<FACE>(phi1(e), f2Emb) ;
			setDartEmbedding<FACE>(beta0(phi1(e)), f2Emb) ;
293 294 295 296 297 298
		}
		return true ;
	}
	return false ;
}

299 300 301 302
//void EmbeddedGMap2::insertEdgeInVertex(Dart d, Dart e)
//{
//	GMap2::insertEdgeInVertex(d, e);
//
303
//	if (isOrbitEmbedded<VERTEX>())
304
//	{
305 306
//		copyDartEmbedding<VERTEX>(e, d) ;
//		copyDartEmbedding<VERTEX>(beta2(e), d) ;
307 308
//	}
//
309
//	if (isOrbitEmbedded<FACE>())
310 311 312
//	{
//		if(!sameFace(d,e))
//		{
313
//			setOrbitEmbeddingOnNewCell<FACE>(e);
314
//			copyCell<FACE>(e, d) ;
315 316 317
//		}
//		else
//		{
318
//			setOrbitEmbedding<FACE>(d, getEmbedding<FACE>(d)) ;
319 320 321 322 323 324 325 326 327 328
//		}
//	}
//}
//
//void EmbeddedGMap2::removeEdgeFromVertex(Dart d)
//{
//	Dart dPrev = alpha_1(d);
//
//	GMap2::removeEdgeFromVertex(d);
//
329
//	if (isOrbitEmbedded<VERTEX>())
330
//	{
331
//		setOrbitEmbeddingOnNewCell<VERTEX>(d);
332
//		copyCell<VERTEX>(d, dPrev);
333 334
//	}
//
335
//	if (isOrbitEmbedded<FACE>())
336 337 338
//	{
//		if(!sameFace(d, dPrev))
//		{
339
//			setOrbitEmbeddingOnNewCell<FACE>(d);
340
//			copyCell<FACE>(d, dPrev) ;
341 342 343
//		}
//		else
//		{
344
//			setOrbitEmbedding<FACE>(d, getEmbedding<FACE>(d)) ;
345 346 347
//		}
//	}
//}
348

349
void EmbeddedGMap2::sewFaces(Dart d, Dart e, bool withBoundary)
350
{
351 352
	// for fixed point construction (import & primitives)
	if (!withBoundary)
353
	{
354
		GMap2::sewFaces(d, e, false) ;
Thery Sylvain's avatar
Thery Sylvain committed
355 356
		if(isOrbitEmbedded<EDGE>())
		{
Pierre Kraemer's avatar
Pierre Kraemer committed
357
			initOrbitEmbeddingOnNewCell<EDGE>(d) ;
Thery Sylvain's avatar
Thery Sylvain committed
358
		}
359
		return ;
360 361
	}

362
	GMap2::sewFaces(d, e, true) ;
363

364
	if (isOrbitEmbedded<VERTEX>())
365
	{
366 367
		setOrbitEmbedding<VERTEX>(d, getEmbedding<VERTEX>(d)) ;
		setOrbitEmbedding<VERTEX>(e, getEmbedding<VERTEX>(beta0(d))) ;
368 369
	}

370
	if (isOrbitEmbedded<EDGE>())
371
	{
372
		setOrbitEmbedding<EDGE>(e, getEmbedding<EDGE>(d)) ;
373 374 375 376 377
	}
}

void EmbeddedGMap2::unsewFaces(Dart d)
{
378 379
	Dart e = beta2(d);
	GMap2::unsewFaces(d);
380

381
	if (isOrbitEmbedded<VERTEX>())
382
	{
383
		if(!sameVertex(d,e))
384
		{
385
			setOrbitEmbeddingOnNewCell<VERTEX>(e);
Pierre Kraemer's avatar
Pierre Kraemer committed
386
			copyCellAttributes<VERTEX>(e, d);
387 388
		}

389 390 391 392
		d = beta0(d);
		e = beta0(e);

		if(!sameVertex(d,e))
393
		{
394
			setOrbitEmbeddingOnNewCell<VERTEX>(e);
Pierre Kraemer's avatar
Pierre Kraemer committed
395
			copyCellAttributes<VERTEX>(e, d);
396 397
		}
	}
398

399
	if (isOrbitEmbedded<EDGE>())
400
	{
401
		setOrbitEmbeddingOnNewCell<EDGE>(e);
Pierre Kraemer's avatar
Pierre Kraemer committed
402
		copyCellAttributes<EDGE>(e, d);
403 404 405 406 407
	}
}

bool EmbeddedGMap2::collapseDegeneratedFace(Dart d)
{
408 409 410 411
	Dart e = beta2(d) ;
	bool updateEdgeEmb = false ;
	if(phi1(d) != d)
		updateEdgeEmb = true ;
412 413 414

	if(GMap2::collapseDegeneratedFace(d))
	{
415
		if (isOrbitEmbedded<EDGE>() && updateEdgeEmb)
416
		{
417 418 419
			unsigned int eEmb = getEmbedding<EDGE>(e) ;
			setDartEmbedding<EDGE>(beta2(e), eEmb) ;
			setDartEmbedding<EDGE>(phi2(e), eEmb) ;
420 421 422 423 424 425 426 427 428 429
		}
		return true ;
	}
	return false ;
}

void EmbeddedGMap2::splitFace(Dart d, Dart e)
{
	GMap2::splitFace(d, e) ;

430
	if (isOrbitEmbedded<VERTEX>())
431
	{
432 433 434 435 436 437 438 439
		unsigned int v1Emb = getEmbedding<VERTEX>(d) ;
		setDartEmbedding<VERTEX>(phi_1(e), v1Emb) ;
		setDartEmbedding<VERTEX>(beta1(d), v1Emb) ;
		setDartEmbedding<VERTEX>(beta1(phi_1(e)), v1Emb) ;
		unsigned int v2Emb = getEmbedding<VERTEX>(e) ;
		setDartEmbedding<VERTEX>(phi_1(d), v2Emb) ;
		setDartEmbedding<VERTEX>(beta1(e), v2Emb) ;
		setDartEmbedding<VERTEX>(beta1(phi_1(d)), v2Emb) ;
440
	}
441 442 443

	if(isOrbitEmbedded<EDGE>())
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
444
		initOrbitEmbeddingOnNewCell<EDGE>(beta1(d)) ;
445 446
	}

447
	if (isOrbitEmbedded<FACE>())
448
	{
449 450 451
		unsigned int fEmb = getEmbedding<FACE>(d) ;
		setDartEmbedding<FACE>(phi_1(d), fEmb) ;
		setDartEmbedding<FACE>(beta1(phi_1(d)), fEmb) ;
452
		setOrbitEmbeddingOnNewCell<FACE>(e) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
453
		copyCellAttributes<FACE>(e, d) ;
454 455 456 457 458 459 460 461 462
	}
}

bool EmbeddedGMap2::mergeFaces(Dart d)
{
	Dart dNext = phi1(d) ;

	if(GMap2::mergeFaces(d))
	{
463
		if (isOrbitEmbedded<FACE>())
464
		{
465
			setOrbitEmbedding<FACE>(dNext, getEmbedding<FACE>(dNext)) ;
466 467 468 469 470 471 472 473 474 475 476
		}
		return true ;
	}
	return false ;
}

bool EmbeddedGMap2::mergeVolumes(Dart d, Dart e)
{
	std::vector<Dart> darts ;
	std::vector<unsigned int> vEmb ;
	std::vector<unsigned int> eEmb ;
477 478 479 480
	darts.reserve(32) ;
	vEmb.reserve(32) ;
	eEmb.reserve(32) ;

481 482 483 484 485
	Dart fit = d ;
	do
	{
		darts.push_back(phi2(fit)) ;

486
		if (isOrbitEmbedded<VERTEX>())
487
		{
488
			vEmb.push_back(getEmbedding<VERTEX>(phi2(fit))) ;
489 490
		}

491
		if (isOrbitEmbedded<EDGE>())
492
		{
493
			eEmb.push_back(getEmbedding<EDGE>(fit)) ;
494 495 496 497 498 499 500 501 502
		}

		fit = phi1(fit) ;
	} while (fit != d) ;

	if(GMap2::mergeVolumes(d, e))
	{
		for(unsigned int i = 0; i < darts.size(); ++i)
		{
503
			if (isOrbitEmbedded<VERTEX>())
504
			{
505
				setOrbitEmbedding<VERTEX>(darts[i], vEmb[i]) ;
506 507
			}

508
			if (isOrbitEmbedded<EDGE>())
509
			{
510
				setOrbitEmbedding<EDGE>(darts[i], eEmb[i]) ;
511 512 513 514 515 516 517
			}
		}
		return true ;
	}
	return false ;
}

518
unsigned int EmbeddedGMap2::closeHole(Dart d, bool forboundary)
519 520 521
{
	unsigned int nbE = GMap2::closeHole(d) ;
	Dart dd = phi2(d) ;
522
	Dart it = dd ;
523 524
	do
	{
525
		if (isOrbitEmbedded<VERTEX>())
526
		{
527 528
			copyDartEmbedding<VERTEX>(it, beta2(it)) ;
			copyDartEmbedding<VERTEX>(beta0(it), phi2(it)) ;
529
		}
530
		if (isOrbitEmbedded<EDGE>())
531
		{
532 533 534
			unsigned int eEmb = getEmbedding<EDGE>(beta2(it)) ;
			setDartEmbedding<EDGE>(it, eEmb) ;
			setDartEmbedding<EDGE>(beta0(it), eEmb) ;
535
		}
536 537
		it = phi1(it) ;
	} while(it != dd) ;
538 539 540

	if(isOrbitEmbedded<FACE>())
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
541
		initOrbitEmbeddingOnNewCell<FACE>(dd) ;
542 543
	}

544 545 546 547 548 549 550 551 552 553 554 555
	return nbE ;
}

bool EmbeddedGMap2::check()
{
	bool topo = GMap2::check() ;
	if (!topo)
		return false ;

	CGoGNout << "Check: embedding begin" << CGoGNendl ;
	for(Dart d = begin(); d != end(); next(d))
	{
556
		if (isOrbitEmbedded<VERTEX>())
557
		{
558
			if (getEmbedding<VERTEX>(d) != getEmbedding<VERTEX>(alpha1(d)))
559 560 561 562 563 564
			{
				CGoGNout << "Check: different embeddings on vertex" << CGoGNendl ;
				return false ;
			}
		}

565
		if (isOrbitEmbedded<EDGE>())
566
		{
567
			if (getEmbedding<EDGE>(d) != getEmbedding<EDGE>(phi2(d)))
568 569 570 571 572 573
			{
				CGoGNout << "Check: different embeddings on edge" << CGoGNendl ;
				return false ;
			}
		}

574
		if (isOrbitEmbedded<FACE>())
575
		{
576
			if (getEmbedding<FACE>(d) != getEmbedding<FACE>(phi1(d)))
577 578 579 580 581 582
		{
				CGoGNout << "Check: different embeddings on face" << CGoGNendl ;
				return false ;
			}
		}
	}
583

584
	CGoGNout << "Check: embedding ok" << CGoGNendl ;
585

586
	std::cout << "nb vertex orbits : " << Algo::Topo::getNbOrbits<VERTEX>(*this) << std::endl ;
587 588
    std::cout << "nb vertex cells : " << m_attribs[VERTEX].size() << std::endl ;

589
	std::cout << "nb edge orbits : " << Algo::Topo::getNbOrbits<EDGE>(*this) << std::endl ;
590 591
    std::cout << "nb edge cells : " << m_attribs[EDGE].size() << std::endl ;

592
	std::cout << "nb face orbits : " << Algo::Topo::getNbOrbits<FACE>(*this) << std::endl ;
593 594
    std::cout << "nb face cells : " << m_attribs[FACE].size() << std::endl ;

595 596 597 598
	return true ;
}

} // namespace CGoGN