Esempio n. 1
0
static void check_neighbour(const std::vector<Vec3ui> &tri, const std::vector<Vec3f> &x,
                            Array3f &phi, Array3i &closest_tri,
                            const Vec3f &gx, int i0, int j0, int k0, int i1, int j1, int k1)
{
   if(closest_tri(i1,j1,k1)>=0){
      unsigned int p, q, r; assign(tri[closest_tri(i1,j1,k1)], p, q, r);
      float d=point_triangle_distance(gx, x[p], x[q], x[r]);
      if(d<phi(i0,j0,k0)){
         phi(i0,j0,k0)=d;
         closest_tri(i0,j0,k0)=closest_tri(i1,j1,k1);
      }
   }
}
Esempio n. 2
0
void meshsurf3::buildSurface( std::vector<vec3d> &vertices, std::vector<vec3d> &normals, std::vector<vec3i> &faces, const levelset3 *fluid, const levelset3 *solid, bool enclose, FLOAT64 dpx, uint iteration, bool doFit ) {
	// Save a reference to the mesher
	const mesher3 &g = *this->g;
	
	tick(); dump("Computing levelset for %d nodes...", g.nodes.size());
	values.clear();
	values.resize(g.nodes.size());
	if( values.empty() ) {
		email::print("Mesher Uninitialized !\n");
		email::send();
		exit(0);
	}
	// Compute levelset for each node
	PARALLEL_FOR for( uint n=0; n<g.nodes.size(); n++ ) {
		FLOAT64 phi = fluid->evalLevelset(g.nodes[n]);
		if( enclose ) phi = fmax(phi,-dpx-solid->evalLevelset(g.nodes[n]));
		values[n] = phi;
	}
	dump("Done. Took %s.\n",stock("meshsurf_levelset_sample"));
	
	// Fill holes
	fillHoles(values,solid,g.nodes,g.elements,g.node2node,fluid->dx);
	
	// Calculate intersections on edges
	tick(); dump("Computing cut edges for each tet...");
	std::vector<vec3d> cutpoints(g.edges.size());
	std::vector<int> cutIndices(g.edges.size());
	uint index = 0;
	for( int n=0; n<g.edges.size(); n++ ) {
		FLOAT64 levelsets[2];
		for( uint m=0; m<2; m++ ) levelsets[m] = values[g.edges[n][m]];
		if( copysign(1.0,levelsets[0]) * copysign(1.0,levelsets[1]) <= 0 ) {
			FLOAT64 det = levelsets[0]-levelsets[1];
			if( fabs(det) < 1e-16 ) det = copysign(1e-16,det);
			FLOAT64 a = fmin(0.99,fmax(0.01,levelsets[0]/det));
			vec3d p = (1.0-a)*g.nodes[g.edges[n][0]]+a*g.nodes[g.edges[n][1]];
			cutpoints[n] = p;
			cutIndices[n] = index++;
		} else {
			cutIndices[n] = -1;
		}
	}
	
	// Copy them to packed array
	vertices.clear();
	vertices.resize(index);
	index = 0;
	for( uint n=0; n<cutIndices.size(); n++ ) {
		if( cutIndices[n] >= 0 ) vertices[index++] = cutpoints[n];
	}
	dump("Done. Took %s.\n",stock());
	
	// Stitch faces (marching tet)
	tick(); dump("Stitching edges...");
	std::vector<std::vector<uint> > node_faces;
	node_faces.resize(g.nodes.size());
	faces.clear();
	for( uint n=0; n<g.elements.size(); n++ ) {
		std::vector<uint> nv;
		for( uint m=0; m<g.element_edges[n].size(); m++ ) {
			uint idx = g.element_edges[n][m];
			if( cutIndices[idx] >= 0 ) {
				nv.push_back(cutIndices[idx]);
			}
		}
		if( nv.size() == 4 ) {
			// Triangulate the veritces
			int idx0 = -1;
			int idx1 = -1;
			for( uint m=0; m<g.element_edges[n].size(); m++ ) {
				if( cutIndices[g.element_edges[n][m]] >= 0 ) {
					idx0 = g.element_edges[n][m];
					break;
				}
			}
			// If found one intersection edge
			if( idx0 >= 0 ) {
				for( uint m=0; m<g.element_edges[n].size(); m++ ) {
					uint opID = g.element_edges[n][m];
					if( cutIndices[opID] >= 0 && isOpEdge(idx0,opID)) {
						idx1 = opID;
						break;
					}
				}
				// If found opposite intersection edge
				if( idx1 >= 0 ) {
					vec3i v;
					v[0] = cutIndices[idx0];
					v[1] = cutIndices[idx1];
					for( uint m=0; m<g.element_edges[n].size(); m++ ) {
						uint idx2 = g.element_edges[n][m];
						if( cutIndices[idx2] >= 0 && idx2 != idx0 && idx2 != idx1 ) {
							v[2] = cutIndices[idx2];
							faces.push_back(v);
							for( uint m=0; m<g.elements[n].size(); m++ ) {
								node_faces[g.elements[n][m]].push_back(faces.size()-1);
							}
						}
					}
				} else {
					dump( "Opposite edge was not found !\n");
					exit(0);
				}
			} else {
				dump( "Ground edge was not found !\n");
				exit(0);
			}
		} else if( nv.size() == 3 ) {
			faces.push_back(vec3i(nv[0],nv[1],nv[2]));
			for( uint m=0; m<g.elements[n].size(); m++ ) {
				node_faces[g.elements[n][m]].push_back(faces.size()-1);
			}
		} else if( nv.size() == 0 ) {
			// Empty surface. Do nothing...
		} else {
			dump( "\nBad stitch encounrtered: Element - edge count = %d.\n", g.element_edges[n].size() );
			dump( "Unknown set found N(%e,%e,%e,%e) = %d.\n",
				   values[g.elements[n][0]], values[g.elements[n][1]], values[g.elements[n][2]], values[g.elements[n][3]], nv.size());
			for( uint k=0; k<g.element_edges[n].size(); k++ ) {
				uint vidx[2] = { g.edges[g.element_edges[n][k]][0], g.edges[g.element_edges[n][k]][1] };
				dump( "Edge info[%d] = edge(%d,%d) = (%e,%e) = (%f,%f)\n", k, vidx[0], vidx[1], values[vidx[0]], values[vidx[1]], copysign(1.0,values[vidx[0]]), copysign(1.0,values[vidx[1]]) );
			}
		}
	}
	dump("Done. Took %s.\n",stock("meshsurf_stitch_mesh"));
	
	// Find closest position
	tick(); dump("Finding closest surface position at surface tets...");
	surfacePos.clear();
	surfacePos.resize(g.nodes.size());
	for( uint n=0; n<g.nodes.size(); n++ ) {
		FLOAT64 dist = 1e8;
		vec3d p = g.nodes[n];
		for( uint m=0; m<node_faces[n].size(); m++ ) {
			vec3d p0 = vertices[faces[node_faces[n][m]][0]];
			vec3d p1 = vertices[faces[node_faces[n][m]][1]];
			vec3d p2 = vertices[faces[node_faces[n][m]][2]];
			vec3d out = g.nodes[n];
			vec3d src = out;
			FLOAT64 d = fmax(1e-8,point_triangle_distance(src,p0,p1,p2,out));
			if( d < dist ) {
				p = out;
				dist = d;
			}
		}
		if( dist < 1.0 ) {
			values[n] = (values[n]>=0 ? 1.0 : -1.0) * dist;
			surfacePos[n].push_back(g.nodes[n]);
			surfacePos[n].push_back(p);
		} else {
			values[n] = (values[n]>=0 ? 1.0 : -1.0) * 1e8;
		}
	}
	dump("Done. Took %s.\n",stock("meshsurf_find_close_pos1"));
	
	if( extrapolate_dist ) {
		// Fast march
		tick();
		std::vector<fastmarch3<FLOAT64>::node3 *> fnodes(g.nodes.size());
		for( uint n=0; n<g.nodes.size(); n++ ) fnodes[n] = new fastmarch3<FLOAT64>::node3;
		for( uint n=0; n<g.nodes.size(); n++ ) {
			vec3d p = g.nodes[n];
			bool fixed = fabs(values[n]) < 1.0;
			fnodes[n]->p = p;
			fnodes[n]->fixed = fixed;
			fnodes[n]->levelset = values[n];
			fnodes[n]->value = 0.0;
			fnodes[n]->p2p.resize(g.node2node[n].size());
			for( uint m=0; m<g.node2node[n].size(); m++ ) {
				fnodes[n]->p2p[m] = fnodes[g.node2node[n][m]];
			}
		}
		fastmarch3<FLOAT64>::fastMarch(fnodes,extrapolate_dist,-extrapolate_dist,1);
		
		// Pick up values
		for( uint n=0; n<g.nodes.size(); n++ ) {
			values[n] = fnodes[n]->levelset;
			delete fnodes[n];
		}
		stock("meshsurf_fastmarch");
	}
	
	// Compute normal
	tick(); dump("Computing normals...");
	computeNormals(vertices,normals,faces,cutIndices);
	dump("Done. Took %s.\n",stock("meshsurf_normal"));

	// Flip facet rotation if necessary
	flipFacet(vertices,normals,faces,0.1*fluid->dx);
	
#if 1
	// Fit surface
	if( doFit ) {
		tick(); dump("Fitting %d surface vertices...", vertices.size() );
		for( uint k=0; k<1; k++ ) {
			smoothMesh(vertices,normals,faces,solid,dpx,1);
			PARALLEL_FOR for( uint n=0; n<vertices.size(); n++ ) {
				vec3d out = vertices[n];
				if( solid->evalLevelset(out) > dpx && fluid->getClosestSurfacePos(out) ) {
					vertices[n] = out;
				}				
			}
		}
		dump("Done. Took %s.\n",stock("meshsurf_fit"));
	}
#endif
	
	// Smooth mesh
#if 1
	tick(); dump("Smoothing faces...");
	smoothMesh(vertices,normals,faces,solid,dpx,iteration);
	dump("Done. Took %s.\n",stock("meshsurf_smooth"));
#endif
	
	// Find closest position again
	tick(); dump("Finding closest surface position at surface tets again...");
	surfacePos.clear();
	surfacePos.resize(g.nodes.size());
	for( uint n=0; n<g.nodes.size(); n++ ) {
		FLOAT64 dist = 1e8;
		vec3d p = g.nodes[n];
		for( uint m=0; m<node_faces[n].size(); m++ ) {
			vec3d p0 = vertices[faces[node_faces[n][m]][0]];
			vec3d p1 = vertices[faces[node_faces[n][m]][1]];
			vec3d p2 = vertices[faces[node_faces[n][m]][2]];
			vec3d out = g.nodes[n];
			vec3d src = out;
			FLOAT64 d = fmax(1e-8,point_triangle_distance(src,p0,p1,p2,out));
			if( d < dist ) {
				p = out;
				dist = d;
			}
		}
		if( dist < 1.0 ) {
			values[n] = (values[n]>=0 ? 1.0 : -1.0) * dist;
		}
	}
	dump("Done. Took %s.\n",stock("meshsurf_find_close_pos2"));
	
	// Flip again
	flipFacet(vertices,normals,faces,0.1*fluid->dx);
}
Esempio n. 3
0
Array3i make_level_set3(const std::vector<Vec3ui> &tri, 
                        const std::vector<Vec3f> &x,
                        const Vec3f &origin, 
                        float dx, float dy, float dz,
                        int ni, int nj, int nk,
                        Array3f &phi, 
                        const int exact_band)
{
   phi.resize(ni, nj, nk);
   phi.assign(ni*dx+nj*dy+nk*dz); // upper bound on distance
   Array3i closest_tri(ni, nj, nk, -1);
   Array3i intersection_count(ni, nj, nk, 0); // intersection_count(i,j,k) is # of tri intersections in (i-1,i]x{j}x{k}
   // we begin by initializing distances near the mesh, and figuring out intersection counts
   Vec3f ijkmin, ijkmax;
   for(unsigned int t=0; t<tri.size(); ++t){
     unsigned int p, q, r; assign(tri[t], p, q, r);
     // coordinates in grid to high precision
      double fip=((double)x[p][0]-origin[0])/dx, fjp=((double)x[p][1]-origin[1])/dy, fkp=((double)x[p][2]-origin[2])/dz;
      double fiq=((double)x[q][0]-origin[0])/dx, fjq=((double)x[q][1]-origin[1])/dy, fkq=((double)x[q][2]-origin[2])/dz;
      double fir=((double)x[r][0]-origin[0])/dx, fjr=((double)x[r][1]-origin[1])/dy, fkr=((double)x[r][2]-origin[2])/dz;
      // do distances nearby
      int i0=clamp(int(min(fip,fiq,fir))-exact_band, 0, ni-1), i1=clamp(int(max(fip,fiq,fir))+exact_band+1, 0, ni-1);
      int j0=clamp(int(min(fjp,fjq,fjr))-exact_band, 0, nj-1), j1=clamp(int(max(fjp,fjq,fjr))+exact_band+1, 0, nj-1);
      int k0=clamp(int(min(fkp,fkq,fkr))-exact_band, 0, nk-1), k1=clamp(int(max(fkp,fkq,fkr))+exact_band+1, 0, nk-1);
      for(int k=k0; k<=k1; ++k) for(int j=j0; j<=j1; ++j) for(int i=i0; i<=i1; ++i){
         Vec3f gx(i*dx+origin[0], j*dy+origin[1], k*dz+origin[2]);
         float d=point_triangle_distance(gx, x[p], x[q], x[r]);
         if(d<phi(i,j,k)){
            phi(i,j,k)=d;
            closest_tri(i,j,k)=t;
         }
      }
      // and do intersection counts
      j0=clamp((int)std::ceil(min(fjp,fjq,fjr)), 0, nj-1);
      j1=clamp((int)std::floor(max(fjp,fjq,fjr)), 0, nj-1);
      k0=clamp((int)std::ceil(min(fkp,fkq,fkr)), 0, nk-1);
      k1=clamp((int)std::floor(max(fkp,fkq,fkr)), 0, nk-1);
      for(int k=k0; k<=k1; ++k) for(int j=j0; j<=j1; ++j){
         double a, b, c;
         if(point_in_triangle_2d(j, k, fjp, fkp, fjq, fkq, fjr, fkr, a, b, c)){
            double fi=a*fip+b*fiq+c*fir; // intersection i coordinate
            int i_interval=int(std::ceil(fi)); // intersection is in (i_interval-1,i_interval]
            if(i_interval<0) ++intersection_count(0, j, k); // we enlarge the first interval to include everything to the -x direction
            else if(i_interval<ni) ++intersection_count(i_interval,j,k);
            // we ignore intersections that are beyond the +x side of the grid
         }
      }
   }
   // and now we fill in the rest of the distances with fast sweeping
   for(unsigned int pass=0; pass<2; ++pass){
      sweep(tri, x, phi, closest_tri, origin, dx, dy, dz, +1, +1, +1);
      sweep(tri, x, phi, closest_tri, origin, dx, dy, dz, -1, -1, -1);
      sweep(tri, x, phi, closest_tri, origin, dx, dy, dz, +1, +1, -1);
      sweep(tri, x, phi, closest_tri, origin, dx, dy, dz, -1, -1, +1);
      sweep(tri, x, phi, closest_tri, origin, dx, dy, dz, +1, -1, +1);
      sweep(tri, x, phi, closest_tri, origin, dx, dy, dz, -1, +1, -1);
      sweep(tri, x, phi, closest_tri, origin, dx, dy, dz, +1, -1, -1);
      sweep(tri, x, phi, closest_tri, origin, dx, dy, dz, -1, +1, +1);
   }
   // then figure out signs (inside/outside) from intersection counts
   for(int k=0; k<nk; ++k) for(int j=0; j<nj; ++j){
      int total_count=0;
      for(int i=0; i<ni; ++i){
         total_count+=intersection_count(i,j,k);
         if(total_count%2==1){ // if parity of intersections so far is odd,
            phi(i,j,k)=-phi(i,j,k); // we are inside the mesh
         }
      }
   }
   return closest_tri;
}