예제 #1
0
        public void SelectEdgeTris(int eid)
        {
            Index2i et = Mesh.GetEdgeT(eid);

            add(et.a);
            if (et.b != DMesh3.InvalidID)
            {
                add(et.b);
            }
        }
        // returns true for both internal and mesh boundary edges
        // tid_in and tid_out are triangles 'in' and 'out' of set, respectively
        bool edge_is_boundary(int eid, ref int tid_in, ref int tid_out)
        {
            if (edges.Contains(eid) == false)
            {
                return(false);
            }

            tid_in = tid_out = DMesh3.InvalidID;
            Index2i et = Mesh.GetEdgeT(eid);

            if (et.b == DMesh3.InvalidID)           // boundary edge!
            {
                tid_in  = et.a;
                tid_out = et.b;
                return(true);
            }

            bool in0 = triangles[et.a];
            bool in1 = triangles[et.b];

            if (in0 != in1)
            {
                tid_in  = (in0) ? et.a : et.b;
                tid_out = (in0) ? et.b : et.a;
                return(true);
            }
            return(false);
        }
예제 #3
0
        /// <summary>
        /// for each on-edge vtx, we split the edge and then
        /// re-sort any of the vertices on that edge onto new edges
        /// </summary>
        void insert_edge_vertices()
        {
            while (EdgeVertices.Count > 0)
            {
                var pair = EdgeVertices.First();
                int eid  = pair.Key;
                List <SegmentVtx> edgeVerts = pair.Value;
                SegmentVtx        v         = edgeVerts[edgeVerts.Count - 1];
                edgeVerts.RemoveAt(edgeVerts.Count - 1);

                Index2i splitTris = Target.GetEdgeT(eid);

                DMesh3.EdgeSplitInfo splitInfo;
                MeshResult           result = Target.SplitEdge(eid, out splitInfo);
                if (result != MeshResult.Ok)
                {
                    throw new Exception("insert_edge_vertices: split failed!");
                }

                int new_v      = splitInfo.vNew;
                var splitEdges = new Index2i(eid, splitInfo.eNewBN);

                Target.SetVertex(new_v, v.v);
                v.vtx_id = new_v;
                VIDToSegVtxMap[v.vtx_id] = v;
                PointHash.InsertPoint(v.vtx_id, v.v);

                // remove this triangles vtx list because it is no longer valid
                EdgeVertices.Remove(eid);

                // update remaining verts
                foreach (SegmentVtx sv in edgeVerts)
                {
                    update_from_split(sv, splitEdges);
                    if (sv.type == 1)
                    {
                        add_edge_vtx(sv.elem_id, sv);
                    }
                }

                // track subfaces
                add_split_subfaces(splitTris, ref splitInfo);
            }
        }
예제 #4
0
        public static double OpeningAngleD(DMesh3 mesh, int eid)
        {
            Index2i et = mesh.GetEdgeT(eid);

            if (et[1] == DMesh3.InvalidID)
            {
                return(double.MaxValue);     // boundary edge!!
            }
            Vector3d n0 = mesh.GetTriNormal(et[0]);
            Vector3d n1 = mesh.GetTriNormal(et[1]);

            return(Vector3d.AngleD(n0, n1));
        }
예제 #5
0
 public void SelectBoundaryTriEdges(MeshFaceSelection triangles)
 {
     foreach (int tid in triangles)
     {
         Index3i te = Mesh.GetTriEdges(tid);
         for (int j = 0; j < 3; ++j)
         {
             Index2i et        = Mesh.GetEdgeT(te[j]);
             int     other_tid = (et.a == tid) ? et.b : et.a;
             if (triangles.IsSelected(other_tid) == false)
             {
                 add(te[j]);
             }
         }
     }
 }
예제 #6
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();
            }
        }
예제 #8
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);
                    }
                }
            }
        }
        // insert point at bary_coords inside tid. If point is at vtx, just use that vtx.
        // If it is on an edge, do an edge split. Otherwise poke face.
        int insert_corner_from_bary(int iCorner, int tid, Vector3d bary_coords,
                                    double bary_tol, double spatial_tol, out bool is_existing_v)
        {
            is_existing_v = false;
            Vector2d vInsert = Curve[iCorner];
            Index3i  tv      = Mesh.GetTriangle(tid);

            // handle cases where corner is on a vertex
            int cornerv = -1;

            if (bary_coords.x > 1 - bary_tol)
            {
                cornerv = tv.a;
            }
            else if (bary_coords.y > 1 - bary_tol)
            {
                cornerv = tv.b;
            }
            else if (bary_coords.z > 1 - bary_tol)
            {
                cornerv = tv.c;
            }
            if (cornerv != -1 && PointF(cornerv).Distance(vInsert) < spatial_tol)
            {
                is_existing_v = true;
                return(cornerv);
            }

            // handle cases where corner is on an edge
            int split_edge = -1;

            if (bary_coords.x < bary_tol)
            {
                split_edge = 1;
            }
            else if (bary_coords.y < bary_tol)
            {
                split_edge = 2;
            }
            else if (bary_coords.z < bary_tol)
            {
                split_edge = 0;
            }
            if (split_edge >= 0)
            {
                int eid = Mesh.GetTriEdge(tid, split_edge);

                Index2i   ev  = Mesh.GetEdgeV(eid);
                Segment2d seg = new Segment2d(PointF(ev.a), PointF(ev.b));
                if (seg.DistanceSquared(vInsert) < spatial_tol * spatial_tol)
                {
                    Index2i et = Mesh.GetEdgeT(eid);
                    spatial_remove_triangles(et.a, et.b);

                    DMesh3.EdgeSplitInfo split_info;
                    MeshResult           splitResult = Mesh.SplitEdge(eid, out split_info);
                    if (splitResult != MeshResult.Ok)
                    {
                        throw new Exception("MeshInsertUVPolyCurve.insert_corner_from_bary: edge split failed in case sum==2 - " + splitResult.ToString());
                    }
                    SetPointF(split_info.vNew, vInsert);

                    spatial_add_triangles(et.a, et.b);
                    spatial_add_triangles(split_info.eNewT2, split_info.eNewT3);

                    return(split_info.vNew);
                }
            }

            spatial_remove_triangle(tid);

            // otherwise corner is inside triangle
            DMesh3.PokeTriangleInfo pokeinfo;
            MeshResult result = Mesh.PokeTriangle(tid, bary_coords, out pokeinfo);

            if (result != MeshResult.Ok)
            {
                throw new Exception("MeshInsertUVPolyCurve.insert_corner_from_bary: face poke failed - " + result.ToString());
            }

            SetPointF(pokeinfo.new_vid, vInsert);

            spatial_add_triangle(tid);
            spatial_add_triangle(pokeinfo.new_t1);
            spatial_add_triangle(pokeinfo.new_t2);

            return(pokeinfo.new_vid);
        }
예제 #10
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);
        }
예제 #11
0
        public bool Insert()
        {
            OuterInsert = new MeshInsertUVPolyCurve(Mesh, Polygon.Outer);
            Util.gDevAssert(OuterInsert.Validate() == ValidationStatus.Ok);
            bool outerApplyOK = OuterInsert.Apply();

            if (outerApplyOK == false || OuterInsert.Loops.Count == 0)
            {
                return(false);
            }

            if (SimplifyInsertion)
            {
                OuterInsert.Simplify();
            }

            HoleInserts = new List <MeshInsertUVPolyCurve>(Polygon.Holes.Count);
            for (int hi = 0; hi < Polygon.Holes.Count; ++hi)
            {
                var insert = new MeshInsertUVPolyCurve(Mesh, Polygon.Holes[hi]);
                Util.gDevAssert(insert.Validate() == ValidationStatus.Ok);
                insert.Apply();
                if (SimplifyInsertion)
                {
                    insert.Simplify();
                }

                HoleInserts.Add(insert);
            }


            // find a triangle connected to loop that is inside the polygon
            //   [TODO] maybe we could be a bit more robust about this? at least
            //   check if triangle is too degenerate...
            int      seed_tri   = -1;
            EdgeLoop outer_loop = OuterInsert.Loops[0];

            for (int i = 0; i < outer_loop.EdgeCount; ++i)
            {
                if (!Mesh.IsEdge(outer_loop.Edges[i]))
                {
                    continue;
                }

                Index2i  et   = Mesh.GetEdgeT(outer_loop.Edges[i]);
                Vector3d ca   = Mesh.GetTriCentroid(et.a);
                bool     in_a = Polygon.Outer.Contains(ca.xy);
                Vector3d cb   = Mesh.GetTriCentroid(et.b);
                bool     in_b = Polygon.Outer.Contains(cb.xy);
                if (in_a && in_b == false)
                {
                    seed_tri = et.a;
                    break;
                }
                else if (in_b && in_a == false)
                {
                    seed_tri = et.b;
                    break;
                }
            }
            if (seed_tri == -1)
            {
                throw new Exception("MeshPolygonsInserter: could not find seed triangle!");
            }

            // make list of all outer & hole edges
            InsertedPolygonEdges = new HashSet <int>(outer_loop.Edges);
            foreach (var insertion in HoleInserts)
            {
                foreach (int eid in insertion.Loops[0].Edges)
                {
                    InsertedPolygonEdges.Add(eid);
                }
            }

            // flood-fill inside loop from seed triangle
            InteriorTriangles = new MeshFaceSelection(Mesh);
            InteriorTriangles.FloodFill(seed_tri, null, (eid) => { return(InsertedPolygonEdges.Contains(eid) == false); });

            return(true);
        }
        // insert point at bary_coords inside tid. If point is at vtx, just use that vtx.
        // If it is on an edge, do an edge split. Otherwise poke face.
        int insert_corner_from_bary(int iCorner, int tid, Vector3d bary_coords, double tol = MathUtil.ZeroTolerance)
        {
            Vector2d vInsert = Curve[iCorner];
            Index3i  tv      = Mesh.GetTriangle(tid);

            // handle cases where corner is on a vertex
            if (bary_coords.x > 1 - tol)
            {
                return(tv.a);
            }
            else if (bary_coords.y > 1 - tol)
            {
                return(tv.b);
            }
            else if (bary_coords.z > 1 - tol)
            {
                return(tv.c);
            }

            // handle cases where corner is on an edge
            int split_edge = -1;

            if (bary_coords.x < tol)
            {
                split_edge = 1;
            }
            else if (bary_coords.y < tol)
            {
                split_edge = 2;
            }
            else if (bary_coords.z < tol)
            {
                split_edge = 0;
            }
            if (split_edge >= 0)
            {
                int eid = Mesh.GetTriEdge(tid, split_edge);

                Index2i ev = Mesh.GetEdgeT(eid);
                spatial_remove_triangles(ev.a, ev.b);

                DMesh3.EdgeSplitInfo split_info;
                MeshResult           splitResult = Mesh.SplitEdge(eid, out split_info);
                if (splitResult != MeshResult.Ok)
                {
                    throw new Exception("MeshInsertUVPolyCurve.insert_corner_from_bary: edge split failed in case sum==2 - " + splitResult.ToString());
                }
                SetPointF(split_info.vNew, vInsert);

                spatial_add_triangles(ev.a, ev.b);
                spatial_add_triangles(split_info.eNewT2, split_info.eNewT3);

                return(split_info.vNew);
            }

            spatial_remove_triangle(tid);

            // otherwise corner is inside triangle
            DMesh3.PokeTriangleInfo pokeinfo;
            MeshResult result = Mesh.PokeTriangle(tid, bary_coords, out pokeinfo);

            if (result != MeshResult.Ok)
            {
                throw new Exception("MeshInsertUVPolyCurve.insert_corner_from_bary: face poke failed - " + result.ToString());
            }

            spatial_add_triangle(tid);
            spatial_add_triangle(pokeinfo.new_t1);
            spatial_add_triangle(pokeinfo.new_t2);

            SetPointF(pokeinfo.new_vid, vInsert);
            return(pokeinfo.new_vid);
        }