void SurfTrack::trim_non_manifold( std::vector<size_t>& triangle_indices ) { // If we're not allowing non-manifold, assert we don't have any if ( false == m_allow_non_manifold ) { // check for edges incident on more than 2 triangles for ( size_t i = 0; i < m_mesh.m_edge_to_triangle_map.size(); ++i ) { if ( m_mesh.edge_is_deleted(i) ) { continue; } assert( m_mesh.m_edge_to_triangle_map[i].size() == 1 || m_mesh.m_edge_to_triangle_map[i].size() == 2 ); } triangle_indices.clear(); return; } for ( size_t j = 0; j < triangle_indices.size(); ++j ) { size_t i = triangle_indices[j]; const Vec3st& current_triangle = m_mesh.get_triangle(i); if ( (current_triangle[0] == 0) && (current_triangle[1] == 0) && (current_triangle[2] == 0) ) { continue; } // // look for triangles with repeated vertices // if ( (current_triangle[0] == current_triangle[1]) || (current_triangle[1] == current_triangle[2]) || (current_triangle[2] == current_triangle[0]) ) { if ( m_verbose ) { std::cout << "deleting degenerate triangle " << i << ": " << current_triangle << std::endl; } // delete it remove_triangle( i ); continue; } // // look for flaps // const Vec3st& tri_edges = m_mesh.m_triangle_to_edge_map[i]; bool flap_found = false; for ( unsigned int e = 0; e < 3 && flap_found == false; ++e ) { const std::vector<size_t>& edge_tris = m_mesh.m_edge_to_triangle_map[ tri_edges[e] ]; for ( size_t t = 0; t < edge_tris.size(); ++t ) { if ( edge_tris[t] == i ) { continue; } size_t other_triangle_index = edge_tris[t]; const Vec3st& other_triangle = m_mesh.get_triangle( other_triangle_index ); if ( (other_triangle[0] == other_triangle[1]) || (other_triangle[1] == other_triangle[2]) || (other_triangle[2] == other_triangle[0]) ) { continue; } if ( ((current_triangle[0] == other_triangle[0]) || (current_triangle[0] == other_triangle[1]) || (current_triangle[0] == other_triangle[2])) && ((current_triangle[1] == other_triangle[0]) || (current_triangle[1] == other_triangle[1]) || (current_triangle[1] == other_triangle[2])) && ((current_triangle[2] == other_triangle[0]) || (current_triangle[2] == other_triangle[1]) || (current_triangle[2] == other_triangle[2])) ) { if ( false == m_allow_topology_changes ) { std::cout << "flap found while topology changes disallowed" << std::endl; std::cout << current_triangle << std::endl; std::cout << other_triangle << std::endl; assert(0); } size_t common_edge = tri_edges[e]; if ( m_mesh.oriented( m_mesh.m_edges[common_edge][0], m_mesh.m_edges[common_edge][1], current_triangle ) == m_mesh.oriented( m_mesh.m_edges[common_edge][0], m_mesh.m_edges[common_edge][1], other_triangle ) ) { continue; } // the dangling vertex will be safely removed by the vertex cleanup function // delete the triangle if ( m_verbose ) { std::cout << "flap: triangles << " << i << " [" << current_triangle << "] and " << edge_tris[t] << " [" << other_triangle << "]" << std::endl; } remove_triangle( i ); // delete its opposite remove_triangle( other_triangle_index ); flap_found = true; break; } } } } triangle_indices.clear(); }
void SurfTrack::defrag_mesh( ) { std::vector<Vec2st> old_edges = m_mesh.m_edges; PostDefragInfo info; info.m_defragged_vertex_map.clear(); // // First clear deleted vertices from the data stuctures // // do a quick pass through to see if any vertices have been deleted bool any_deleted = false; for ( size_t i = 0; i < get_num_vertices(); ++i ) { if ( m_mesh.vertex_is_deleted(i) ) { any_deleted = true; break; } } if ( !any_deleted ) { for ( size_t i = 0; i < get_num_vertices(); ++i ) { info.m_defragged_vertex_map.push_back( Vec2st(i,i) ); } } else { // Note: We could rebuild the mesh from scratch, rather than adding/removing // triangles, however this function is not a major computational bottleneck. size_t j = 0; std::vector<Vec3st> new_tris = m_mesh.get_triangles(); for ( size_t i = 0; i < get_num_vertices(); ++i ) { if ( !m_mesh.vertex_is_deleted(i) ) { pm_positions[j] = pm_positions[i]; pm_newpositions[j] = pm_newpositions[i]; m_masses[j] = m_masses[i]; info.m_defragged_vertex_map.push_back( Vec2st(i,j) ); // Now rewire the triangles containting vertex i // copy this, since we'll be changing the original as we go std::vector<size_t> inc_tris = m_mesh.m_vertex_to_triangle_map[i]; for ( size_t t = 0; t < inc_tris.size(); ++t ) { Vec3st triangle = m_mesh.get_triangle( inc_tris[t] ); assert( triangle[0] == i || triangle[1] == i || triangle[2] == i ); if ( triangle[0] == i ) { triangle[0] = j; } if ( triangle[1] == i ) { triangle[1] = j; } if ( triangle[2] == i ) { triangle[2] = j; } remove_triangle(inc_tris[t]); // mark the triangle deleted add_triangle(triangle); // add the updated triangle } ++j; } } pm_positions.resize(j); pm_newpositions.resize(j); m_masses.resize(j); } // // Now clear deleted triangles from the mesh // m_mesh.set_num_vertices( get_num_vertices() ); m_mesh.clear_deleted_triangles( &info.m_defragged_triangle_map ); // // Update data carried on the edges // info.m_defragged_edge_map.clear(); info.m_defragged_edge_map.resize( old_edges.size(), UNINITIALIZED_SIZE_T ); // First update the set of edges to point to new vertex indices for ( size_t i = 0; i < old_edges.size(); ++i ) { for ( int v = 0; v < 2; ++v ) { const size_t old_v = old_edges[i][v]; size_t new_v = old_v; for ( size_t j = 0; j < info.m_defragged_vertex_map.size(); ++j ) { if ( info.m_defragged_vertex_map[j][0] == old_v ) { new_v = info.m_defragged_vertex_map[j][1]; assert( !m_mesh.vertex_is_deleted(new_v) ); break; } } old_edges[i][v] = new_v; } } // Now use this modified set of edges to find where the edge data maps to for ( unsigned int i = 0; i < old_edges.size(); ++i ) { if ( old_edges[i][0] == old_edges[i][1] ) { continue; } size_t new_edge_index = m_mesh.get_edge_index( old_edges[i][0], old_edges[i][1] ); // This edge has disappeared from the mesh. This can occur when trimming non-manifold flaps. if ( new_edge_index == m_mesh.m_edges.size() ) { continue; } info.m_defragged_edge_map[i] = new_edge_index; assert( new_edge_index < m_mesh.m_edges.size() ); // If the internal storage of the edge flipped, flip it back to original if ( old_edges[i][0] != m_mesh.m_edges[new_edge_index][0] ) { assert( old_edges[i][1] == m_mesh.m_edges[new_edge_index][0] ); assert( old_edges[i][0] == m_mesh.m_edges[new_edge_index][1] ); swap( m_mesh.m_edges[new_edge_index][0], m_mesh.m_edges[new_edge_index][1] ); assert( old_edges[i][0] == m_mesh.m_edges[new_edge_index][0] ); assert( old_edges[i][1] == m_mesh.m_edges[new_edge_index][1] ); } } for ( size_t i = 0; i < m_observers.size(); ++i ) { m_observers[i]->operationOccurred(*this, info); } if ( m_collision_safety ) { rebuild_continuous_broad_phase(); } }
void SurfTrack::defrag_mesh( ) { // // First clear deleted vertices from the data stuctures // double start_time = get_time_in_seconds(); // do a quick pass through to see if any vertices have been deleted bool any_deleted = false; for ( size_t i = 0; i < get_num_vertices(); ++i ) { if ( m_mesh.vertex_is_deleted(i) ) { any_deleted = true; break; } } if ( !any_deleted ) { for ( size_t i = 0; i < get_num_vertices(); ++i ) { m_defragged_vertex_map.push_back( Vec2st(i,i) ); } double end_time = get_time_in_seconds(); g_stats.add_to_double( "total_clear_deleted_vertices_time", end_time - start_time ); } else { // Note: We could rebuild the mesh from scratch, rather than adding/removing // triangles, however this function is not a major computational bottleneck. size_t j = 0; std::vector<Vec3st> new_tris = m_mesh.get_triangles(); for ( size_t i = 0; i < get_num_vertices(); ++i ) { if ( !m_mesh.vertex_is_deleted(i) ) { pm_positions[j] = pm_positions[i]; pm_newpositions[j] = pm_newpositions[i]; m_masses[j] = m_masses[i]; m_defragged_vertex_map.push_back( Vec2st(i,j) ); // Now rewire the triangles containting vertex i // copy this, since we'll be changing the original as we go std::vector<size_t> inc_tris = m_mesh.m_vertex_to_triangle_map[i]; for ( size_t t = 0; t < inc_tris.size(); ++t ) { Vec3st triangle = m_mesh.get_triangle( inc_tris[t] ); assert( triangle[0] == i || triangle[1] == i || triangle[2] == i ); if ( triangle[0] == i ) { triangle[0] = j; } if ( triangle[1] == i ) { triangle[1] = j; } if ( triangle[2] == i ) { triangle[2] = j; } remove_triangle(inc_tris[t]); // mark the triangle deleted add_triangle(triangle); // add the updated triangle } ++j; } } pm_positions.resize(j); pm_newpositions.resize(j); m_masses.resize(j); } double end_time = get_time_in_seconds(); g_stats.add_to_double( "total_clear_deleted_vertices_time", end_time - start_time ); // // Now clear deleted triangles from the mesh // m_mesh.set_num_vertices( get_num_vertices() ); m_mesh.clear_deleted_triangles( &m_defragged_triangle_map ); if ( m_collision_safety ) { rebuild_continuous_broad_phase(); } }
void OutlineTriangulator_Impl::triangulate() { // Order vertices: std::vector<OutlineTriangulator_Vertex *> vertices; create_ordered_vertex_list(vertices); // 1. Create initial triangulation: DelauneyTriangulator delauney; std::vector<OutlineTriangulator_Vertex *>::size_type index_vertices, num_vertices; num_vertices = vertices.size(); for (index_vertices = 0; index_vertices < num_vertices; index_vertices++) { vertices[index_vertices]->num_triangles = 0; vertices[index_vertices]->extra = 0; vertices[index_vertices]->triangles = nullptr; delauney.add_vertex( vertices[index_vertices]->x, vertices[index_vertices]->y, vertices[index_vertices]); } delauney.generate(); // 2. Link triangles to vertices: const std::vector<DelauneyTriangulator_Triangle> &triangles = delauney.get_triangles(); std::vector<DelauneyTriangulator_Triangle>::size_type index_triangles, num_triangles; num_triangles = triangles.size(); for (index_triangles = 0; index_triangles < num_triangles; index_triangles++) { OutlineTriangulator_Vertex *data_A = (OutlineTriangulator_Vertex *) triangles[index_triangles].vertex_A->data; OutlineTriangulator_Vertex *data_B = (OutlineTriangulator_Vertex *) triangles[index_triangles].vertex_B->data; OutlineTriangulator_Vertex *data_C = (OutlineTriangulator_Vertex *) triangles[index_triangles].vertex_C->data; data_A->num_triangles++; data_B->num_triangles++; data_C->num_triangles++; } auto links = new DelauneyTriangulator_Triangle const *[num_triangles]; int pos = 0; for (index_vertices = 0; index_vertices < num_vertices; index_vertices++) { vertices[index_vertices]->data = links+pos; pos += vertices[index_vertices]->num_triangles; vertices[index_vertices]->num_triangles = 0; } for (index_triangles = 0; index_triangles < num_triangles; index_triangles++) { OutlineTriangulator_Vertex *data_A = (OutlineTriangulator_Vertex *) triangles[index_triangles].vertex_A->data; OutlineTriangulator_Vertex *data_B = (OutlineTriangulator_Vertex *) triangles[index_triangles].vertex_B->data; OutlineTriangulator_Vertex *data_C = (OutlineTriangulator_Vertex *) triangles[index_triangles].vertex_C->data; data_A->triangles[data_A->num_triangles++] = &triangles[index_triangles]; data_B->triangles[data_B->num_triangles++] = &triangles[index_triangles]; data_C->triangles[data_C->num_triangles++] = &triangles[index_triangles]; } // 3. Walk contours. Check if any triangles intersect with each line segment. // 3a. Add each triangle's point that intersect to vertex buffer. // 3b. Divide vertices into two lists, one for left and one for right side of line segment. // 3c. Delauney triangulate each point list. // 3d. Update links to include new triangles. // 3e. Add the resulting triangles to triangles list. std::list<DelauneyTriangulator_Triangle const *> final_triangles; for (index_triangles = 0; index_triangles < num_triangles; index_triangles++) final_triangles.push_back(&triangles[index_triangles]); std::vector<DelauneyTriangulator_Triangle const **> added_links; std::vector<DelauneyTriangulator> extra_triangulations; std::vector<OutlineTriangulator_Polygon>::size_type index_polygons, num_polygons; num_polygons = polygons.size(); for (index_polygons = 0; index_polygons < num_polygons; index_polygons++) { OutlineTriangulator_Polygon &cur_poly = polygons[index_polygons]; std::vector<OutlineTriangulator_Contour>::size_type index_contours, num_contours; num_contours = cur_poly.contours.size(); for (index_contours = 0; index_contours < num_contours; index_contours++) { OutlineTriangulator_Contour &cur_contour = cur_poly.contours[index_contours]; std::vector<OutlineTriangulator_Vertex>::size_type index_vertices, num_vertices; num_vertices = cur_contour.vertices.size(); for (index_vertices = 1; index_vertices < num_vertices; index_vertices++) { OutlineTriangulator_Vertex *vertex_1 = &cur_contour.vertices[index_vertices-1]; OutlineTriangulator_Vertex *vertex_2 = &cur_contour.vertices[index_vertices]; OutlineTriangulator_Collision collision = find_colliding_triangles(vertex_1, vertex_2); if (collision.triangles.empty()) continue; std::vector<OutlineTriangulator_Vertex *>::size_type index_points, num_points; // Triangulate left and right sides: DelauneyTriangulator delauney_first; num_points = collision.first.size(); for (index_points = 0; index_points < num_points; index_points++) { delauney.add_vertex( collision.first[index_points]->x, collision.first[index_points]->y, collision.first[index_points]); } delauney_first.generate(); DelauneyTriangulator delauney_second; num_points = collision.second.size(); for (index_points = 0; index_points < num_points; index_points++) { delauney.add_vertex( collision.second[index_points]->x, collision.second[index_points]->y, collision.second[index_points]); } delauney_second.generate(); extra_triangulations.push_back(delauney_first); extra_triangulations.push_back(delauney_second); // Remove old triangles: std::vector<DelauneyTriangulator_Triangle *>::size_type index_old_triangles, size_old_triangles; size_old_triangles = collision.triangles.size(); for (index_old_triangles = 0; index_old_triangles < size_old_triangles; index_old_triangles++) { remove_triangle(collision.triangles[index_old_triangles]); final_triangles.remove(collision.triangles[index_old_triangles]); } // Add new triangles: DelauneyTriangulator_Triangle const **new_links = add_triangles(delauney_first, delauney_second); added_links.push_back(new_links); const std::vector<DelauneyTriangulator_Triangle> &triangles1 = delauney_first.get_triangles(); const std::vector<DelauneyTriangulator_Triangle> &triangles2 = delauney_second.get_triangles(); std::vector<DelauneyTriangulator_Triangle>::size_type index_triangles, num_triangles1, num_triangles2; num_triangles1 = triangles1.size(); num_triangles2 = triangles2.size(); for (index_triangles = 0; index_triangles < num_triangles1; index_triangles++) final_triangles.push_back(&triangles1[index_triangles]); for (index_triangles = 0; index_triangles < num_triangles2; index_triangles++) final_triangles.push_back(&triangles2[index_triangles]); } } } // 4. Remove outside and hole triangles. // 5. Clean up: delete[] links; std::vector<DelauneyTriangulator_Triangle const **>::size_type index_added_links, size_added_links; size_added_links = added_links.size(); for (index_added_links = 0; index_added_links < size_added_links; index_added_links++) { delete[] added_links[index_added_links]; } // 6. Generate final list: }