示例#1
0
        /// <summary>
        /// precompute constant coefficients of triangle winding number approximation
        /// p: 'center' of expansion for triangles (area-weighted centroid avg)
        /// r: max distance from p to triangles
        /// order1: first-order vector coeff
        /// order2: second-order matrix coeff
        /// triCache: optional precomputed triangle centroid/normal/area
        /// </summary>
        public static void ComputeCoeffs(DMesh3 mesh, IEnumerable <int> triangles,
                                         ref Vector3d p, ref double r,
                                         ref Vector3d order1, ref Matrix3d order2,
                                         MeshTriInfoCache triCache = null)
        {
            p      = Vector3d.Zero;
            order1 = Vector3d.Zero;
            order2 = Matrix3d.Zero;
            r      = 0;

            // compute area-weighted centroid of triangles, we use this as the expansion point
            Vector3d P0 = Vector3d.Zero, P1 = Vector3d.Zero, P2 = Vector3d.Zero;
            double   sum_area = 0;

            foreach (int tid in triangles)
            {
                if (triCache != null)
                {
                    double area = triCache.Areas[tid];
                    sum_area += area;
                    p        += area * triCache.Centroids[tid];
                }
                else
                {
                    mesh.GetTriVertices(tid, ref P0, ref P1, ref P2);
                    double area = MathUtil.Area(ref P0, ref P1, ref P2);
                    sum_area += area;
                    p        += area * ((P0 + P1 + P2) / 3.0);
                }
            }
            p /= sum_area;

            // compute first and second-order coefficients of FWN taylor expansion, as well as
            // 'radius' value r, which is max dist from any tri vertex to p
            Vector3d n = Vector3d.Zero, c = Vector3d.Zero; double a = 0;

            foreach (int tid in triangles)
            {
                mesh.GetTriVertices(tid, ref P0, ref P1, ref P2);

                if (triCache == null)
                {
                    c = (1.0 / 3.0) * (P0 + P1 + P2);
                    n = MathUtil.FastNormalArea(ref P0, ref P1, ref P2, out a);
                }
                else
                {
                    triCache.GetTriInfo(tid, ref n, ref a, ref c);
                }

                order1 += a * n;

                Vector3d dcp = c - p;
                order2 += a * new Matrix3d(ref dcp, ref n);

                // this is just for return value...
                double maxdist = MathUtil.Max(P0.DistanceSquared(ref p), P1.DistanceSquared(ref p), P2.DistanceSquared(ref p));
                r = Math.Max(r, Math.Sqrt(maxdist));
            }
        }
示例#2
0
        /// <summary>
        /// Brute-force search for closest pair of triangles on two meshes
        /// </summary>
        public static Index2i FindNearestTriangles_LinearSearch(DMesh3 mesh1, DMesh3 mesh2, out double fNearestSqr)
        {
            Index2i nearPair = Index2i.Max;

            fNearestSqr = double.MaxValue;
            foreach (int ti in mesh1.TriangleIndices())
            {
                Vector3d a = Vector3d.Zero, b = Vector3d.Zero, c = Vector3d.Zero;
                mesh1.GetTriVertices(ti, ref a, ref b, ref c);
                foreach (int tj in mesh2.TriangleIndices())
                {
                    Vector3d e = Vector3d.Zero, f = Vector3d.Zero, g = Vector3d.Zero;
                    mesh2.GetTriVertices(tj, ref e, ref f, ref g);

                    var dist = new DistTriangle3Triangle3(new Triangle3d(a, b, c), new Triangle3d(e, f, g));
                    if (dist.GetSquared() < fNearestSqr)
                    {
                        fNearestSqr = dist.GetSquared();
                        nearPair    = new Index2i(ti, tj);
                    }
                }
            }
            fNearestSqr = Math.Sqrt(fNearestSqr);
            return(nearPair);
        }
示例#3
0
            internal double GetTriangleAnglesQuality(g3.DMesh3 mesh)
            {
                Vector3d v0 = Vector3d.Zero, v1 = Vector3d.Zero, v2 = Vector3d.Zero;

                mesh.GetTriVertices(meshIndex, ref v0, ref v1, ref v2);

                Vector3d anglesD = Vector3d.Zero;

                Vector3d e00 = (v1 - v0);

                e00.Normalize();
                Vector3d e01 = (v2 - v0);

                e01.Normalize();
                anglesD.x = Vector3d.AngleD(e00, e01);

                Vector3d e10 = (v0 - v1);

                e10.Normalize();
                Vector3d e11 = (v2 - v1);

                e11.Normalize();
                anglesD.y = Vector3d.AngleD(e10, e11);

                anglesD.z = 180 - anglesD.x - anglesD.y;

                double resultA = Math.Min(Math.Min(Math.Abs(anglesD.x - 90) / 10.0, Math.Abs(anglesD.y - 90) / 10.0), Math.Abs(anglesD.z - 90) / 10.0);

                double resultB = Math.Abs(anglesD.x - 60) / 30.0 + Math.Abs(anglesD.y - 60) / 30.0 + Math.Abs(anglesD.z - 60) / 30.0;

                double result = Math.Min(resultA, resultB);

                return(Math.Pow(result, 3));
            }
示例#4
0
        /// <summary>
        /// Get barycentric coords of point in triangle
        /// </summary>
        public static Vector3d BaryCoords(DMesh3 mesh, int tID, Vector3d point)
        {
            if (!mesh.IsTriangle(tID))
            {
                throw new Exception("MeshQueries.SurfaceFrame: triangle " + tID + " does not exist!");
            }
            Triangle3d tri = new Triangle3d();

            mesh.GetTriVertices(tID, ref tri.V0, ref tri.V1, ref tri.V2);
            return(tri.BarycentricCoords(point));
        }
示例#5
0
        /// <summary>
        /// convenience function to construct a IntrRay3Triangle3 object for a mesh triangle
        /// </summary>
        public static IntrRay3Triangle3 TriangleIntersection(DMesh3 mesh, int ti, Ray3d ray)
        {
            if (!mesh.IsTriangle(ti))
            {
                return(null);
            }
            Triangle3d tri = new Triangle3d();

            mesh.GetTriVertices(ti, ref tri.V0, ref tri.V1, ref tri.V2);
            IntrRay3Triangle3 q = new IntrRay3Triangle3(ray, tri);

            q.Find();
            return(q);
        }
示例#6
0
        /// <summary>
        /// construct a DistPoint3Triangle3 object for a mesh triangle
        /// </summary>
        public static DistPoint3Triangle3 TriangleDistance(DMesh3 mesh, int ti, Vector3d point)
        {
            if (!mesh.IsTriangle(ti))
            {
                return(null);
            }
            Triangle3d tri = new Triangle3d();

            mesh.GetTriVertices(ti, ref tri.V0, ref tri.V1, ref tri.V2);
            DistPoint3Triangle3 q = new DistPoint3Triangle3(point, tri);

            q.GetSquared();
            return(q);
        }
示例#7
0
        /// <summary>
        /// Find distance from point to mesh
        /// Returns interpolated vertex-normal frame if available, otherwise tri-normal frame.
        /// </summary>
        public static double NearestPointDistance(DMesh3 mesh, ISpatial spatial, Vector3d queryPoint, double maxDist = double.MaxValue)
        {
            int tid = spatial.FindNearestTriangle(queryPoint, maxDist);

            if (tid == DMesh3.InvalidID)
            {
                return(double.MaxValue);
            }
            Triangle3d tri = new Triangle3d();

            mesh.GetTriVertices(tid, ref tri.V0, ref tri.V1, ref tri.V2);
            Vector3d closest, bary;
            double   dist_sqr = DistPoint3Triangle3.DistanceSqr(ref queryPoint, ref tri, out closest, out bary);

            return(Math.Sqrt(dist_sqr));
        }
示例#8
0
        /// <summary>
        /// check if edge collapse will create a face-normal flip.
        /// Also checks if collapse would violate link condition, since
        /// we are iterating over one-ring anyway.
        ///
        /// This only checks one-ring of vid, so you have to call it twice,
        /// with vid and vother reversed, to check both one-rings
        /// </summary>
        protected bool collapse_creates_flip_or_invalid(int vid, int vother, ref Vector3d newv, int tc, int td)
        {
            Vector3d va = Vector3d.Zero, vb = Vector3d.Zero, vc = Vector3d.Zero;

            foreach (int tid in mesh.VtxTrianglesItr(vid))
            {
                if (tid == tc || tid == td)
                {
                    continue;
                }

                Index3i curt = mesh.GetTriangle(tid);
                if (curt.a == vother || curt.b == vother || curt.c == vother)
                {
                    return(true);                          // invalid nbrhood for collapse
                }

                mesh.GetTriVertices(tid, ref va, ref vb, ref vc);
                Vector3d ncur = (vb - va).Cross(vc - va);
                double   sign = 0;
                if (curt.a == vid)
                {
                    Vector3d nnew = (vb - newv).Cross(vc - newv);
                    sign = edge_flip_metric(ref ncur, ref nnew);
                }
                else if (curt.b == vid)
                {
                    Vector3d nnew = (newv - va).Cross(vc - va);
                    sign = edge_flip_metric(ref ncur, ref nnew);
                }
                else if (curt.c == vid)
                {
                    Vector3d nnew = (vb - va).Cross(newv - va);
                    sign = edge_flip_metric(ref ncur, ref nnew);
                }
                else
                {
                    throw new Exception("should never be here!");
                }

                if (sign <= edge_flip_tol)
                {
                    return(true);
                }
            }
            return(false);
        }
示例#9
0
 /// <summary>
 /// brute force search for any intersecting triangles on two meshes
 /// </summary>
 public static Index2i FindIntersectingTriangles_LinearSearch(DMesh3 mesh1, DMesh3 mesh2)
 {
     foreach (int ti in mesh1.TriangleIndices())
     {
         Vector3d a = Vector3d.Zero, b = Vector3d.Zero, c = Vector3d.Zero;
         mesh1.GetTriVertices(ti, ref a, ref b, ref c);
         foreach (int tj in mesh2.TriangleIndices())
         {
             Vector3d e = Vector3d.Zero, f = Vector3d.Zero, g = Vector3d.Zero;
             mesh2.GetTriVertices(tj, ref e, ref f, ref g);
             var intr = new IntrTriangle3Triangle3(new Triangle3d(a, b, c), new Triangle3d(e, f, g));
             if (intr.Test())
             {
                 return(new Index2i(ti, tj));
             }
         }
     }
     return(Index2i.Max);
 }
示例#10
0
        /// <summary>
        /// convenience function to construct a IntrTriangle3Triangle3 object for two mesh triangles
        /// </summary>
        public static IntrTriangle3Triangle3 TrianglesIntersection(DMesh3 mesh1, int ti, DMesh3 mesh2, int tj, Func <Vector3d, Vector3d> TransformF = null)
        {
            if (mesh1.IsTriangle(ti) == false || mesh2.IsTriangle(tj) == false)
            {
                return(null);
            }
            Triangle3d tri1 = new Triangle3d(), tri2 = new Triangle3d();

            mesh1.GetTriVertices(ti, ref tri1.V0, ref tri1.V1, ref tri1.V2);
            mesh2.GetTriVertices(tj, ref tri2.V0, ref tri2.V1, ref tri2.V2);
            if (TransformF != null)
            {
                tri2.V0 = TransformF(tri2.V0);
                tri2.V1 = TransformF(tri2.V1);
                tri2.V2 = TransformF(tri2.V2);
            }
            IntrTriangle3Triangle3 intr = new IntrTriangle3Triangle3(tri1, tri2);

            intr.Find();
            return(intr);
        }
示例#11
0
        /// <summary>
        /// convenience function to construct a DistTriangle3Triangle3 object for two mesh triangles
        /// </summary>
        public static DistTriangle3Triangle3 TrianglesDistance(DMesh3 mesh1, int ti, DMesh3 mesh2, int tj, Func <Vector3d, Vector3d> TransformF = null)
        {
            if (mesh1.IsTriangle(ti) == false || mesh2.IsTriangle(tj) == false)
            {
                return(null);
            }
            Triangle3d tri1 = new Triangle3d(), tri2 = new Triangle3d();

            mesh1.GetTriVertices(ti, ref tri1.V0, ref tri1.V1, ref tri1.V2);
            mesh2.GetTriVertices(tj, ref tri2.V0, ref tri2.V1, ref tri2.V2);
            if (TransformF != null)
            {
                tri2.V0 = TransformF(tri2.V0);
                tri2.V1 = TransformF(tri2.V1);
                tri2.V2 = TransformF(tri2.V2);
            }
            DistTriangle3Triangle3 dist = new DistTriangle3Triangle3(tri1, tri2);

            dist.GetSquared();
            return(dist);
        }
示例#12
0
        /// <summary>
        /// Get point-normal frame on surface of mesh. Assumption is that point lies in tID.
        /// returns interpolated vertex-normal frame if available, otherwise tri-normal frame.
        /// </summary>
        public static Frame3f SurfaceFrame(DMesh3 mesh, int tID, Vector3d point)
        {
            if (!mesh.IsTriangle(tID))
            {
                throw new Exception("MeshQueries.SurfaceFrame: triangle " + tID + " does not exist!");
            }
            Triangle3d tri = new Triangle3d();

            mesh.GetTriVertices(tID, ref tri.V0, ref tri.V1, ref tri.V2);
            Vector3d bary = tri.BarycentricCoords(point);

            point = tri.PointAt(bary);
            if (mesh.HasVertexNormals)
            {
                Vector3d normal = mesh.GetTriBaryNormal(tID, bary.x, bary.y, bary.z);
                return(new Frame3f(point, normal));
            }
            else
            {
                return(new Frame3f(point, mesh.GetTriNormal(tID)));
            }
        }
示例#13
0
        public static int FindHitTriangle_LinearSearch(DMesh3 mesh, Ray3d ray)
        {
            int    tNearestID = DMesh3.InvalidID;
            double fNearestT  = double.MaxValue;
            var    tri        = new Triangle3d();

            foreach (int ti in mesh.TriangleIndices())
            {
                // [TODO] optimize this
                mesh.GetTriVertices(ti, ref tri.V0, ref tri.V1, ref tri.V2);
                var ray_tri_hit = new IntrRay3Triangle3(ray, tri);
                if (ray_tri_hit.Find())
                {
                    if (ray_tri_hit.RayParameter < fNearestT)
                    {
                        fNearestT  = ray_tri_hit.RayParameter;
                        tNearestID = ti;
                    }
                }
            }

            return(tNearestID);
        }
示例#14
0
        protected void compute_full(IEnumerable <int> Triangles, bool bIsFullMeshHint = false)
        {
            Graph = new DGraph3();
            if (WantGraphEdgeInfo)
            {
                GraphEdges = new DVector <GraphEdgeInfo>();
            }

            Vertices = new Dictionary <Vector3d, int>();


            // multithreaded precomputation of per-vertex values
            double[] vertex_values = null;
            if (PrecomputeVertexValues)
            {
                vertex_values = new double[Mesh.MaxVertexID];
                IEnumerable <int> verts = Mesh.VertexIndices();
                if (bIsFullMeshHint == false)
                {
                    MeshVertexSelection vertices = new MeshVertexSelection(Mesh);
                    vertices.SelectTriangleVertices(Triangles);
                    verts = vertices;
                }
                gParallel.ForEach(verts, (vid) => {
                    vertex_values[vid] = ValueF(Mesh.GetVertex(vid));
                });
                VertexValueF = (vid) => { return(vertex_values[vid]); };
            }


            foreach (int tid in Triangles)
            {
                Vector3dTuple3 tv = new Vector3dTuple3();
                Mesh.GetTriVertices(tid, ref tv.V0, ref tv.V1, ref tv.V2);
                Index3i triVerts = Mesh.GetTriangle(tid);

                Vector3d f = (VertexValueF != null) ?
                             new Vector3d(VertexValueF(triVerts.a), VertexValueF(triVerts.b), VertexValueF(triVerts.c))
                    : new Vector3d(ValueF(tv.V0), ValueF(tv.V1), ValueF(tv.V2));

                // round f to 0 within epsilon?

                if (f.x < 0 && f.y < 0 && f.z < 0)
                {
                    continue;
                }
                if (f.x > 0 && f.y > 0 && f.z > 0)
                {
                    continue;
                }

                Index3i triEdges = Mesh.GetTriEdges(tid);

                if (f.x * f.y * f.z == 0)
                {
                    int z0 = (f.x == 0) ? 0 : ((f.y == 0) ? 1 : 2);
                    int i1 = (z0 + 1) % 3, i2 = (z0 + 2) % 3;
                    if (f[i1] * f[i2] > 0)
                    {
                        continue;       // single-vertex-crossing case, skip here and let other edges catch it
                    }
                    if (f[i1] == 0 || f[i2] == 0)
                    {
                        // on-edge case
                        int z1 = f[i1] == 0 ? i1 : i2;
                        if ((z0 + 1) % 3 != z1)
                        {
                            int tmp = z0; z0 = z1; z1 = tmp;        // catch reverse-orientation cases
                        }
                        int e0        = add_or_append_vertex(Mesh.GetVertex(triVerts[z0]));
                        int e1        = add_or_append_vertex(Mesh.GetVertex(triVerts[z1]));
                        int graph_eid = Graph.AppendEdge(e0, e1, (int)TriangleCase.OnEdge);
                        if (graph_eid >= 0 && WantGraphEdgeInfo)
                        {
                            add_on_edge(graph_eid, tid, triEdges[z0], new Index2i(e0, e1));
                        }
                    }
                    else
                    {
                        // edge/vertex case
                        Util.gDevAssert(f[i1] * f[i2] < 0);

                        int vert_vid = add_or_append_vertex(Mesh.GetVertex(triVerts[z0]));

                        int i = i1, j = i2;
                        if (triVerts[j] < triVerts[i])
                        {
                            int tmp = i; i = j; j = tmp;
                        }
                        Vector3d cross     = find_crossing(tv[i], tv[j], f[i], f[j]);
                        int      cross_vid = add_or_append_vertex(cross);
                        add_edge_pos(triVerts[i], triVerts[j], cross);

                        int graph_eid = Graph.AppendEdge(vert_vid, cross_vid, (int)TriangleCase.EdgeVertex);
                        if (graph_eid >= 0 && WantGraphEdgeInfo)
                        {
                            add_edge_vert(graph_eid, tid, triEdges[(z0 + 1) % 3], triVerts[z0], new Index2i(vert_vid, cross_vid));
                        }
                    }
                }
                else
                {
                    Index3i cross_verts = Index3i.Min;
                    int     less_than   = 0;
                    for (int tei = 0; tei < 3; ++tei)
                    {
                        int i = tei, j = (tei + 1) % 3;
                        if (f[i] < 0)
                        {
                            less_than++;
                        }
                        if (f[i] * f[j] > 0)
                        {
                            continue;
                        }
                        if (triVerts[j] < triVerts[i])
                        {
                            int tmp = i; i = j; j = tmp;
                        }
                        Vector3d cross = find_crossing(tv[i], tv[j], f[i], f[j]);
                        cross_verts[tei] = add_or_append_vertex(cross);
                        add_edge_pos(triVerts[i], triVerts[j], cross);
                    }
                    int e0 = (cross_verts.a == int.MinValue) ? 1 : 0;
                    int e1 = (cross_verts.c == int.MinValue) ? 1 : 2;
                    if (e0 == 0 && e1 == 2)         // preserve orientation order
                    {
                        e0 = 2; e1 = 0;
                    }

                    // preserving orientation does not mean we get a *consistent* orientation across faces.
                    // To do that, we need to assign "sides". Either we have 1 less-than-0 or 1 greater-than-0 vtx.
                    // Arbitrary decide that we want loops oriented like bdry loops would be if we discarded less-than side.
                    // In that case, when we are "cutting off" one vertex, orientation would end up flipped
                    if (less_than == 1)
                    {
                        int tmp = e0; e0 = e1; e1 = tmp;
                    }

                    int ev0 = cross_verts[e0];
                    int ev1 = cross_verts[e1];
                    // [RMS] if function is garbage, we can end up w/ case where both crossings
                    //   happen at same vertex, even though values are not the same (eg if
                    //   some values are double.MaxValue). We will just fail in these cases.
                    if (ev0 != ev1)
                    {
                        Util.gDevAssert(ev0 != int.MinValue && ev1 != int.MinValue);
                        int graph_eid = Graph.AppendEdge(ev0, ev1, (int)TriangleCase.EdgeEdge);
                        if (graph_eid >= 0 && WantGraphEdgeInfo)
                        {
                            add_edge_edge(graph_eid, tid, new Index2i(triEdges[e0], triEdges[e1]), new Index2i(ev0, ev1));
                        }
                    }
                }
            }


            Vertices = null;
        }
示例#15
0
        void find_hit_triangle(int iBox, ref Ray3d ray, ref double fNearestT, ref int tID)
        {
            int idx = box_to_index[iBox];

            if (idx < triangles_end)                // triange-list case, array is [N t1 t2 ... tN]
            {
                Triangle3d tri      = new Triangle3d();
                int        num_tris = index_list[idx];
                for (int i = 1; i <= num_tris; ++i)
                {
                    int ti = index_list[idx + i];

                    // [TODO] optimize this
                    mesh.GetTriVertices(ti, ref tri.V0, ref tri.V1, ref tri.V2);
                    IntrRay3Triangle3 ray_tri_hit = new IntrRay3Triangle3(ray, tri);
                    if (ray_tri_hit.Find())
                    {
                        if (ray_tri_hit.RayParameter < fNearestT)
                        {
                            fNearestT = ray_tri_hit.RayParameter;
                            tID       = ti;
                        }
                    }
                }
            }
            else                                    // internal node, either 1 or 2 child boxes
            {
                double e = MathUtil.ZeroTolerancef;

                int iChild1 = index_list[idx];
                if (iChild1 < 0)                     // 1 child, descend if nearer than cur min-dist
                {
                    iChild1 = (-iChild1) - 1;
                    double fChild1T = box_ray_intersect_t(iChild1, ray);
                    if (fChild1T <= fNearestT + e)
                    {
                        find_hit_triangle(iChild1, ref ray, ref fNearestT, ref tID);
                    }
                }
                else                                // 2 children, descend closest first
                {
                    iChild1 = iChild1 - 1;
                    int iChild2 = index_list[idx + 1] - 1;

                    double fChild1T = box_ray_intersect_t(iChild1, ray);
                    double fChild2T = box_ray_intersect_t(iChild2, ray);
                    if (fChild1T < fChild2T)
                    {
                        if (fChild1T <= fNearestT + e)
                        {
                            find_hit_triangle(iChild1, ref ray, ref fNearestT, ref tID);
                            if (fChild2T <= fNearestT + e)
                            {
                                find_hit_triangle(iChild2, ref ray, ref fNearestT, ref tID);
                            }
                        }
                    }
                    else
                    {
                        if (fChild2T <= fNearestT + e)
                        {
                            find_hit_triangle(iChild2, ref ray, ref fNearestT, ref tID);
                            if (fChild1T <= fNearestT + e)
                            {
                                find_hit_triangle(iChild1, ref ray, ref fNearestT, ref tID);
                            }
                        }
                    }
                }
            }
        }
示例#16
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
示例#17
0
        protected void compute_full(IEnumerable <int> Triangles)
        {
            Graph = new DGraph3();
            if (WantGraphEdgeInfo)
            {
                GraphEdges = new DVector <GraphEdgeInfo>();
            }

            Vertices = new Dictionary <Vector3d, int>();

            foreach (int tid in Triangles)
            {
                Vector3dTuple3 tv = new Vector3dTuple3();
                Mesh.GetTriVertices(tid, ref tv.V0, ref tv.V1, ref tv.V2);
                Vector3d f = new Vector3d(ValueF(tv.V0), ValueF(tv.V1), ValueF(tv.V2));

                // round f to 0 within epsilon?

                if (f.x < 0 && f.y < 0 && f.z < 0)
                {
                    continue;
                }
                if (f.x > 0 && f.y > 0 && f.z > 0)
                {
                    continue;
                }

                Index3i triVerts = Mesh.GetTriangle(tid);
                Index3i triEdges = Mesh.GetTriEdges(tid);

                if (f.x * f.y * f.z == 0)
                {
                    int z0 = (f.x == 0) ? 0 : ((f.y == 0) ? 1 : 2);
                    int i1 = (z0 + 1) % 3, i2 = (z0 + 2) % 3;
                    if (f[i1] * f[i2] > 0)
                    {
                        continue;       // single-vertex-crossing case, skip here and let other edges catch it
                    }
                    if (f[i1] == 0 || f[i2] == 0)
                    {
                        // on-edge case
                        int z1        = f[i1] == 0 ? i1 : i2;
                        int e0        = add_or_append_vertex(Mesh.GetVertex(triVerts[z0]));
                        int e1        = add_or_append_vertex(Mesh.GetVertex(triVerts[z1]));
                        int graph_eid = Graph.AppendEdge(e0, e1, (int)TriangleCase.OnEdge);
                        if (WantGraphEdgeInfo)
                        {
                            add_on_edge(graph_eid, tid, triEdges[z0]);
                        }
                    }
                    else
                    {
                        // edge/vertex case
                        Util.gDevAssert(f[i1] * f[i2] < 0);

                        int vert_vid = add_or_append_vertex(Mesh.GetVertex(triVerts[z0]));

                        int i = i1, j = i2;
                        if (triVerts[j] < triVerts[i])
                        {
                            int tmp = i; i = j; j = tmp;
                        }
                        Vector3d cross     = find_crossing(tv[i], tv[j], f[i], f[j]);
                        int      cross_vid = add_or_append_vertex(cross);

                        int graph_eid = Graph.AppendEdge(vert_vid, cross_vid, (int)TriangleCase.EdgeVertex);
                        if (WantGraphEdgeInfo)
                        {
                            add_edge_edge(graph_eid, tid, new Index2i(triEdges[(z0 + 1) % 3], triVerts[z0]));
                        }
                    }
                }
                else
                {
                    Index3i cross_verts = Index3i.Min;
                    for (int ti = 0; ti < 3; ++ti)
                    {
                        int i = ti, j = (ti + 1) % 3;
                        if (f[i] * f[j] > 0)
                        {
                            continue;
                        }
                        if (triVerts[j] < triVerts[i])
                        {
                            int tmp = i; i = j; j = tmp;
                        }
                        Vector3d cross = find_crossing(tv[i], tv[j], f[i], f[j]);
                        cross_verts[ti] = add_or_append_vertex(cross);
                    }
                    int e0  = (cross_verts.a == int.MinValue) ? 1 : 0;
                    int e1  = (cross_verts.c == int.MinValue) ? 1 : 2;
                    int ev0 = cross_verts[e0];
                    int ev1 = cross_verts[e1];
                    Util.gDevAssert(ev0 != int.MinValue && ev1 != int.MinValue);
                    int graph_eid = Graph.AppendEdge(ev0, ev1, (int)TriangleCase.EdgeEdge);
                    if (WantGraphEdgeInfo)
                    {
                        add_edge_edge(graph_eid, tid, new Index2i(triEdges[e0], triEdges[e1]));
                    }
                }
            }


            Vertices = null;
        }
示例#18
0
        // fill the intersection grid w/ number of intersections in each cell
        void compute_intersections(Vector3f origin, float dx, int ni, int nj, int nk, DenseGrid3i intersection_count)
        {
            double ox = (double)origin[0], oy = (double)origin[1], oz = (double)origin[2];
            double invdx = 1.0 / dx;

            bool cancelled = false;

            // this is what we will do for each triangle. There are no grid-reads, only grid-writes,
            // since we use atomic_increment, it is always thread-safe
            Action <int> ProcessTriangleF = (tid) => {
                if (tid % 100 == 0 && CancelF() == true)
                {
                    cancelled = true;
                }
                if (cancelled)
                {
                    return;
                }

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


                bool neg_x = false;
                if (InsideMode == InsideModes.ParityCount)
                {
                    Vector3d n = MathUtil.FastNormalDirection(ref xp, ref xq, ref xr);
                    neg_x = n.x > 0;
                }

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

                // recompute j/k integer bounds of triangle w/o exact band
                int j0 = MathUtil.Clamp((int)Math.Ceiling(MathUtil.Min(fjp, fjq, fjr)), 0, nj - 1);
                int j1 = MathUtil.Clamp((int)Math.Floor(MathUtil.Max(fjp, fjq, fjr)), 0, nj - 1);
                int k0 = MathUtil.Clamp((int)Math.Ceiling(MathUtil.Min(fkp, fkq, fkr)), 0, nk - 1);
                int k1 = MathUtil.Clamp((int)Math.Floor(MathUtil.Max(fkp, fkq, fkr)), 0, nk - 1);

                // and do intersection counts
                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.atomic_incdec(0, j, k, neg_x);
                            }
                            else if (i_interval < ni)
                            {
                                intersection_count.atomic_incdec(i_interval, j, k, neg_x);
                            }
                            else
                            {
                                // we ignore intersections that are beyond the +x side of the grid
                            }
                        }
                    }
                }
            };

            if (UseParallel)
            {
                gParallel.ForEach(Mesh.TriangleIndices(), ProcessTriangleF);
            }
            else
            {
                foreach (int tid in Mesh.TriangleIndices())
                {
                    ProcessTriangleF(tid);
                }
            }
        }
示例#19
0
        /// <summary>
        /// Compute distance from point to triangle in mesh, with minimal extra objects/etc
        /// </summary>
        public static double TriDistanceSqr(DMesh3 mesh, int ti, Vector3d point)
        {
            Vector3d V0 = Vector3d.Zero, V1 = Vector3d.Zero, V2 = Vector3d.Zero;

            mesh.GetTriVertices(ti, ref V0, ref V1, ref V2);

            Vector3d diff  = V0 - point;
            Vector3d edge0 = V1 - V0;
            Vector3d edge1 = V2 - V0;
            double   a00   = edge0.LengthSquared;
            double   a01   = edge0.Dot(ref edge1);
            double   a11   = edge1.LengthSquared;
            double   b0    = diff.Dot(ref edge0);
            double   b1    = diff.Dot(ref edge1);
            double   c     = diff.LengthSquared;
            double   det   = Math.Abs(a00 * a11 - a01 * a01);
            double   s     = a01 * b1 - a11 * b0;
            double   t     = a01 * b0 - a00 * b1;
            double   sqrDistance;

            if (s + t <= det)
            {
                if (s < 0)
                {
                    if (t < 0)
                    {                     // region 4
                        if (b0 < 0)
                        {
                            t = 0;
                            if (-b0 >= a00)
                            {
                                s           = 1;
                                sqrDistance = a00 + (2) * b0 + c;
                            }
                            else
                            {
                                s           = -b0 / a00;
                                sqrDistance = b0 * s + c;
                            }
                        }
                        else
                        {
                            s = 0;
                            if (b1 >= 0)
                            {
                                t           = 0;
                                sqrDistance = c;
                            }
                            else if (-b1 >= a11)
                            {
                                t           = 1;
                                sqrDistance = a11 + (2) * b1 + c;
                            }
                            else
                            {
                                t           = -b1 / a11;
                                sqrDistance = b1 * t + c;
                            }
                        }
                    }
                    else
                    {                     // region 3
                        s = 0;
                        if (b1 >= 0)
                        {
                            t           = 0;
                            sqrDistance = c;
                        }
                        else if (-b1 >= a11)
                        {
                            t           = 1;
                            sqrDistance = a11 + (2) * b1 + c;
                        }
                        else
                        {
                            t           = -b1 / a11;
                            sqrDistance = b1 * t + c;
                        }
                    }
                }
                else if (t < 0)
                {                 // region 5
                    t = 0;
                    if (b0 >= 0)
                    {
                        s           = 0;
                        sqrDistance = c;
                    }
                    else if (-b0 >= a00)
                    {
                        s           = 1;
                        sqrDistance = a00 + (2) * b0 + c;
                    }
                    else
                    {
                        s           = -b0 / a00;
                        sqrDistance = b0 * s + c;
                    }
                }
                else
                {                 // region 0
                                  // minimum at interior point
                    double invDet = (1) / det;
                    s          *= invDet;
                    t          *= invDet;
                    sqrDistance = s * (a00 * s + a01 * t + (2) * b0) +
                                  t * (a01 * s + a11 * t + (2) * b1) + c;
                }
            }
            else
            {
                double tmp0, tmp1, numer, denom;
                if (s < 0)
                {                 // region 2
                    tmp0 = a01 + b0;
                    tmp1 = a11 + b1;
                    if (tmp1 > tmp0)
                    {
                        numer = tmp1 - tmp0;
                        denom = a00 - (2) * a01 + a11;
                        if (numer >= denom)
                        {
                            s           = 1;
                            t           = 0;
                            sqrDistance = a00 + (2) * b0 + c;
                        }
                        else
                        {
                            s           = numer / denom;
                            t           = 1 - s;
                            sqrDistance = s * (a00 * s + a01 * t + (2) * b0) +
                                          t * (a01 * s + a11 * t + (2) * b1) + c;
                        }
                    }
                    else
                    {
                        s = 0;
                        if (tmp1 <= 0)
                        {
                            t           = 1;
                            sqrDistance = a11 + (2) * b1 + c;
                        }
                        else if (b1 >= 0)
                        {
                            t           = 0;
                            sqrDistance = c;
                        }
                        else
                        {
                            t           = -b1 / a11;
                            sqrDistance = b1 * t + c;
                        }
                    }
                }
                else if (t < 0)
                {                  // region 6
                    tmp0 = a01 + b1;
                    tmp1 = a00 + b0;
                    if (tmp1 > tmp0)
                    {
                        numer = tmp1 - tmp0;
                        denom = a00 - (2) * a01 + a11;
                        if (numer >= denom)
                        {
                            t           = 1;
                            s           = 0;
                            sqrDistance = a11 + (2) * b1 + c;
                        }
                        else
                        {
                            t           = numer / denom;
                            s           = 1 - t;
                            sqrDistance = s * (a00 * s + a01 * t + (2) * b0) +
                                          t * (a01 * s + a11 * t + (2) * b1) + c;
                        }
                    }
                    else
                    {
                        t = 0;
                        if (tmp1 <= 0)
                        {
                            s           = 1;
                            sqrDistance = a00 + (2) * b0 + c;
                        }
                        else if (b0 >= 0)
                        {
                            s           = 0;
                            sqrDistance = c;
                        }
                        else
                        {
                            s           = -b0 / a00;
                            sqrDistance = b0 * s + c;
                        }
                    }
                }
                else
                {                  // region 1
                    numer = a11 + b1 - a01 - b0;
                    if (numer <= 0)
                    {
                        s           = 0;
                        t           = 1;
                        sqrDistance = a11 + (2) * b1 + c;
                    }
                    else
                    {
                        denom = a00 - (2) * a01 + a11;
                        if (numer >= denom)
                        {
                            s           = 1;
                            t           = 0;
                            sqrDistance = a00 + (2) * b0 + c;
                        }
                        else
                        {
                            s           = numer / denom;
                            t           = 1 - s;
                            sqrDistance = s * (a00 * s + a01 * t + (2) * b0) +
                                          t * (a01 * s + a11 * t + (2) * b1) + c;
                        }
                    }
                }
            }

            if (sqrDistance < 0)
            {
                sqrDistance = 0;
            }

            return(sqrDistance);
        }
示例#20
0
        private void Remove(TriangleRemoval rem = TriangleRemoval.contained)
        {
#if ACAD
            var lastColor = 0;
#endif

            DMeshAABBTree3 spatial = new DMeshAABBTree3(CutMesh, true);
            spatial.WindingNumber(Vector3d.Zero);
            SafeListBuilder <int> containedT    = new SafeListBuilder <int>();
            SafeListBuilder <int> removeAnywayT = new SafeListBuilder <int>();

            // if the windinging number for the centroid point candidate triangles
            // is one or more (or close for safety), then it's inside the volume of cutMesh
            //
            gParallel.ForEach(Target.TriangleIndices(), (tid) =>
            {
                if (Target.GetTriArea(tid) < VertexSnapTol)
                {
                    removeAnywayT.SafeAdd(tid);
                    return; // parallel: equivalent to continue.
                }
                Vector3d v = Target.GetTriCentroid(tid);
                if (AttemptPlanarRemoval)
                {
                    // slightly offset the point to be evaluated.
                    //
                    var nrm = Target.GetTriNormal(tid);
                    v      -= nrm * 5 * VertexSnapTol;
                }

                var winding     = spatial.WindingNumber(v);
                bool IsInternal = winding > 0.9;
#if ACAD
                // temporarily here for debug purposes
                var wantColor = IsInternal ? 1 : 2;
                if (lastColor != wantColor)
                {
                    Debug.WriteLine($"-LAYER set L{wantColor}");
                    Debug.WriteLine($"");
                    lastColor = wantColor;
                }
                Triangle3d tri = new Triangle3d();
                Target.GetTriVertices(tid, ref tri.V0, ref tri.V1, ref tri.V2);
                Debug.WriteLine($"3DPOLY {tri.V0.CommaDelimited} {tri.V1.CommaDelimited} {tri.V2.CommaDelimited} {tri.V0.CommaDelimited} {v.CommaDelimited} ");
#endif
                if (IsInternal)
                {
                    containedT.SafeAdd(tid);
                }
            });
            if (rem == TriangleRemoval.contained)
            {
                MeshEditor.RemoveTriangles(Target, containedT.Result);
            }
            else if (rem == TriangleRemoval.external)
            {
                var ext = Target.TriangleIndices().Except(containedT.Result);
                MeshEditor.RemoveTriangles(Target, ext);
            }

            MeshEditor.RemoveTriangles(Target, removeAnywayT.Result);

            // [RMS] construct set of on-cut vertices? This is not
            // necessarily all boundary vertices...
            CutVertices = new List <int>();
            foreach (int vid in SegmentInsertVertices)
            {
                if (Target.IsVertex(vid))
                {
                    CutVertices.Add(vid);
                }
            }
        }
示例#21
0
        /// <summary>
        /// 1) Find intersection segments
        /// 2) sort onto existing input mesh vtx/edge/face
        /// </summary>
        void find_segments()
        {
            Dictionary <Vector3d, SegmentVtx> SegVtxMap = new Dictionary <Vector3d, SegmentVtx>();

            // find intersection segments
            // TODO: intersection polygons
            // TODO: do we need to care about intersection vertices?
            DMeshAABBTree3 targetSpatial = new DMeshAABBTree3(Target, true);
            DMeshAABBTree3 cutSpatial    = new DMeshAABBTree3(CutMesh, true);
            var            intersections = targetSpatial.FindAllIntersections(cutSpatial);

            // for each segment, for each vtx, determine if it is
            // at an existing vertex, on-edge, or in-face
            Segments = new IntersectSegment[intersections.Segments.Count];
            for (int i = 0; i < Segments.Length; ++i)
            {
                var              isect  = intersections.Segments[i];
                Vector3dTuple2   points = new Vector3dTuple2(isect.point0, isect.point1);
                IntersectSegment iseg   = new IntersectSegment()
                {
                    base_tid = isect.t0
                };
                Segments[i] = iseg;
                for (int j = 0; j < 2; ++j)
                {
                    Vector3d v = points[j];

                    // if this exact vtx coord has been seen, use same vtx
                    SegmentVtx sv;
                    if (SegVtxMap.TryGetValue(v, out sv))
                    {
                        iseg[j] = sv;
                        continue;
                    }
                    sv = new SegmentVtx()
                    {
                        v = v
                    };
                    SegVertices.Add(sv);
                    SegVtxMap[v] = sv;
                    iseg[j]      = sv;

                    // this vtx is tol-equal to input mesh vtx
                    int existing_v = find_existing_vertex(isect.point0);
                    if (existing_v >= 0)
                    {
                        sv.initial_type           = sv.type = 0;
                        sv.elem_id                = existing_v;
                        sv.vtx_id                 = existing_v;
                        VIDToSegVtxMap[sv.vtx_id] = sv;
                        continue;
                    }

                    Triangle3d tri = new Triangle3d();
                    Target.GetTriVertices(isect.t0, ref tri.V0, ref tri.V1, ref tri.V2);
                    Index3i tv = Target.GetTriangle(isect.t0);

                    // this vtx is tol-on input mesh edge
                    int on_edge_i = on_edge(ref tri, ref v);
                    if (on_edge_i >= 0)
                    {
                        sv.initial_type = sv.type = 1;
                        sv.elem_id      = Target.FindEdge(tv[on_edge_i], tv[(on_edge_i + 1) % 3]);
                        Util.gDevAssert(sv.elem_id != DMesh3.InvalidID);
                        add_edge_vtx(sv.elem_id, sv);
                        continue;
                    }

                    // otherwise contained in input mesh face
                    sv.initial_type = sv.type = 2;
                    sv.elem_id      = isect.t0;
                    add_face_vtx(sv.elem_id, sv);
                }
            }
        }
        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);
        }