/** * Computes normal from density field at given point. * * \note Doesn't do normalization! */ static void vnormal(PROCESS *process, const float point[3], float r_no[3]) { const float delta = process->delta; const float f = metaball(process, point[0], point[1], point[2]); r_no[0] = metaball(process, point[0] + delta, point[1], point[2]) - f; r_no[1] = metaball(process, point[0], point[1] + delta, point[2]) - f; r_no[2] = metaball(process, point[0], point[1], point[2] + delta) - f; #if 0 f = normalize_v3(r_no); if (0) { float tvec[3]; delta *= 2.0f; f = process->function(process, point[0], point[1], point[2]); tvec[0] = process->function(process, point[0] + delta, point[1], point[2]) - f; tvec[1] = process->function(process, point[0], point[1] + delta, point[2]) - f; tvec[2] = process->function(process, point[0], point[1], point[2] + delta) - f; if (normalize_v3(tvec) != 0.0f) { add_v3_v3(r_no, tvec); normalize_v3(r_no); } } #endif }
/** * return corner with the given lattice location * set (and cache) its function value */ static CORNER *setcorner(PROCESS *process, int i, int j, int k) { /* for speed, do corner value caching here */ CORNER *c; int index; /* does corner exist? */ index = HASH(i, j, k); c = process->corners[index]; for (; c != NULL; c = c->next) { if (c->i == i && c->j == j && c->k == k) { return c; } } c = BLI_memarena_alloc(process->pgn_elements, sizeof(CORNER)); c->i = i; c->co[0] = ((float)i - 0.5f) * process->size; c->j = j; c->co[1] = ((float)j - 0.5f) * process->size; c->k = k; c->co[2] = ((float)k - 0.5f) * process->size; c->value = metaball(process, c->co[0], c->co[1], c->co[2]); c->next = process->corners[index]; process->corners[index] = c; return c; }
int main(int argc, char **argv) { VoxelMesh vm(dim3(20, 20, 20), point(0, 0, 0), point(1, 1, 1)); std::vector<metaball> mbs; for (int i = 0; i < 20; i++) { mbs.push_back(metaball(point(randv(), randv(), randv()), 3 * randv() - 1)); } std::cout << "Setting voxel data" << std::endl; vm.for_each_voxel([&mbs] (VoxelMesh &vm, const dim3 &vox) { const point &p = vm.center(vox); /* vm[vox] = 0; for (const auto &m : mbs) vm[vox] += m(p); */ vm[vox] = 1. / (p - point(.5, .5, .5)).norm(); }); bool tri = true; if (argc > 1) tri = std::string(argv[1])[0] == 't'; std::cout << "Generating mesh" << std::endl; double th = 2.1; if (tri) { SurfaceMesh<triangle> sm(vm, th); std::cout << "Saving TRI mesh" << std::endl; sm.save_vtk("res_tri.vtk"); sm.save_txt("res.tri"); } else { SurfaceMesh<quad> sm(vm, th); std::cout << "Saving QUAD mesh" << std::endl; sm.save_vtk("res_quad.vtk"); sm.save_txt("res.quad"); } return 0; }
/** * Given two corners, computes approximation of surface intersection point between them. * In case of small threshold, do bisection. */ static void converge(PROCESS *process, const CORNER *c1, const CORNER *c2, float r_p[3]) { float tmp, dens; unsigned int i; float c1_value, c1_co[3]; float c2_value, c2_co[3]; if (c1->value < c2->value) { c1_value = c2->value; copy_v3_v3(c1_co, c2->co); c2_value = c1->value; copy_v3_v3(c2_co, c1->co); } else { c1_value = c1->value; copy_v3_v3(c1_co, c1->co); c2_value = c2->value; copy_v3_v3(c2_co, c2->co); } for (i = 0; i < process->converge_res; i++) { interp_v3_v3v3(r_p, c1_co, c2_co, 0.5f); dens = metaball(process, r_p[0], r_p[1], r_p[2]); if (dens > 0.0f) { c1_value = dens; copy_v3_v3(c1_co, r_p); } else { c2_value = dens; copy_v3_v3(c2_co, r_p); } } tmp = -c1_value / (c2_value - c1_value); interp_v3_v3v3(r_p, c1_co, c2_co, tmp); }