//##################################################################### // Function Compute_Level_Set //##################################################################### template<class T> void LEVELSET_MAKER_UNIFORM_2D<T>:: Compute_Level_Set(SEGMENTED_CURVE_2D<T>& curve,GRID<TV>& grid,int ghost_cells,ARRAY<T,TV_INT>& phi) { phi.Fill(FLT_MAX); T dx=grid.dX.Max(); ARRAY<bool,TV_INT> done(grid.Domain_Indices(ghost_cells+1)); for(int i=1;i<=curve.mesh.elements.m;i++){ SEGMENT_2D<T> segment(curve.particles.X(curve.mesh.elements(i).x),curve.particles.X(curve.mesh.elements(i).y)); RANGE<TV_INT> box(grid.Cell(segment.x1,3)); box.Enlarge_To_Include_Point(grid.Cell(segment.x2,3)); box=box.Intersect(box,grid.Domain_Indices(ghost_cells-1)); if(box.Empty()) continue; for(UNIFORM_ARRAY_ITERATOR<TV::m> it(box.Thickened(1));it.Valid();it.Next()){ TV X=grid.X(it.index); T dist=segment.Distance_From_Point_To_Segment(X); if(dist<abs(phi(it.index))+dx*1e-4 && dist<dx){ bool new_sign=TV::Dot_Product(X-segment.x1,segment.Normal())<0; if(abs(dist-abs(phi(it.index)))<dx*1e-4 && new_sign != (phi(it.index)<0)) new_sign=curve.Inside(grid.X(it.index)); if(abs(dist)<abs(phi(it.index))) phi(it.index)=dist; phi(it.index)=abs(phi(it.index))*(new_sign?-1:1); done(it.index)=true;}}} ARRAY<TV_INT> todo,next_todo; for(UNIFORM_GRID_ITERATOR_CELL<TV> it(grid);it.Valid();it.Next()) if(phi(it.index)!=FLT_MAX) todo.Append(it.index); for(int layer=1;todo.m;layer++){ while(todo.m){ TV_INT index=todo.Pop(); T next=sign(phi(index))*layer*dx; Compute_Level_Set_Helper(index+TV_INT(1,0),next,next_todo,phi); Compute_Level_Set_Helper(index-TV_INT(1,0),next,next_todo,phi); Compute_Level_Set_Helper(index+TV_INT(0,1),next,next_todo,phi); Compute_Level_Set_Helper(index-TV_INT(0,1),next,next_todo,phi);} todo.Exchange(next_todo);} /* for(UNIFORM_GRID_ITERATOR_CELL<TV> it(grid);it.Valid();it.Next()){ VECTOR<T,3> color=phi(it.index)>0?VECTOR<T,3>(0,1,0):VECTOR<T,3>(1,0,0); if(done(it.index)) color/=(T)3; Add_Debug_Particle(grid.X(it.index),color);}*/ PHYSBAM_DEBUG_WRITE_SUBSTEP("Compute Level Set",0,1); LEVELSET_2D<GRID<TV> > levelset(grid,phi); FAST_MARCHING_METHOD_UNIFORM<GRID<TV> > fmm(levelset,ghost_cells); fmm.Fast_Marching_Method(phi,done); }
LEVELSET<GRID<TV> >* createTriMeshAndLevelSet(const char* name) { string n = string(name); TRIANGULATED_SURFACE<float>* triangles = new TRIANGULATED_SURFACE<float>(); triangles->loadOBJ(name); triangles->Update_Bounding_Box_And_Gravity_Center(); RANGE<TV> range = triangles->bounding_box; range.min -= TV(0.2, 0.2, 0.2); range.max += TV(0.2, 0.2, 0.2); GRID<TV>* grid = new GRID<TV>(TV_INT(40,40,40), range); ARRAY<3,float>* phi = new ARRAY<3, float>(grid->Domain_Indices()); LEVELSET<GRID<TV> >* implicit_object = new LEVELSET<GRID<TV> >(*grid, *phi); SimLib::LEVELSET_MAKER<float> level_maker; ARRAY<3, int> closest_index; level_maker.Compute_Level_Set(*triangles, *grid, *phi, closest_index); ((LEVELSET<GRID<TV> >*)implicit_object)->Fast_Marching_Method(*triangles, closest_index); return implicit_object; }
//##################################################################### // Function Fill_Level //##################################################################### template<class TV,class T2> void EXTRAPOLATION_HIGHER_ORDER<TV,T2>:: Fill_Level(const GRID<TV>& grid,const T_LEVELSET& phi,int ghost,MAPPING& m,ARRAY<TV>& normal,ARRAY<VECTOR<STENCIL,TV::m> >& stencil,int order,T distance) { ARRAY<TV_INT> inside; m.node_to_index.Resize(grid.Domain_Indices(ghost+1)); // Need an extra ring for the sentinals m.index_to_node.Append(TV_INT::All_Ones_Vector()*INT_MAX); // First index is the "outside" index. normal.Append(TV::All_Ones_Vector()*INT_MAX); // Cells that must be solved for normally. for(UNIFORM_GRID_ITERATOR_NODE<TV> it(grid,ghost);it.Valid();it.Next()){ T p=phi.Phi(it.Location()); if(p<=0){ if(p>-(T)2.1*grid.dX.Max()){inside.Append(it.index);m.node_to_index(it.index)=-1;}} // Register two levels to prevent the closure below from leaking inside. else if(p<=(distance+(T)1e-4)*grid.dX.Max()) m.node_to_index(it.index)=m.index_to_node.Append(it.index);} // Ensure that two upwind nodes are being solved for. for(int i=2;i<=m.index_to_node.m;i++){ TV N=phi.Normal(grid.X(m.index_to_node(i))); normal.Append(N); for(int d=1;d<=TV::m;d++){ int s=N(d)<0?1:-1; TV_INT ind=m.index_to_node(i); for(int j=1;j<=2;j++){ ind(d)+=s; int& k=m.node_to_index(ind); if(!k) k=m.index_to_node.Append(ind);}}} m.max_solve_index(1)=m.index_to_node.m; // Register additional cells inside for derivatives. for(int o=1,i=1;o<=order*2;o++){ int previous=m.index_to_node.m,mx=inside.m; for(;i<=mx;i++){ bool added=false; for(int k=1;k<=TV::m*2;k++){ TV_INT ind=grid.Node_Neighbor(inside(i),k); int& n=m.node_to_index(ind); if(!n){n=-1;inside.Append(ind);} else if(n>0 && n<=previous && !added){ m.node_to_index(inside(i))=m.index_to_node.Append(inside(i)); normal.Append(phi.Normal(grid.X(inside(i)))); added=true;}} if(!added) inside.Append(TV_INT(inside(i)));} // Use a copy to avoid but on resize m.max_solve_index(o+1)=m.index_to_node.m;} // Register sentinal layer and precompute stencils. stencil.Resize(m.max_solve_index(order)); for(int i=2;i<=m.max_solve_index(order);i++){ TV N=normal(i); for(int d=1;d<=TV::m;d++){ int s=N(d)<0?1:-1; STENCIL& st=stencil(i)(d); st.scale=s*N(d)*grid.one_over_dX(d); TV_INT ind=m.index_to_node(i); for(int j=1;j<=3;j++){ st.nodes(j+1)=m.node_to_index(ind); ind(d)+=s;} ind(d)-=4*s; int& n=m.node_to_index(ind); if(!n) n=1; st.nodes(1)=n;}} }