// remove tets with corners where phi=0 but are outside the volume static void remove_exterior_tets(TetMesh& mesh, const std::vector<float> &vphi, const SDF& sdf) { for (size_t t=0; t<mesh.tSize(); ) { int i, j, k, l; assign(mesh.T(t), i, j, k, l); assert(vphi[i]<=0 && vphi[j]<=0 && vphi[k]<=0 && vphi[l]<=0); if (vphi[i]==0 && vphi[j]==0 && vphi[k]==0 && vphi[l]==0 && sdf((mesh.V(i)+mesh.V(j)+mesh.V(k)+mesh.V(l))/4)>0) { mesh.T(t) = mesh.tets().back(); mesh.tets().pop_back(); } else { ++t; } } }
// 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; } }
// 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; } }