Exemple #1
0
        }   // end make_level_set_3

        void make_level_set3_parallel(Vector3f origin, float dx,
                                      int ni, int nj, int nk,
                                      DenseGrid3f distances, int exact_band)
        {
            distances.resize(ni, nj, nk);
            distances.assign((float)((ni + nj + nk) * dx)); // upper bound on distance

            // closest triangle id for each grid cell
            DenseGrid3i closest_tri = new DenseGrid3i(ni, nj, nk, -1);

            // intersection_count(i,j,k) is # of tri intersections in (i-1,i]x{j}x{k}
            DenseGrid3i intersection_count = new DenseGrid3i(ni, nj, nk, 0);

            if (DebugPrint)
            {
                System.Console.WriteLine("start");
            }

            double ox = (double)origin[0], oy = (double)origin[1], oz = (double)origin[2];
            double invdx = 1.0 / dx;

            // Compute narrow-band distances. For each triangle, we find its grid-coord-bbox,
            // and compute exact distances within that box.

            // To compute in parallel, we need to safely update grid cells. Current strategy is
            // to use a spinlock to control access to grid. Partitioning the grid into a few regions,
            // each w/ a separate spinlock, improves performance somewhat. Have also tried having a
            // separate spinlock per-row, this resulted in a few-percent performance improvement.
            // Also tried pre-sorting triangles into disjoint regions, this did not help much except
            // on "perfect" cases like a sphere.
            int wi = ni / 2, wj = nj / 2, wk = nk / 2;

            SpinLock[] grid_locks = new SpinLock[8];

            bool abort            = false;

            gParallel.ForEach(Mesh.TriangleIndices(), (tid) => {
                if (tid % 100 == 0)
                {
                    abort = CancelF();
                }
                if (abort)
                {
                    return;
                }

                Vector3d xp = Vector3d.Zero, xq = Vector3d.Zero, xr = Vector3d.Zero;
                Mesh.GetTriVertices(tid, ref xp, ref xq, ref xr);

                // real ijk coordinates of xp/xq/xr
                double fip = (xp[0] - ox) * invdx, fjp = (xp[1] - oy) * invdx, fkp = (xp[2] - oz) * invdx;
                double fiq = (xq[0] - ox) * invdx, fjq = (xq[1] - oy) * invdx, fkq = (xq[2] - oz) * invdx;
                double fir = (xr[0] - ox) * invdx, fjr = (xr[1] - oy) * invdx, fkr = (xr[2] - oz) * invdx;

                // clamped integer bounding box of triangle plus exact-band
                int i0 = MathUtil.Clamp(((int)MathUtil.Min(fip, fiq, fir)) - exact_band, 0, ni - 1);
                int i1 = MathUtil.Clamp(((int)MathUtil.Max(fip, fiq, fir)) + exact_band + 1, 0, ni - 1);
                int j0 = MathUtil.Clamp(((int)MathUtil.Min(fjp, fjq, fjr)) - exact_band, 0, nj - 1);
                int j1 = MathUtil.Clamp(((int)MathUtil.Max(fjp, fjq, fjr)) + exact_band + 1, 0, nj - 1);
                int k0 = MathUtil.Clamp(((int)MathUtil.Min(fkp, fkq, fkr)) - exact_band, 0, nk - 1);
                int k1 = MathUtil.Clamp(((int)MathUtil.Max(fkp, fkq, fkr)) + exact_band + 1, 0, nk - 1);

                // compute distance for each tri inside this bounding box
                // note: this can be very conservative if the triangle is large and on diagonal to grid axes
                for (int k = k0; k <= k1; ++k)
                {
                    for (int j = j0; j <= j1; ++j)
                    {
                        int base_idx = ((j < wj) ? 0 : 1) | ((k < wk) ? 0 : 2);    // construct index into spinlocks array

                        for (int i = i0; i <= i1; ++i)
                        {
                            Vector3d gx = new Vector3d((float)i * dx + origin[0], (float)j * dx + origin[1], (float)k * dx + origin[2]);
                            float d     = (float)point_triangle_distance(ref gx, ref xp, ref xq, ref xr);
                            if (d < distances[i, j, k])
                            {
                                int lock_idx = base_idx | ((i < wi) ? 0 : 4);
                                bool taken   = false;
                                grid_locks[lock_idx].Enter(ref taken);
                                if (d < distances[i, j, k])        // have to check again in case grid changed in another thread...
                                {
                                    distances[i, j, k]   = d;
                                    closest_tri[i, j, k] = tid;
                                }
                                grid_locks[lock_idx].Exit();
                            }
                        }
                    }
                }
            });

            if (CancelF())
            {
                return;
            }

            if (ComputeSigns == true)
            {
                if (DebugPrint)
                {
                    System.Console.WriteLine("done narrow-band");
                }

                compute_intersections(origin, dx, ni, nj, nk, intersection_count);
                if (CancelF())
                {
                    return;
                }

                if (DebugPrint)
                {
                    System.Console.WriteLine("done intersections");
                }

                if (ComputeMode == ComputeModes.FullGrid)
                {
                    // and now we fill in the rest of the distances with fast sweeping
                    for (int pass = 0; pass < 2; ++pass)
                    {
                        sweep_pass(origin, dx, distances, closest_tri);
                        if (CancelF())
                        {
                            return;
                        }
                    }
                    if (DebugPrint)
                    {
                        System.Console.WriteLine("done sweeping");
                    }
                }
                else
                {
                    // nothing!
                    if (DebugPrint)
                    {
                        System.Console.WriteLine("skipped sweeping");
                    }
                }

                if (DebugPrint)
                {
                    System.Console.WriteLine("done sweeping");
                }

                // then figure out signs (inside/outside) from intersection counts
                compute_signs(ni, nj, nk, distances, intersection_count);
                if (CancelF())
                {
                    return;
                }

                if (WantIntersectionsGrid)
                {
                    intersections_grid = intersection_count;
                }

                if (DebugPrint)
                {
                    System.Console.WriteLine("done signs");
                }
            }

            if (WantClosestTriGrid)
            {
                closest_tri_grid = closest_tri;
            }
        }   // end make_level_set_3
Exemple #2
0
        void make_level_set3(Vector3f origin, float dx,
                             int ni, int nj, int nk,
                             DenseGrid3f distances, int exact_band)
        {
            distances.resize(ni, nj, nk);
            distances.assign((ni + nj + nk) * dx); // upper bound on distance

            // closest triangle id for each grid cell
            DenseGrid3i closest_tri = new DenseGrid3i(ni, nj, nk, -1);

            // intersection_count(i,j,k) is # of tri intersections in (i-1,i]x{j}x{k}
            DenseGrid3i intersection_count = new DenseGrid3i(ni, nj, nk, 0);

            if (DebugPrint)
            {
                System.Console.WriteLine("start");
            }

            // Compute narrow-band distances. For each triangle, we find its grid-coord-bbox,
            // and compute exact distances within that box. The intersection_count grid
            // is also filled in this computation
            double   ddx = (double)dx;
            double   ox = (double)origin[0], oy = (double)origin[1], oz = (double)origin[2];
            Vector3d xp = Vector3d.Zero, xq = Vector3d.Zero, xr = Vector3d.Zero;

            foreach (int tid in Mesh.TriangleIndices())
            {
                if (tid % 100 == 0 && CancelF())
                {
                    break;
                }
                Mesh.GetTriVertices(tid, ref xp, ref xq, ref xr);

                // real ijk coordinates of xp/xq/xr
                double fip = (xp[0] - ox) / ddx, fjp = (xp[1] - oy) / ddx, fkp = (xp[2] - oz) / ddx;
                double fiq = (xq[0] - ox) / ddx, fjq = (xq[1] - oy) / ddx, fkq = (xq[2] - oz) / ddx;
                double fir = (xr[0] - ox) / ddx, fjr = (xr[1] - oy) / ddx, fkr = (xr[2] - oz) / ddx;

                // clamped integer bounding box of triangle plus exact-band
                int i0 = MathUtil.Clamp(((int)MathUtil.Min(fip, fiq, fir)) - exact_band, 0, ni - 1);
                int i1 = MathUtil.Clamp(((int)MathUtil.Max(fip, fiq, fir)) + exact_band + 1, 0, ni - 1);
                int j0 = MathUtil.Clamp(((int)MathUtil.Min(fjp, fjq, fjr)) - exact_band, 0, nj - 1);
                int j1 = MathUtil.Clamp(((int)MathUtil.Max(fjp, fjq, fjr)) + exact_band + 1, 0, nj - 1);
                int k0 = MathUtil.Clamp(((int)MathUtil.Min(fkp, fkq, fkr)) - exact_band, 0, nk - 1);
                int k1 = MathUtil.Clamp(((int)MathUtil.Max(fkp, fkq, fkr)) + exact_band + 1, 0, nk - 1);

                // compute distance for each tri inside this bounding box
                // note: this can be very conservative if the triangle is large and on diagonal to grid axes
                for (int k = k0; k <= k1; ++k)
                {
                    for (int j = j0; j <= j1; ++j)
                    {
                        for (int i = i0; i <= i1; ++i)
                        {
                            Vector3d gx = new Vector3d((float)i * dx + origin[0], (float)j * dx + origin[1], (float)k * dx + origin[2]);
                            float    d  = (float)point_triangle_distance(ref gx, ref xp, ref xq, ref xr);
                            if (d < distances[i, j, k])
                            {
                                distances[i, j, k]   = d;
                                closest_tri[i, j, k] = tid;
                            }
                        }
                    }
                }
            }
            if (CancelF())
            {
                return;
            }

            if (ComputeSigns == true)
            {
                if (DebugPrint)
                {
                    System.Console.WriteLine("done narrow-band");
                }

                compute_intersections(origin, dx, ni, nj, nk, intersection_count);
                if (CancelF())
                {
                    return;
                }

                if (DebugPrint)
                {
                    System.Console.WriteLine("done intersections");
                }

                if (ComputeMode == ComputeModes.FullGrid)
                {
                    // and now we fill in the rest of the distances with fast sweeping
                    for (int pass = 0; pass < 2; ++pass)
                    {
                        sweep_pass(origin, dx, distances, closest_tri);
                        if (CancelF())
                        {
                            return;
                        }
                    }
                    if (DebugPrint)
                    {
                        System.Console.WriteLine("done sweeping");
                    }
                }
                else
                {
                    // nothing!
                    if (DebugPrint)
                    {
                        System.Console.WriteLine("skipped sweeping");
                    }
                }


                // then figure out signs (inside/outside) from intersection counts
                compute_signs(ni, nj, nk, distances, intersection_count);
                if (CancelF())
                {
                    return;
                }

                if (DebugPrint)
                {
                    System.Console.WriteLine("done signs");
                }

                if (WantIntersectionsGrid)
                {
                    intersections_grid = intersection_count;
                }
            }

            if (WantClosestTriGrid)
            {
                closest_tri_grid = closest_tri;
            }
        }   // end make_level_set_3
 public void Clear(float f)
 {
     BackgroundValue = f;
     Grid.assign(BackgroundValue);
 }
        void make_level_set3(DMesh3 mesh, /*const std::vector<Vec3ui> &tri, const std::vector<Vec3f> &x*/
                             Vector3f origin, float dx,
                             int ni, int nj, int nk,
                             DenseGrid3f phi, int exact_band)
        {
            phi.resize(ni, nj, nk);
            phi.assign((ni + nj + nk) * dx);                                 // upper bound on distance
            DenseGrid3i closest_tri        = new DenseGrid3i(ni, nj, nk, -1);
            DenseGrid3i intersection_count = new DenseGrid3i(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

            System.Console.WriteLine("start");

            //Vector3f ijkmin, ijkmax;  // [RMS] unused in original code
            double ddx = (double)dx;
            double ox = (double)origin[0], oy = (double)origin[1], oz = (double)origin[2];

            foreach (int t in mesh.TriangleIndices())
            {
                Index3i triangle = mesh.GetTriangle(t);
                int     p = triangle.a, q = triangle.b, r = triangle.c;

                Vector3d xp = mesh.GetVertex(p);
                Vector3d xq = mesh.GetVertex(q);
                Vector3d xr = mesh.GetVertex(r);

                // coordinates in grid to high precision
                double fip = (xp[0] - ox) / ddx, fjp = (xp[1] - oy) / ddx, fkp = (xp[2] - oz) / ddx;
                double fiq = (xq[0] - ox) / ddx, fjq = (xq[1] - oy) / ddx, fkq = (xq[2] - oz) / ddx;
                double fir = (xr[0] - ox) / ddx, fjr = (xr[1] - oy) / ddx, fkr = (xr[2] - oz) / ddx;
                // do distances nearby
                int i0 = MathUtil.Clamp(((int)MathUtil.Min(fip, fiq, fir)) - exact_band, 0, ni - 1);
                int i1 = MathUtil.Clamp(((int)MathUtil.Max(fip, fiq, fir)) + exact_band + 1, 0, ni - 1);
                int j0 = MathUtil.Clamp(((int)MathUtil.Min(fjp, fjq, fjr)) - exact_band, 0, nj - 1);
                int j1 = MathUtil.Clamp(((int)MathUtil.Max(fjp, fjq, fjr)) + exact_band + 1, 0, nj - 1);
                int k0 = MathUtil.Clamp(((int)MathUtil.Min(fkp, fkq, fkr)) - exact_band, 0, nk - 1);
                int k1 = MathUtil.Clamp(((int)MathUtil.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)
                        {
                            Vector3f gx = new Vector3f((float)i * dx + origin[0], (float)j * dx + origin[1], (float)k * dx + origin[2]);
                            float    d  = point_triangle_distance(gx, (Vector3f)xp, (Vector3f)xq, (Vector3f)xr);
                            if (d < phi[i, j, k])
                            {
                                phi[i, j, k]         = d;
                                closest_tri[i, j, k] = t;
                            }
                        }
                    }
                }


                // and do intersection counts
                j0 = MathUtil.Clamp((int)Math.Ceiling(MathUtil.Min(fjp, fjq, fjr)), 0, nj - 1);
                j1 = MathUtil.Clamp((int)Math.Floor(MathUtil.Max(fjp, fjq, fjr)), 0, nj - 1);
                k0 = MathUtil.Clamp((int)Math.Ceiling(MathUtil.Min(fkp, fkq, fkr)), 0, nk - 1);
                k1 = MathUtil.Clamp((int)Math.Floor(MathUtil.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, out a, out b, out c))
                        {
                            double fi         = a * fip + b * fiq + c * fir; // intersection i coordinate
                            int    i_interval = (int)(Math.Ceiling(fi));     // intersection is in (i_interval-1,i_interval]
                            if (i_interval < 0)
                            {
                                intersection_count.increment(0, j, k); // we enlarge the first interval to include everything to the -x direction
                            }
                            else if (i_interval < ni)
                            {
                                intersection_count.increment(i_interval, j, k);
                            }
                            // we ignore intersections that are beyond the +x side of the grid
                        }
                    }
                }
            }

            System.Console.WriteLine("done narrow-band");

            // and now we fill in the rest of the distances with fast sweeping
            for (int pass = 0; pass < 2; ++pass)
            {
                sweep(mesh, phi, closest_tri, origin, dx, +1, +1, +1);
                sweep(mesh, phi, closest_tri, origin, dx, -1, -1, -1);
                sweep(mesh, phi, closest_tri, origin, dx, +1, +1, -1);
                sweep(mesh, phi, closest_tri, origin, dx, -1, -1, +1);
                sweep(mesh, phi, closest_tri, origin, dx, +1, -1, +1);
                sweep(mesh, phi, closest_tri, origin, dx, -1, +1, -1);
                sweep(mesh, phi, closest_tri, origin, dx, +1, -1, -1);
                sweep(mesh, phi, closest_tri, origin, dx, -1, +1, +1);
            }

            System.Console.WriteLine("done sweeping");

            // 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
                        }
                    }
                }
            }

            System.Console.WriteLine("done signs");
        }   // end make_level_set_3
        void generate_support(Vector3f origin, float dx,
            int ni, int nj, int nk,
            DenseGrid3f supportGrid)
        {
            supportGrid.resize(ni, nj, nk);
            supportGrid.assign(1); // sentinel

            if (DebugPrint) System.Console.WriteLine("start");

            bool CHECKERBOARD = false;

            System.Console.WriteLine("Computing SDF");

            // compute unsigned SDF
            MeshSignedDistanceGrid sdf = new MeshSignedDistanceGrid(Mesh, CellSize) {
                ComputeSigns = true, ExactBandWidth = 3,
                /*,ComputeMode = MeshSignedDistanceGrid.ComputeModes.FullGrid*/ };
            sdf.CancelF = Cancelled;
            sdf.Compute();
            if (Cancelled())
                return;
            var distanceField = new DenseGridTrilinearImplicit(sdf.Grid, sdf.GridOrigin, sdf.CellSize);

            double angle = MathUtil.Clamp(OverhangAngleDeg, 0.01, 89.99);
            double cos_thresh = Math.Cos(angle * MathUtil.Deg2Rad);

            System.Console.WriteLine("Marking overhangs");

            // Compute narrow-band distances. For each triangle, we find its grid-coord-bbox,
            // and compute exact distances within that box. The intersection_count grid
            // is also filled in this computation
            double ddx = (double)dx;
            double ox = (double)origin[0], oy = (double)origin[1], oz = (double)origin[2];
            Vector3d va = Vector3d.Zero, vb = Vector3d.Zero, vc = Vector3d.Zero;
            foreach (int tid in Mesh.TriangleIndices()) {
                if (tid % 100 == 0 && Cancelled())
                    break;

                Mesh.GetTriVertices(tid, ref va, ref vb, ref vc);
                Vector3d normal = MathUtil.Normal(ref va, ref vb, ref vc);
                if (normal.Dot(-Vector3d.AxisY) < cos_thresh)
                    continue;

                // real ijk coordinates of va/vb/vc
                double fip = (va[0] - ox) / ddx, fjp = (va[1] - oy) / ddx, fkp = (va[2] - oz) / ddx;
                double fiq = (vb[0] - ox) / ddx, fjq = (vb[1] - oy) / ddx, fkq = (vb[2] - oz) / ddx;
                double fir = (vc[0] - ox) / ddx, fjr = (vc[1] - oy) / ddx, fkr = (vc[2] - oz) / ddx;

                // clamped integer bounding box of triangle plus exact-band
                int exact_band = 0;
                int i0 = MathUtil.Clamp(((int)MathUtil.Min(fip, fiq, fir)) - exact_band, 0, ni - 1);
                int i1 = MathUtil.Clamp(((int)MathUtil.Max(fip, fiq, fir)) + exact_band + 1, 0, ni - 1);
                int j0 = MathUtil.Clamp(((int)MathUtil.Min(fjp, fjq, fjr)) - exact_band, 0, nj - 1);
                int j1 = MathUtil.Clamp(((int)MathUtil.Max(fjp, fjq, fjr)) + exact_band + 1, 0, nj - 1);
                int k0 = MathUtil.Clamp(((int)MathUtil.Min(fkp, fkq, fkr)) - exact_band, 0, nk - 1);
                int k1 = MathUtil.Clamp(((int)MathUtil.Max(fkp, fkq, fkr)) + exact_band + 1, 0, nk - 1);

                // don't put into y=0 plane
                if (j0 == 0)
                    j0 = 1;

                // compute distance for each tri inside this bounding box
                // note: this can be very conservative if the triangle is large and on diagonal to grid axes
                for (int k = k0; k <= k1; ++k) {
                    for (int j = j0; j <= j1; ++j) {
                        for (int i = i0; i <= i1; ++i) {
                            Vector3d gx = new Vector3d((float)i * dx + origin[0], (float)j * dx + origin[1], (float)k * dx + origin[2]);
                            float d = (float)MeshSignedDistanceGrid.point_triangle_distance(ref gx, ref va, ref vb, ref vc);

                            // vertical checkerboard pattern (eg 'tips')
                            if (CHECKERBOARD) {
                                int zz = (k % 2 == 0) ? 1 : 0;
                                if (i % 2 == zz)
                                    continue;
                            }

                            if (d < dx / 2) {
                                if (j > 1) {
                                    supportGrid[i, j, k] = SUPPORT_TIP_TOP;
                                    supportGrid[i, j - 1, k] = SUPPORT_TIP_BASE;
                                } else {
                                    supportGrid[i, j, k] = SUPPORT_TIP_BASE;
                                }
                            }
                        }
                    }
                }
            }
            if (Cancelled())
                return;

            //process_version1(supportGrid, distanceField);
            //process_version2(supportGrid, distanceField);

            generate_graph(supportGrid, distanceField);
            //Util.WriteDebugMesh(MakeDebugGraphMesh(), "c:\\scratch\\__LAST_GRAPH_INIT.obj");

            postprocess_graph();
            //Util.WriteDebugMesh(MakeDebugGraphMesh(), "c:\\scratch\\__LAST_GRAPH_OPT.obj");
        }
        void generate_support(Vector3f origin, float dx,
                              int ni, int nj, int nk,
                              DenseGrid3f supportGrid)
        {
            supportGrid.resize(ni, nj, nk);
            supportGrid.assign(1); // sentinel

            bool CHECKERBOARD = false;

            // compute unsigned SDF
            int exact_band = 1;

            if (SubtractMesh && SubtractMeshOffset > 0)
            {
                int offset_band = (int)(SubtractMeshOffset / CellSize) + 1;
                exact_band = Math.Max(exact_band, offset_band);
            }
            sdf = new MeshSignedDistanceGrid(Mesh, CellSize)
            {
                ComputeSigns = true, ExactBandWidth = exact_band
            };
            sdf.CancelF = this.CancelF;
            sdf.Compute();
            if (CancelF())
            {
                return;
            }
            var distanceField = new DenseGridTrilinearImplicit(sdf.Grid, sdf.GridOrigin, sdf.CellSize);


            double angle      = MathUtil.Clamp(OverhangAngleDeg, 0.01, 89.99);
            double cos_thresh = Math.Cos(angle * MathUtil.Deg2Rad);

            // Compute narrow-band distances. For each triangle, we find its grid-coord-bbox,
            // and compute exact distances within that box. The intersection_count grid
            // is also filled in this computation
            double   ddx = (double)dx;
            double   ox = (double)origin[0], oy = (double)origin[1], oz = (double)origin[2];
            Vector3d va = Vector3d.Zero, vb = Vector3d.Zero, vc = Vector3d.Zero;

            foreach (int tid in Mesh.TriangleIndices())
            {
                if (tid % 100 == 0 && CancelF())
                {
                    break;
                }

                Mesh.GetTriVertices(tid, ref va, ref vb, ref vc);
                Vector3d normal = MathUtil.Normal(ref va, ref vb, ref vc);
                if (normal.Dot(-Vector3d.AxisY) < cos_thresh)
                {
                    continue;
                }

                // real ijk coordinates of va/vb/vc
                double fip = (va[0] - ox) / ddx, fjp = (va[1] - oy) / ddx, fkp = (va[2] - oz) / ddx;
                double fiq = (vb[0] - ox) / ddx, fjq = (vb[1] - oy) / ddx, fkq = (vb[2] - oz) / ddx;
                double fir = (vc[0] - ox) / ddx, fjr = (vc[1] - oy) / ddx, fkr = (vc[2] - oz) / ddx;

                // clamped integer bounding box of triangle plus exact-band
                int extra_band = 0;
                int i0         = MathUtil.Clamp(((int)MathUtil.Min(fip, fiq, fir)) - extra_band, 0, ni - 1);
                int i1         = MathUtil.Clamp(((int)MathUtil.Max(fip, fiq, fir)) + extra_band + 1, 0, ni - 1);
                int j0         = MathUtil.Clamp(((int)MathUtil.Min(fjp, fjq, fjr)) - extra_band, 0, nj - 1);
                int j1         = MathUtil.Clamp(((int)MathUtil.Max(fjp, fjq, fjr)) + extra_band + 1, 0, nj - 1);
                int k0         = MathUtil.Clamp(((int)MathUtil.Min(fkp, fkq, fkr)) - extra_band, 0, nk - 1);
                int k1         = MathUtil.Clamp(((int)MathUtil.Max(fkp, fkq, fkr)) + extra_band + 1, 0, nk - 1);

                // don't put into y=0 plane
                //if (j0 == 0)
                //    j0 = 1;

                // compute distance for each tri inside this bounding box
                // note: this can be very conservative if the triangle is large and on diagonal to grid axes
                for (int k = k0; k <= k1; ++k)
                {
                    for (int j = j0; j <= j1; ++j)
                    {
                        for (int i = i0; i <= i1; ++i)
                        {
                            Vector3d gx = new Vector3d((float)i * dx + origin[0], (float)j * dx + origin[1], (float)k * dx + origin[2]);
                            float    d  = (float)MeshSignedDistanceGrid.point_triangle_distance(ref gx, ref va, ref vb, ref vc);

                            // vertical checkerboard pattern (eg 'tips')
                            if (CHECKERBOARD)
                            {
                                int zz = (k % 2 == 0) ? 1 : 0;
                                if (i % 2 == zz)
                                {
                                    continue;
                                }
                            }

                            if (d < dx / 2)
                            {
                                supportGrid[i, j, k] = SUPPORT_TIP_TOP;
                            }
                        }
                    }
                }
            }
            if (CancelF())
            {
                return;
            }

            fill_vertical_spans(supportGrid, distanceField);
            generate_mesh(supportGrid, distanceField);
        }