double NormalDriver::compute_l1_error( const SurfTrack& surf ) { double total_error = 0.0; double total_area = 0.0; for ( unsigned int i = 0; i < surf.get_num_vertices(); ++i ) { if ( surf.m_mesh.m_vertex_to_triangle_map[i].empty() ) { // ignore deleted vertices continue; } double dist = fabs( signed_distance_entropy( surf.get_position(i), sphere_a_centre, sphere_b_centre, max_radius, interior_radius ) ); double area = 0; for ( unsigned int j = 0; j < surf.m_mesh.m_vertex_to_triangle_map[i].size(); ++j ) { area += surf.get_triangle_area( surf.m_mesh.m_vertex_to_triangle_map[i][j] ); } area /= 3; total_error += dist * area; total_area += area; } total_error /= total_area; return total_error; }
void MidpointScheme::generate_new_midpoint( size_t edge_index, const SurfTrack& surface, Vec3d& new_point ) { const NonDestructiveTriMesh& mesh = surface.m_mesh; const std::vector<Vec3d>& positions = surface.get_positions(); size_t p1_index = mesh.m_edges[edge_index][0]; size_t p2_index = mesh.m_edges[edge_index][1]; new_point = 0.5 * ( positions[ p1_index ] + positions[ p2_index ] ); }
double NormalDriver::compute_inf_error( const SurfTrack& surf ) { double max_error = -1.0; for ( unsigned int i = 0; i < surf.get_num_vertices(); ++i ) { if ( surf.m_mesh.m_vertex_to_triangle_map[i].empty() ) { // ignore deleted vertices continue; } double dist = signed_distance_entropy( surf.get_position(i), sphere_a_centre, sphere_b_centre, max_radius, interior_radius ); max_error = max( max_error, fabs(dist) ); } return max_error; }
void ButterflyScheme::generate_new_midpoint( size_t edge_index, const SurfTrack& surface, Vec3d& new_point ) { const NonDestructiveTriMesh& mesh = surface.m_mesh; const std::vector<Vec3d>& positions = surface.get_positions(); size_t p1_index = mesh.m_edges[edge_index][0]; size_t p2_index = mesh.m_edges[edge_index][1]; size_t tri0 = mesh.m_edge_to_triangle_map[edge_index][0]; size_t tri1 = mesh.m_edge_to_triangle_map[edge_index][1]; size_t p3_index = mesh.get_third_vertex( mesh.m_edges[edge_index][0], mesh.m_edges[edge_index][1], mesh.get_triangle(tri0) ); size_t p4_index = mesh.get_third_vertex( mesh.m_edges[edge_index][0], mesh.m_edges[edge_index][1], mesh.get_triangle(tri1) ); size_t adj_edges[4] = { mesh.get_edge_index( p1_index, p3_index ), mesh.get_edge_index( p2_index, p3_index ), mesh.get_edge_index( p1_index, p4_index ), mesh.get_edge_index( p2_index, p4_index ) }; size_t q_indices[4]; for ( size_t i = 0; i < 4; ++i ) { const std::vector<size_t>& adj_tris = mesh.m_edge_to_triangle_map[ adj_edges[i] ]; if ( adj_tris.size() != 2 ) { // abort new_point = 0.5 * ( positions[ p1_index ] + positions[ p2_index ] ); return; } if ( adj_tris[0] == tri0 || adj_tris[0] == tri1 ) { q_indices[i] = mesh.get_third_vertex( mesh.m_edges[ adj_edges[i] ][0], mesh.m_edges[ adj_edges[i] ][1], mesh.get_triangle( adj_tris[1] ) ); } else { q_indices[i] = mesh.get_third_vertex( mesh.m_edges[ adj_edges[i] ][0], mesh.m_edges[ adj_edges[i] ][1], mesh.get_triangle( adj_tris[0] ) ); } } new_point = 8. * positions[ p1_index ] + 8. * positions[ p2_index ] + 2. * positions[ p3_index ] + 2. * positions[ p4_index ] - positions[ q_indices[0] ] - positions[ q_indices[1] ] - positions[ q_indices[2] ] - positions[ q_indices[3] ]; new_point *= 0.0625; }
void NormalDriver::set_predicted_vertex_positions( const SurfTrack& surf, std::vector<Vec3d>& predicted_positions, double current_t, double& adaptive_dt ) { std::vector<Vec3d> displacements( surf.get_num_vertices(), Vec3d(0,0,0) ); std::vector<Vec3d> velocities( surf.get_num_vertices(), Vec3d(0,0,0) ); for ( unsigned int i = 0; i < surf.get_num_vertices(); ++i ) { if ( surf.m_mesh.m_vertex_to_triangle_map[i].empty() ) { displacements[i] = Vec3d(0,0,0); continue; } Vec3d normal(0,0,0); double sum_areas = 0.0; for ( unsigned int j = 0; j < surf.m_mesh.m_vertex_to_triangle_map[i].size(); ++j ) { double area = surf.get_triangle_area( surf.m_mesh.m_vertex_to_triangle_map[i][j] ); normal += surf.get_triangle_normal( surf.m_mesh.m_vertex_to_triangle_map[i][j] ) * area; sum_areas += area; } //normal /= sum_areas; normal /= mag(normal); double switch_speed = (current_t >= 1.0) ? -speed : speed; velocities[i] = switch_speed * normal; displacements[i] = adaptive_dt * velocities[i]; } double capped_dt = MeshSmoother::compute_max_timestep_quadratic_solve( surf.m_mesh.get_triangles(), surf.get_positions(), displacements, false ); adaptive_dt = min( adaptive_dt, capped_dt ); for ( unsigned int i = 0; i < surf.get_num_vertices(); ++i ) { predicted_positions[i] = surf.get_position(i) + adaptive_dt * velocities[i]; } }
void QuadraticErrorMinScheme::generate_new_midpoint( size_t edge_index, const SurfTrack& surface, Vec3d& new_point ) { const NonDestructiveTriMesh& mesh = surface.m_mesh; const std::vector<Vec3d>& positions = surface.get_positions(); size_t v0 = mesh.m_edges[edge_index][0]; size_t v1 = mesh.m_edges[edge_index][1]; Mat33d Q; zero(Q); Vec3d b; zero(b); std::vector<size_t> triangles_counted; Mat<1,1,double> constant_dist; constant_dist.a[0] = 0; for ( size_t i = 0; i < mesh.m_vertex_to_triangle_map[v0].size(); ++i ) { size_t t = mesh.m_vertex_to_triangle_map[v0][i]; const Vec3d& plane_normal = surface.get_triangle_normal( t ); Q += outer( plane_normal, plane_normal ); b += dot( positions[v0], plane_normal ) * plane_normal; constant_dist.a[0] += dot( plane_normal, positions[v0] ) * dot( plane_normal, positions[v0] ); triangles_counted.push_back(t); } for ( size_t i = 0; i < mesh.m_vertex_to_triangle_map[v1].size(); ++i ) { size_t t = mesh.m_vertex_to_triangle_map[v1][i]; bool already_counted = false; for ( size_t j = 0; j < triangles_counted.size(); ++j ) { if ( t == triangles_counted[j] ) { already_counted = true; } } if ( !already_counted ) { const Vec3d& plane_normal = surface.get_triangle_normal( t ); Q += outer( plane_normal, plane_normal ); b += dot( positions[v1], plane_normal ) * plane_normal; constant_dist.a[0] += dot( plane_normal, positions[v1] ) * dot( plane_normal, positions[v1] ); } } // Compute normal direction Vec3d normal = 0.5 * (surface.get_vertex_normal(v0) + surface.get_vertex_normal(v1)); normalize(normal); Mat<3,1,double> n; n(0,0) = normal[0]; n(1,0) = normal[1]; n(2,0) = normal[2]; // Compute edge midpoint Vec3d midpoint = 0.5 * (positions[v0] + positions[v1]); Mat<3,1,double> m; m(0,0) = midpoint[0]; m(1,0) = midpoint[1]; m(2,0) = midpoint[2]; Mat<3,1,double> d; d(0,0) = b[0]; d(1,0) = b[1]; d(2,0) = b[2]; double LHS = 2.0 * (n.transpose()*Q*n).a[0]; // result of multiplication is Mat<1,1,double>, hence the .a[0] double RHS = ( 2.0 * (n.transpose()*d) - (n.transpose()*Q*m) - (m.transpose()*Q*n) ).a[0]; double a; if ( fabs(LHS) > 1e-10 ) { a = RHS / LHS; } else { a = 0.0; } Mat<3,1,double> v = m + (a * n); double v_error = (v.transpose() * Q * v - 2.0 * (v.transpose() * d) + constant_dist).a[0]; double m_error = (m.transpose() * Q * m - 2.0 * (m.transpose() * d) + constant_dist).a[0]; //assert( v_error < m_error + 1e-8 ); if ( surface.m_verbose ) { std::cout << "a: " << a << std::endl; std::cout << "error at v: " << v_error << std::endl; std::cout << "error at midpoint: " << m_error << std::endl; } new_point = Vec3d( v.a[0], v.a[1], v.a[2] ); }
void FaceOffDriver::set_predicted_vertex_positions( const SurfTrack& surf, std::vector<Vec3d>& new_positions, double current_t, double& adaptive_dt ) { const NonDestructiveTriMesh& mesh = surf.m_mesh; std::vector<double> triangle_areas; triangle_areas.reserve(mesh.num_triangles()); std::vector<Vec3d> triangle_normals; triangle_normals.reserve(mesh.num_triangles()); std::vector<Vec3d> triangle_centroids; triangle_centroids.reserve(mesh.num_triangles()); std::vector<double> triangle_plane_distances; triangle_plane_distances.reserve(mesh.num_triangles()); const std::vector<Vec3st>& tris = mesh.get_triangles(); for ( size_t i = 0; i < tris.size(); ++i ) { if ( tris[i][0] == tris[i][1] ) { triangle_areas.push_back( 0 ); triangle_normals.push_back( Vec3d(0,0,0) ); triangle_centroids.push_back( Vec3d(0,0,0) ); } else { triangle_areas.push_back( surf.get_triangle_area( i ) ); triangle_normals.push_back( surf.get_triangle_normal( i ) ); triangle_centroids.push_back( (surf.get_position(tris[i][0]) + surf.get_position(tris[i][1]) + surf.get_position(tris[i][2])) / 3 ); } double switch_speed = (current_t >= 1.0) ? -speed : speed; triangle_plane_distances.push_back( adaptive_dt * switch_speed ); } std::vector<Vec3d> displacements; displacements.resize( surf.get_num_vertices() ); // // Null space smoothing // { for ( size_t i = 0; i < surf.get_num_vertices(); ++i ) { const MeshSmoother& smoother = surf.m_smoother; smoother.null_space_smooth_vertex( i, triangle_areas, triangle_normals, triangle_centroids, displacements[i] ); } } // // Primary space displacement // for ( size_t p = 0; p < surf.get_num_vertices(); ++p ) { Vec3d normal_dispacement; intersection_point( triangle_normals, triangle_plane_distances, triangle_areas, mesh.m_vertex_to_triangle_map[p], normal_dispacement ); displacements[p] += normal_dispacement; // // Entropy solution // if ( surf.m_mesh.m_vertex_to_triangle_map[p].empty() ) { continue; } double sum_mu_l = 0, sum_mu = 0; const std::vector<size_t>& incident_triangles = mesh.m_vertex_to_triangle_map[p]; for ( size_t j = 0; j < incident_triangles.size(); ++j ) { size_t triangle_index = incident_triangles[j]; const Vec3st& tri = surf.m_mesh.get_triangle( triangle_index ); Vec3d edge_vector; if ( tri[0] == p ) { edge_vector = surf.get_position(tri[1]) - surf.get_position(tri[2]); } else if ( tri[1] == p ) { edge_vector = surf.get_position(tri[2]) - surf.get_position(tri[0]); } else { edge_vector = surf.get_position(tri[0]) - surf.get_position(tri[1]); } Vec3d s = cross( triangle_normals[triangle_index], edge_vector ); // orthogonal to normal and edge oposite vertex bool contracting = dot( s, displacements[p] ) >= 0.0; double cos_theta = dot( triangle_normals[triangle_index], normal_dispacement ) / mag(normal_dispacement); double mu = triangle_areas[triangle_index]; if ( contracting ) { mu *= cos_theta * cos_theta; } double li = fabs( triangle_plane_distances[triangle_index] ); if ( contracting ) { li /= fabs( cos_theta ); } sum_mu_l += mu * li; sum_mu += mu; } double length = sum_mu_l / sum_mu; displacements[p] += length * normal_dispacement / mag(normal_dispacement); } double beta = MeshSmoother::compute_max_timestep_quadratic_solve( surf.m_mesh.get_triangles(), surf.get_positions(), displacements, false ); adaptive_dt *= beta; for(size_t i = 0; i < surf.get_num_vertices(); i++) { new_positions[i] = surf.get_position(i) + beta * displacements[i]; } }