static void skeletonize_layer(DenseGrid3i grid, int j, int dilation_rounds = 1) { DenseGrid2i layer = grid.get_slice(j, 1); DenseGrid2i tmp = new DenseGrid2i(layer.ni, layer.nj, 0); for (int k = 0; k < dilation_rounds; ++k) { tmp.assign(0); dilate(layer, tmp); } bool done = false; while (!done) { int sum_before = layer.sum(); tmp.assign(0); skeletonize_pass(layer, tmp, 0); tmp.assign(0); skeletonize_pass(layer, tmp, 1); int sum_after = layer.sum(); if (sum_before == sum_after) { break; } } for (int i = 0; i < grid.ni; ++i) { for (int k = 0; k < grid.nk; ++k) { grid[i, j, k] = layer[i, k]; } } }
static DenseGrid3i binarize(DenseGrid3f grid, float thresh = 0) { DenseGrid3i result = new DenseGrid3i(); result.resize(grid.ni, grid.nj, grid.nk); int size = result.size; for (int k = 0; k < size; ++k) { result[k] = (grid[k] < thresh) ? 1 : 0; } return(result); }
/// <summary> /// fully sequential version, no threading /// </summary> void generate_continuation(IEnumerable <Vector3d> seeds) { var cell = new GridCell(); int[] vertlist = new int[12]; done_cells = new DenseGrid3i(CellDimensions.x, CellDimensions.y, CellDimensions.z, 0); var stack = new List <Vector3i>(); foreach (Vector3d seed in seeds) { Vector3i seed_idx = cell_index(seed); if (done_cells[seed_idx] == 1) { continue; } stack.Add(seed_idx); done_cells[seed_idx] = 1; while (stack.Count > 0) { Vector3i idx = stack[stack.Count - 1]; stack.RemoveAt(stack.Count - 1); if (CancelF()) { return; } initialize_cell(cell, ref idx); if (polygonize_cell(cell, vertlist)) { // found crossing foreach (Vector3i o in gIndices.GridOffsets6) { Vector3i nbr_idx = idx + o; if (GridBounds.Contains(nbr_idx) && done_cells[nbr_idx] == 0) { stack.Add(nbr_idx); done_cells[nbr_idx] = 1; } } } } } }
public void GenerateContinuation(IEnumerable <Vector3d> seeds) { Mesh = new DMesh3(); int nx = (int)(Bounds.Width / CubeSize) + 1; int ny = (int)(Bounds.Height / CubeSize) + 1; int nz = (int)(Bounds.Depth / CubeSize) + 1; CellDimensions = new Vector3i(nx, ny, nz); GridBounds = new AxisAlignedBox3i(Vector3i.Zero, CellDimensions); if (LastGridBounds != GridBounds) { corner_values_grid = new DenseGrid3f(nx + 1, ny + 1, nz + 1, float.MaxValue); edge_vertices = new Dictionary <long, int>(); corner_values = new Dictionary <long, double>(); if (ParallelCompute) { done_cells = new DenseGrid3i(CellDimensions.x, CellDimensions.y, CellDimensions.z, 0); } } else { edge_vertices.Clear(); corner_values.Clear(); corner_values_grid.assign(float.MaxValue); if (ParallelCompute) { done_cells.assign(0); } } if (ParallelCompute) { generate_continuation_parallel(seeds); } else { generate_continuation(seeds); } LastGridBounds = GridBounds; }
void process_version1(DenseGrid3f supportGrid, DenseGridTrilinearImplicit distanceField) { int ni = supportGrid.ni, nj = supportGrid.nj, nk = supportGrid.nk; float dx = (float)CellSize; Vector3f origin = this.GridOrigin; // sweep values down, column by column for (int k = 0; k < nk; ++k) { for (int i = 0; i < ni; ++i) { bool in_support = false; for (int j = nj - 1; j >= 0; j--) { float fcur = supportGrid[i, j, k]; if (fcur >= 0) { Vector3d cell_center = new Vector3f(i * dx, j * dx, k * dx) + origin; if (in_support) { bool is_inside = distanceField.Value(ref cell_center) < 0; if (is_inside) { supportGrid[i, j, k] = -3; in_support = false; } else { supportGrid[i, j, k] = -1; } } } else { in_support = true; } } } } // skeletonize each layer // todo: would be nice to skeletonize the 3D volume.. ? DenseGrid3i binary = new DenseGrid3i(ni, nj, nk, 0); foreach (Vector3i idx in binary.Indices()) { binary[idx] = (supportGrid[idx] < 0) ? 1 : 0; } for (int j = 0; j < nj; ++j) { skeletonize_layer(binary, j); } // debug thing //VoxelSurfaceGenerator voxgen = new VoxelSurfaceGenerator() { // Voxels = binary.get_bitmap() //}; //voxgen.Generate(); //Util.WriteDebugMesh(voxgen.makemesh(), "c:\\scratch\\binary.obj"); // for skeleton voxels, we add some power for (int j = 0; j < nj; ++j) { for (int k = 1; k < nk - 1; ++k) { for (int i = 1; i < ni - 1; ++i) { if (binary[i, j, k] > 0) { supportGrid[i, j, k] = -3; } //else // supportGrid[i, j, k] = 1; // clear non-skeleton voxels } } } // power up the ground-plane voxels for (int k = 0; k < nk; ++k) { for (int i = 0; i < ni; ++i) { if (supportGrid[i, 0, k] < 0) { supportGrid[i, 0, k] = -5; } } } #if true DenseGrid3f smoothed = new DenseGrid3f(supportGrid); float nbr_weight = 0.5f; for (int iter = 0; iter < 15; ++iter) { // add some mass to skeleton voxels for (int j = 0; j < nj; ++j) { for (int k = 1; k < nk - 1; ++k) { for (int i = 1; i < ni - 1; ++i) { if (binary[i, j, k] > 0) { supportGrid[i, j, k] = supportGrid[i, j, k] - nbr_weight / 25.0f; } } } } for (int j = 0; j < nj; ++j) { for (int k = 1; k < nk - 1; ++k) { for (int i = 1; i < ni - 1; ++i) { int neg = 0; float avg = 0, w = 0; for (int n = 0; n < 8; ++n) { int xi = i + gIndices.GridOffsets8[n].x; int zi = k + gIndices.GridOffsets8[n].y; float f = supportGrid[xi, j, zi]; if (f < 0) { neg++; } avg += nbr_weight * f; w += nbr_weight; } if (neg > -1) { avg += supportGrid[i, j, k]; w += 1.0f; smoothed[i, j, k] = avg / w; } else { smoothed[i, j, k] = supportGrid[i, j, k]; } } } } supportGrid.swap(smoothed); } #endif // hard-enforce that skeleton voxels stay inside //for (int j = 0; j < nj; ++j) { // for (int k = 1; k < nk - 1; ++k) { // for (int i = 1; i < ni - 1; ++i) { // if (binary[i, j, k] > 0) // supportGrid[i, j, k] = Math.Min(supportGrid[i, j, k], - 1); // } // } //} }