1
// ---------------------------------------------------------
3
// nondestructivetrimesh.cpp
6
// Implementation of NonDestructiveTriMesh: the graph of a
7
// triangle surface mesh. See header for more details.
9
// ---------------------------------------------------------
11
// ---------------------------------------------------------
13
// ---------------------------------------------------------
15
#include <nondestructivetrimesh.h>
21
#include <wallclocktime.h>
23
// ---------------------------------------------------------
24
// Local constants, typedefs, macros
25
// ---------------------------------------------------------
29
/// Avoid modulo operator in (i+1)%3
30
const unsigned int i_plus_one_mod_three[3] = {1,2,0};
35
// ---------------------------------------------------------
36
// Member function definitions
37
// ---------------------------------------------------------
39
// --------------------------------------------------------
41
/// Clear all mesh information
43
// --------------------------------------------------------
45
void NonDestructiveTriMesh::clear()
52
// --------------------------------------------------------
54
/// Mark a triangle as deleted without actually changing the data structures
56
// --------------------------------------------------------
58
void NonDestructiveTriMesh::nondestructive_remove_triangle(size_t tri)
60
// Update the vertex->triangle map, m_vertex_to_triangle_map
62
Vec3st& t = m_tris[tri];
63
for(unsigned int i = 0; i < 3; i++)
65
// Get the set of triangles incident on vertex t[i]
66
std::vector<size_t>& vt = m_vertex_to_triangle_map[t[i]];
68
for( int j = 0; j < (int)vt.size(); j++ )
70
// If a triangle incident on vertex t[i] is tri, delete it
73
vt.erase( vt.begin() + j );
79
// Update the triangle->edge map, m_triangle_to_edge_map
81
Vec3st& te = m_triangle_to_edge_map[tri];
83
for(unsigned int i = 0; i < 3; i++)
85
size_t inc_edge = te[i];
87
std::vector<size_t>& et = m_edge_to_triangle_map[inc_edge];
89
for( int j = 0; j < (int) et.size(); j++)
93
et.erase( et.begin() + j );
100
m_is_boundary_edge[inc_edge] = true;
104
m_is_boundary_edge[inc_edge] = false;
109
// No triangles are incident on this edge. Delete it.
110
nondestructive_remove_edge( inc_edge );
114
// triangle is deleted, clear its auxiliary structures
115
te[0] = te[1] = te[2] = 0;
117
update_is_boundary_vertex( t[0] );
118
update_is_boundary_vertex( t[1] );
119
update_is_boundary_vertex( t[2] );
121
// Clear t, marking it as deleted
122
t[0] = t[1] = t[2] = 0;
128
// --------------------------------------------------------
130
/// Add a triangle to the tris structure, update connectivity
132
// --------------------------------------------------------
134
size_t NonDestructiveTriMesh::nondestructive_add_triangle( const Vec3st& tri )
136
assert( tri[0] < m_vertex_to_edge_map.size() );
137
assert( tri[1] < m_vertex_to_edge_map.size() );
138
assert( tri[2] < m_vertex_to_edge_map.size() );
140
size_t idx = m_tris.size();
141
m_tris.push_back(tri);
142
m_triangle_to_edge_map.resize(idx+1);
144
for(unsigned int i = 0; i < 3; i++)
146
size_t vtx0 = tri[ i ];
147
size_t vtx1 = tri[ i_plus_one_mod_three[i] ];
149
// Find the edge composed of these two vertices
150
size_t e = get_edge_index(vtx0, vtx1);
151
if(e == m_edges.size())
153
// if the edge doesn't exist, add it
154
e = nondestructive_add_edge(vtx0, vtx1);
157
// Update connectivity
158
m_edge_to_triangle_map[e].push_back(idx); // edge->triangle
160
if ( m_edge_to_triangle_map[e].size() == 1 )
162
m_is_boundary_edge[e] = true;
166
m_is_boundary_edge[e] = false;
169
m_triangle_to_edge_map[idx][i] = e; // triangle->edge
170
m_vertex_to_triangle_map[tri[i]].push_back(idx); // vertex->triangle
173
update_is_boundary_vertex( tri[0] );
174
update_is_boundary_vertex( tri[1] );
175
update_is_boundary_vertex( tri[2] );
181
// --------------------------------------------------------
183
/// Add a vertex, update connectivity. Return index of new vertex.
185
// --------------------------------------------------------
187
size_t NonDestructiveTriMesh::nondestructive_add_vertex( )
189
assert( m_vertex_to_edge_map.size() == m_vertex_to_triangle_map.size() );
190
assert( m_vertex_to_edge_map.size() == m_is_boundary_vertex.size() );
192
m_vertex_to_edge_map.resize( m_vertex_to_edge_map.size() + 1 );
193
m_vertex_to_triangle_map.resize( m_vertex_to_triangle_map.size() + 1 );
194
m_is_boundary_vertex.resize( m_is_boundary_vertex.size() + 1 );
196
return m_vertex_to_triangle_map.size() - 1;
200
// --------------------------------------------------------
202
/// Remove a vertex, update connectivity
204
// --------------------------------------------------------
206
void NonDestructiveTriMesh::nondestructive_remove_vertex(size_t vtx)
209
m_vertex_to_triangle_map[vtx].clear(); //triangles incident on vertices
211
// check any m_edges incident on this vertex are marked as deleted
212
for ( size_t i = 0; i < m_vertex_to_edge_map[vtx].size(); ++i )
214
assert( m_edges[ m_vertex_to_edge_map[vtx][i] ][0] == m_edges[ m_vertex_to_edge_map[vtx][i] ][1] );
217
m_vertex_to_edge_map[vtx].clear(); //edges incident on vertices
221
// ---------------------------------------------------------
223
/// Update the number of vertices in the mesh.
225
// ---------------------------------------------------------
227
void NonDestructiveTriMesh::set_num_vertices( size_t num_vertices )
229
if ( num_vertices >= m_vertex_to_triangle_map.size() )
231
// expand the vertex data structures with empties
235
// reduce the number of vertices
237
assert( m_vertex_to_triangle_map.size() == m_vertex_to_edge_map.size() );
238
assert( m_vertex_to_triangle_map.size() == m_is_boundary_vertex.size() );
240
for ( size_t i = num_vertices; i < m_vertex_to_triangle_map.size(); ++i )
242
assert( vertex_is_deleted(i) );
243
assert( m_vertex_to_edge_map[i].size() == 0 );
244
assert( m_vertex_to_triangle_map[i].size() == 0 );
248
m_vertex_to_edge_map.resize( num_vertices );
249
m_vertex_to_triangle_map.resize( num_vertices );
250
m_is_boundary_vertex.resize( num_vertices );
256
// --------------------------------------------------------
258
/// Add an edge to the list. Return the index of the new edge.
260
// --------------------------------------------------------
262
size_t NonDestructiveTriMesh::nondestructive_add_edge(size_t vtx0, size_t vtx1)
265
size_t edge_index = m_edges.size();
266
m_edges.push_back(Vec2st(vtx0, vtx1));
268
m_edge_to_triangle_map.push_back( std::vector<size_t>( 0 ) );
270
m_is_boundary_edge.push_back( true );
272
m_vertex_to_edge_map[vtx0].push_back(edge_index);
273
m_vertex_to_edge_map[vtx1].push_back(edge_index);
279
// --------------------------------------------------------
281
/// Mark an edge as deleted, update connectivity
283
// --------------------------------------------------------
285
void NonDestructiveTriMesh::nondestructive_remove_edge( size_t edge_index )
289
std::vector<size_t>& vertex_to_edge_map = m_vertex_to_edge_map[ m_edges[edge_index][0] ];
290
for ( int i=0; i < (int)vertex_to_edge_map.size(); ++i)
292
if ( vertex_to_edge_map[i] == edge_index )
294
vertex_to_edge_map.erase( vertex_to_edge_map.begin() + i );
302
std::vector<size_t>& vertex_to_edge_map = m_vertex_to_edge_map[ m_edges[edge_index][1] ];
303
for ( int i=0; i < (int)vertex_to_edge_map.size(); ++i)
305
if ( vertex_to_edge_map[i] == edge_index )
307
vertex_to_edge_map.erase( vertex_to_edge_map.begin() + i );
313
m_edges[edge_index][0] = 0;
314
m_edges[edge_index][1] = 0;
319
// ---------------------------------------------------------
321
/// Determine if the given vertex is on a boundary edge and store in data structure.
323
// ---------------------------------------------------------
325
void NonDestructiveTriMesh::update_is_boundary_vertex( size_t v )
327
m_is_boundary_vertex[v] = false;
329
for ( size_t i = 0; i < m_vertex_to_edge_map[v].size(); ++i )
331
size_t edge_index = m_vertex_to_edge_map[v][i];
333
if ( m_is_boundary_edge[edge_index] )
335
m_is_boundary_vertex[v] = true;
343
// ---------------------------------------------------------
345
/// Ensure that all adjacent triangles have consistent orientation.
347
// ---------------------------------------------------------
349
void NonDestructiveTriMesh::verify_orientation( )
351
for ( size_t i = 0; i < m_edges.size(); ++i )
353
if ( m_edge_to_triangle_map[i].size() != 2 )
358
if ( edge_is_deleted(i) ) { continue; }
360
size_t a = m_edges[i][0];
361
size_t b = m_edges[i][1];
362
const Vec3st& tri0 = m_tris[ m_edge_to_triangle_map[i][0] ];
363
const Vec3st& tri1 = m_tris[ m_edge_to_triangle_map[i][1] ];
365
bool orient0 = oriented(a, b, tri0 );
366
bool orient1 = oriented(a, b, tri1 );
368
assert( orient0 != orient1 );
373
// --------------------------------------------------------
375
/// Find edge specified by two vertices. Return edges.size if the edge is not found.
377
// --------------------------------------------------------
379
size_t NonDestructiveTriMesh::get_edge_index(size_t vtx0, size_t vtx1) const
381
assert( vtx0 < m_vertex_to_edge_map.size() );
382
assert( vtx1 < m_vertex_to_edge_map.size() );
384
const std::vector<size_t>& edges0 = m_vertex_to_edge_map[vtx0];
385
const std::vector<size_t>& edges1 = m_vertex_to_edge_map[vtx1];
387
for(size_t e0 = 0; e0 < edges0.size(); e0++)
389
size_t edge0 = edges0[e0];
391
for(size_t e1 = 0; e1 < edges1.size(); e1++)
393
if( edge0 == edges1[e1] && m_edges[edge0][0] != m_edges[edge0][1] )
395
assert( ( m_edges[edge0][0] == vtx0 && m_edges[edge0][1] == vtx1 ) ||
396
( m_edges[edge0][1] == vtx0 && m_edges[edge0][0] == vtx1 ) );
403
return m_edges.size();
407
// --------------------------------------------------------
409
/// Find triangle specified by three vertices. Return triangles.size if the triangle is not found.
411
// --------------------------------------------------------
413
size_t NonDestructiveTriMesh::get_triangle_index( size_t vtx0, size_t vtx1, size_t vtx2 ) const
415
Vec3st verts( vtx0, vtx1, vtx2 );
417
const std::vector<size_t>& triangles0 = m_vertex_to_triangle_map[vtx0];
418
for ( size_t i = 0; i < triangles0.size(); ++i )
420
if ( triangle_has_these_verts( m_tris[triangles0[i]], verts ) )
422
return triangles0[i];
426
return m_tris.size();
432
// --------------------------------------------------------
434
/// Remove triangles which have been deleted by nondestructive_remove_triangle
436
// --------------------------------------------------------
438
void NonDestructiveTriMesh::clear_deleted_triangles( std::vector<Vec2st>* defragged_triangle_map )
441
std::vector<Vec3st> new_tris;
442
new_tris.reserve( m_tris.size() );
444
if ( defragged_triangle_map != NULL )
446
for ( size_t i = 0; i < m_tris.size(); ++i )
448
if ( !triangle_is_deleted(i) )
450
new_tris.push_back( m_tris[i] );
451
Vec2st map_entry(i, new_tris.size()-1);
452
defragged_triangle_map->push_back( map_entry );
458
for ( size_t i = 0; i < m_tris.size(); ++i )
460
if ( !triangle_is_deleted(i) )
462
new_tris.push_back( m_tris[i] );
467
replace_all_triangles( new_tris );
472
// --------------------------------------------------------
474
/// Remove auxiliary connectivity information
476
// --------------------------------------------------------
478
void NonDestructiveTriMesh::clear_connectivity()
481
m_vertex_to_edge_map.clear();
482
m_vertex_to_triangle_map.clear();
483
m_edge_to_triangle_map.clear();
484
m_triangle_to_edge_map.clear();
485
m_is_boundary_edge.clear();
486
m_is_boundary_vertex.clear();
491
// --------------------------------------------------------
493
/// Clear and rebuild connectivity information
495
// --------------------------------------------------------
497
void NonDestructiveTriMesh::update_connectivity( )
500
clear_connectivity();
503
for ( size_t i = 0; i < m_tris.size(); ++i )
505
nv = max( nv, m_tris[i][0] );
506
nv = max( nv, m_tris[i][1] );
507
nv = max( nv, m_tris[i][2] );
511
m_vertex_to_triangle_map.resize(nv);
512
m_vertex_to_edge_map.resize(nv);
513
m_triangle_to_edge_map.resize(m_tris.size());
515
for(size_t i = 0; i < m_tris.size(); i++)
517
Vec3st& t = m_tris[i];
526
for(unsigned int j = 0; j < 3; j++)
527
m_vertex_to_triangle_map[t[j]].push_back(i);
529
Vec3st& te = m_triangle_to_edge_map[i];
531
for(int j = 0; j < 3; j++)
534
size_t vtx1 = t[ i_plus_one_mod_three[j] ];
536
size_t e = get_edge_index(vtx0, vtx1);
538
if(e == m_edges.size())
540
e = nondestructive_add_edge(vtx0, vtx1);
544
m_edge_to_triangle_map[e].push_back(i);
549
// find boundary edges and vertices
550
m_is_boundary_edge.resize( m_edges.size() );
551
m_is_boundary_vertex.resize( nv, false );
553
for ( size_t e = 0; e < m_edge_to_triangle_map.size(); ++e )
555
if ( m_edge_to_triangle_map[e].size() % 2 == 0 )
557
m_is_boundary_edge[e] = false;
561
m_is_boundary_edge[e] = true;
562
m_is_boundary_vertex[ m_edges[e][0] ] = true;
563
m_is_boundary_vertex[ m_edges[e][1] ] = true;
570
// --------------------------------------------------------
572
/// Check the consistency of auxiliary data structures
574
// --------------------------------------------------------
576
void NonDestructiveTriMesh::test_connectivity() const
581
assert( m_is_boundary_edge.size() == m_edges.size() );
582
assert( m_edge_to_triangle_map.size() == m_edges.size() );
584
assert( m_is_boundary_vertex.size() == m_vertex_to_edge_map.size() );
585
assert( m_is_boundary_vertex.size() == m_vertex_to_triangle_map.size() );
587
assert( m_triangle_to_edge_map.size() == m_tris.size() );
589
// m_is_boundary_edge
591
for ( size_t i = 0; i < m_is_boundary_edge.size(); ++i )
593
if ( edge_is_deleted(i) ) { continue; }
594
if ( m_is_boundary_edge[i] )
596
assert( m_edge_to_triangle_map[i].size() == 1 );
600
assert( m_edge_to_triangle_map[i].size() > 1 );
604
// m_is_boundary_vertex
606
for ( size_t i = 0; i < m_is_boundary_vertex.size(); ++i )
608
if ( vertex_is_deleted(i) ) { continue; }
610
bool found_incident_boundary_edge = false;
611
for ( size_t j = 0; j < m_vertex_to_edge_map[i].size(); ++j )
613
size_t inc_edge = m_vertex_to_edge_map[i][j];
614
if ( m_is_boundary_edge[inc_edge] )
616
found_incident_boundary_edge = true;
619
assert( m_is_boundary_vertex[i] == found_incident_boundary_edge );
622
// m_vertex_to_edge_map
624
for ( size_t i = 0; i < m_vertex_to_edge_map.size(); ++i )
626
if ( vertex_is_deleted(i) ) { continue; }
627
for ( size_t j = 0; j < m_vertex_to_edge_map[i].size(); ++j )
629
size_t inc_edge = m_vertex_to_edge_map[i][j];
630
assert( !edge_is_deleted( inc_edge ) );
631
assert( m_edges[inc_edge][0] == i || m_edges[inc_edge][1] == i );
636
// m_vertex_to_triangle_map
638
for ( size_t i = 0; i < m_vertex_to_triangle_map.size(); ++i )
640
if ( vertex_is_deleted(i) ) { continue; }
641
for ( size_t j = 0; j < m_vertex_to_triangle_map[i].size(); ++j )
643
size_t inc_triangle = m_vertex_to_triangle_map[i][j];
644
assert( m_tris[inc_triangle][0] == i || m_tris[inc_triangle][1] == i || m_tris[inc_triangle][2] == i );
648
// m_edge_to_triangle_map
650
for ( size_t i = 0; i < m_edge_to_triangle_map.size(); ++i )
652
if ( edge_is_deleted(i) ) { continue; }
653
for ( size_t j = 0; j < m_edge_to_triangle_map[i].size(); ++j )
655
size_t triangle_index = m_edge_to_triangle_map[i][j];
656
size_t num_common_verts = 0;
657
if ( m_tris[triangle_index][0] == m_edges[i][0] || m_tris[triangle_index][0] == m_edges[i][1] )
661
if ( m_tris[triangle_index][1] == m_edges[i][0] || m_tris[triangle_index][1] == m_edges[i][1] )
665
if ( m_tris[triangle_index][2] == m_edges[i][0] || m_tris[triangle_index][2] == m_edges[i][1] )
669
assert( num_common_verts == 2 );
673
// m_triangle_to_edge_map
675
for ( size_t i = 0; i < m_triangle_to_edge_map.size(); ++i )
677
if ( triangle_is_deleted(i) ) { continue; }
679
const Vec3st& inc_edges = m_triangle_to_edge_map[i];
681
const Vec2st& edge0 = m_edges[inc_edges[0]];
682
const Vec2st& edge1 = m_edges[inc_edges[1]];
683
const Vec2st& edge2 = m_edges[inc_edges[2]];
685
assert( !edge_is_deleted( inc_edges[0] ) );
686
assert( !edge_is_deleted( inc_edges[1] ) );
687
assert( !edge_is_deleted( inc_edges[2] ) );
689
assert( edge0[0] != edge0[1] );
690
assert( edge1[0] != edge1[1] );
691
assert( edge2[0] != edge2[1] );
693
assert( edge0[0] == m_tris[i][0] || edge0[0] == m_tris[i][1] || edge0[0] == m_tris[i][2] );
694
assert( edge0[1] == m_tris[i][0] || edge0[1] == m_tris[i][1] || edge0[1] == m_tris[i][2] );
695
assert( edge1[0] == m_tris[i][0] || edge1[0] == m_tris[i][1] || edge1[0] == m_tris[i][2] );
696
assert( edge1[1] == m_tris[i][0] || edge1[1] == m_tris[i][1] || edge1[1] == m_tris[i][2] );
697
assert( edge2[0] == m_tris[i][0] || edge2[0] == m_tris[i][1] || edge2[0] == m_tris[i][2] );
698
assert( edge2[1] == m_tris[i][0] || edge2[1] == m_tris[i][1] || edge2[1] == m_tris[i][2] );