Ejemplo n.º 1
0
 public void SelectTriangleEdges(IEnumerable <int> triangles)
 {
     foreach (int tid in triangles)
     {
         Index3i et = Mesh.GetTriEdges(tid);
         add(et.a); add(et.b); add(et.c);
     }
 }
Ejemplo n.º 2
0
 public static void TrianglesToEdges(DMesh3 mesh, HashSet <int> triangles, HashSet <int> edges)
 {
     foreach (int tid in triangles)
     {
         Index3i te = mesh.GetTriEdges(tid);
         edges.Add(te.a); edges.Add(te.b); edges.Add(te.c);
     }
 }
Ejemplo n.º 3
0
        public void ComputeBoundaryInfo(IEnumerable <int> triangles, int tri_count)
        {
            // set of base-mesh triangles that are in submesh
            IndexFlagSet sub_tris = new IndexFlagSet(BaseMesh.MaxTriangleID, tri_count);

            foreach (int ti in triangles)
            {
                sub_tris[ti] = true;
            }

            BaseBorderV   = new IndexHashSet();
            BaseBorderE   = new IndexHashSet();
            BaseBoundaryE = new IndexHashSet();

            // Iterate through edges in submesh roi on base mesh. If
            // one of the tris of the edge is not in submesh roi, then this
            // is a boundary edge.
            //
            // (edge iteration via triangle iteration processes each internal edge twice...)
            foreach (int ti in triangles)
            {
                Index3i tedges = BaseMesh.GetTriEdges(ti);
                for (int j = 0; j < 3; ++j)
                {
                    int     eid  = tedges[j];
                    Index2i tris = BaseMesh.GetEdgeT(eid);
                    if (tris.b == DMesh3.InvalidID || sub_tris[tris.a] != sub_tris[tris.b])
                    {
                        if (tris.b == DMesh3.InvalidID)
                        {
                            BaseBoundaryE[eid] = true;
                        }
                        else
                        {
                            BaseBorderE[eid] = true;
                        }

                        Index2i ve = BaseMesh.GetEdgeV(eid);
                        BaseBorderV[ve.a] = true;
                        BaseBorderV[ve.b] = true;
                    }
                }
            }
        }
        public MeshRegionBoundaryLoops(DMesh3 mesh, int[] RegionTris, bool bAutoCompute = true)
        {
            this.Mesh = mesh;

            // make flag set for included triangles
            triangles = new IndexFlagSet(mesh.MaxTriangleID, RegionTris.Length);
            for (int i = 0; i < RegionTris.Length; ++i)
            {
                triangles[RegionTris[i]] = true;
            }

            // make flag set for included edges
            // NOTE: this currently processes non-boundary-edges twice. Could
            // avoid w/ another IndexFlagSet, but the check is inexpensive...
            edges = new IndexFlagSet(mesh.MaxEdgeID, RegionTris.Length);
            for (int i = 0; i < RegionTris.Length; ++i)
            {
                int     tid = RegionTris[i];
                Index3i te  = Mesh.GetTriEdges(tid);
                for (int j = 0; j < 3; ++j)
                {
                    int eid = te[j];
                    if (!edges.Contains(eid))
                    {
                        Index2i et = mesh.GetEdgeT(eid);
                        if (et.b == DMesh3.InvalidID || triangles[et.a] != triangles[et.b])
                        {
                            edges.Add(eid);
                        }
                    }
                }
            }


            if (bAutoCompute)
            {
                Compute();
            }
        }
Ejemplo n.º 5
0
        // convert face selection to edge selection. Require at least minCount tris of edge to be selected
        public MeshEdgeSelection(DMesh3 mesh, MeshFaceSelection convertT, int minCount = 1) : this(mesh)
        {
            minCount = MathUtil.Clamp(minCount, 1, 2);

            if (minCount == 1)
            {
                foreach (int tid in convertT)
                {
                    Index3i te = mesh.GetTriEdges(tid);
                    add(te.a); add(te.b); add(te.c);
                }
            }
            else
            {
                foreach (int eid in mesh.EdgeIndices())
                {
                    Index2i et = mesh.GetEdgeT(eid);
                    if (convertT.IsSelected(et.a) && convertT.IsSelected(et.b))
                    {
                        add(eid);
                    }
                }
            }
        }
Ejemplo n.º 6
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;
        }
Ejemplo n.º 7
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;
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Disconnect the given triangles from their neighbours, by duplicating "boundary" vertices, ie
        /// vertices on edges for which one triangle is in-set and the other is not.
        /// If bComputeEdgePairs is true, we return list of old/new edge pairs (useful for stitching)
        /// [TODO] currently boundary-edge behaviour is to *not* duplicate boundary verts
        /// </summary>
        public bool SeparateTriangles(IEnumerable <int> triangles, bool bComputeEdgePairs, out List <Index2i> EdgePairs)
        {
            HashSet <int>         in_set    = new HashSet <int>(triangles);
            Dictionary <int, int> VertexMap = new Dictionary <int, int>();

            EdgePairs = null;
            HashSet <int>  edges        = null;
            List <Index2i> OldEdgeVerts = null;

            if (bComputeEdgePairs)
            {
                EdgePairs    = new List <Index2i>();
                edges        = new HashSet <int>();
                OldEdgeVerts = new List <Index2i>();
            }

            // duplicate vertices on edges that are on boundary of triangles roi
            foreach (int tid in triangles)
            {
                Index3i te = Mesh.GetTriEdges(tid);

                for (int j = 0; j < 3; ++j)
                {
                    Index2i et = Mesh.GetEdgeT(te[j]);
                    // [TODO] what about behavior where we want to also duplicate boundary verts??
                    if (et.b == DMesh3.InvalidID || (et.a == tid && in_set.Contains(et.b)) || (et.b == tid && in_set.Contains(et.a)))
                    {
                        te[j] = -1;
                    }
                }

                for (int j = 0; j < 3; ++j)
                {
                    if (te[j] == -1)
                    {
                        continue;
                    }
                    Index2i ev = Mesh.GetEdgeV(te[j]);
                    if (VertexMap.ContainsKey(ev.a) == false)
                    {
                        VertexMap[ev.a] = Mesh.AppendVertex(Mesh, ev.a);
                    }
                    if (VertexMap.ContainsKey(ev.b) == false)
                    {
                        VertexMap[ev.b] = Mesh.AppendVertex(Mesh, ev.b);
                    }

                    if (bComputeEdgePairs && edges.Contains(te[j]) == false)
                    {
                        edges.Add(te[j]);
                        OldEdgeVerts.Add(ev);
                        EdgePairs.Add(new Index2i(te[j], -1));
                    }
                }
            }

            // update triangles
            foreach (int tid in triangles)
            {
                Index3i tv     = Mesh.GetTriangle(tid);
                Index3i tv_new = tv;
                for (int j = 0; j < 3; ++j)
                {
                    int newv;
                    if (VertexMap.TryGetValue(tv[j], out newv))
                    {
                        tv_new[j] = newv;
                    }
                }
                if (tv_new != tv)
                {
                    Mesh.SetTriangle(tid, tv_new);
                }
            }

            if (bComputeEdgePairs)
            {
                for (int k = 0; k < EdgePairs.Count; ++k)
                {
                    Index2i old_ev  = OldEdgeVerts[k];
                    int     new_a   = VertexMap[old_ev.a];
                    int     new_b   = VertexMap[old_ev.b];
                    int     new_eid = Mesh.FindEdge(new_a, new_b);
                    Util.gDevAssert(new_eid != DMesh3.InvalidID);
                    EdgePairs[k] = new Index2i(EdgePairs[k].a, new_eid);
                }
            }

            return(true);
        }