// Fix some edge crossings by warping vertices if it's admissible static void warp_vertices(const float threshold, TetMesh& mesh, std::vector<float>& vphi) { assert(threshold>=0 && threshold<=0.5); std::vector<float> warp(mesh.vSize(), FLT_MAX); std::vector<int> warp_nbr(mesh.vSize(), -1); std::vector<Vec3f> d(mesh.vSize(), Vec3f(0,0,0)); // it's wasteful to iterate through tets just to look at edges; oh well for (size_t t=0; t<mesh.tSize(); ++t) { for (int u=0; u<3; ++u) { int i = mesh.T(t)[u]; for (int v=u+1; v<4; ++v) { int j = mesh.T(t)[v]; if ((vphi[i]<0 && vphi[j]>0) || (vphi[i]>0 && vphi[j]<0)) { float alpha = vphi[i]/(vphi[i]-vphi[j]); if (alpha < threshold) { // warp i? float d2 = alpha*dist2(mesh.V(i), mesh.V(j)); if (d2 < warp[i]) { warp[i] = d2; warp_nbr[i] = j; d[i] = alpha*(mesh.V(j)-mesh.V(i)); } } else if (alpha > 1-threshold) { // warp j? float d2 = (1-alpha)*dist2(mesh.V(i), mesh.V(j)); if (d2 < warp[j]) { warp[j] = d2; warp_nbr[j] = i; d[j] = (1-alpha)*(mesh.V(i)-mesh.V(j)); } } } } } } // do the warps (also wasteful to loop over all vertices; oh well) for (size_t i=0; i<mesh.vSize(); ++i) if(warp_nbr[i]>=0) { mesh.V(i) += d[i]; vphi[i] = 0; } }
// cut a chunk of the lattice out to roughly match the shape static void cut_lattice(const SDF& sdf, TetMesh& mesh, std::vector<float>& vphi) // phi evaluated at vertices { std::map<Vec3i,int> lattice_map; // loop over tiles that overlap bounding box int i, j, k; for (k=0; k<sdf.phi.nk; k+=4) for (j=0; j<sdf.phi.nj; j+=4) for (i=0; i<sdf.phi.ni; i+=4) { for (int t=0; t<num_lattice_tets; ++t) { // check this tet is entirely inside the grid & has a negative phi bool good_tet = true; bool negative_phi = false; for (int u=0; u<4; ++u) { int a = lattice_node[lattice_tet[t][u]][0]+i; if (a >= sdf.phi.ni) { good_tet=false; break; } int b = lattice_node[lattice_tet[t][u]][1]+j; if (b >= sdf.phi.nj) { good_tet=false; break; } int c = lattice_node[lattice_tet[t][u]][2]+k; if (c >= sdf.phi.nk) { good_tet=false; break; } if (sdf.phi(a,b,c) < 0) negative_phi = true; } if (good_tet && negative_phi) { // add vertices if they don't exist yet, find actual tet to add Vec4i actual_tet(-1,-1,-1,-1); for (int u=0; u<4; ++u) { Vec3i vertex=lattice_node[lattice_tet[t][u]]+Vec3i(i,j,k); std::map<Vec3i,int>::iterator p = lattice_map.find(vertex); if (p == lattice_map.end()) { actual_tet[u] = mesh.vSize(); lattice_map[vertex] = actual_tet[u]; mesh.verts().push_back(sdf.origin+sdf.dx*Vec3f(vertex)); vphi.push_back(sdf.phi(vertex[0],vertex[1],vertex[2])); } else { actual_tet[u]=p->second; } } mesh.tets().push_back(actual_tet); } } } }
// assuming vphi[i] and vphi[j] have different signs, find or create a new // vertex on the edge between them where phi interpolates to zero. static int cut_edge(int i, int j, TetMesh& mesh, std::vector<float> &vphi, std::map<Vec2i,int> &cut_map) { assert((vphi[i]<0 && vphi[j]>0) || (vphi[i]>0 && vphi[j]<0)); Vec2i edge(min(i,j), max(i,j)); std::map<Vec2i,int>::iterator p = cut_map.find(edge); if (p == cut_map.end()) { // this edge hasn't been cut yet? int v = (int)mesh.vSize(); float alpha = vphi[i]/(vphi[i]-vphi[j]); mesh.verts().push_back((1-alpha)*mesh.V(i) + alpha*mesh.V(j)); vphi.push_back(0); cut_map[edge] = v; return v; } else { // already done this edge return p->second; } }