Esempio n. 1
0
        /// <summary>
        /// split input mesh into submeshes based on group ID
        /// **does not** separate disconnected components w/ same group ID
        /// </summary>
        public static DMesh3[] SeparateMeshByGroups(DMesh3 mesh, out int[] groupIDs)
        {
            Dictionary <int, List <int> > meshes = new Dictionary <int, List <int> >();

            foreach (int tid in mesh.TriangleIndices())
            {
                int        gid = mesh.GetTriangleGroup(tid);
                List <int> tris;
                if (meshes.TryGetValue(gid, out tris) == false)
                {
                    tris        = new List <int>();
                    meshes[gid] = tris;
                }
                tris.Add(tid);
            }

            DMesh3[] result = new DMesh3[meshes.Count];
            groupIDs = new int[meshes.Count];
            int k = 0;

            foreach (var pair in meshes)
            {
                groupIDs[k] = pair.Key;
                List <int> tri_list = pair.Value;
                result[k++] = DSubmesh3.QuickSubmesh(mesh, tri_list);
            }

            return(result);
        }
Esempio n. 2
0
        /// <summary>
        /// Apply LaplacianMeshSmoother to subset of mesh triangles.
        /// border of subset always has soft constraint with borderWeight,
        /// but is then snapped back to original vtx pos after solve.
        /// nConstrainLoops inner loops are also soft-constrained, with weight falloff via square roots.
        /// interiorWeight is soft constraint added to all vertices
        /// </summary>
        public static void RegionSmooth(DMesh3 mesh, IEnumerable <int> triangles, int nConstrainLoops,
                                        double borderWeight = 10.0, double interiorWeight = 0.0)
        {
            RegionOperator        region     = new RegionOperator(mesh, triangles);
            DSubmesh3             submesh    = region.Region;
            DMesh3                smoothMesh = submesh.SubMesh;
            LaplacianMeshSmoother smoother   = new LaplacianMeshSmoother(smoothMesh);

            // soft constraint on all interior vertices, if requested
            if (interiorWeight > 0)
            {
                foreach (int vid in smoothMesh.VertexIndices())
                {
                    smoother.SetConstraint(vid, smoothMesh.GetVertex(vid), interiorWeight, false);
                }
            }

            // now constrain borders
            double w = borderWeight;

            HashSet <int> constrained = (region.Region.BaseBorderV.Count > 0) ? new HashSet <int>() : null;

            foreach (int base_vid in region.Region.BaseBorderV)
            {
                int sub_vid = submesh.BaseToSubV[base_vid];
                smoother.SetConstraint(sub_vid, smoothMesh.GetVertex(sub_vid), w, true);
                if (constrained != null)
                {
                    constrained.Add(sub_vid);
                }
            }

            if (constrained.Count > 0)
            {
                w = Math.Sqrt(w);
                for (int k = 0; k < nConstrainLoops; ++k)
                {
                    HashSet <int> next_layer = new HashSet <int>();

                    foreach (int sub_vid in constrained)
                    {
                        foreach (int nbr_vid in smoothMesh.VtxVerticesItr(sub_vid))
                        {
                            if (constrained.Contains(nbr_vid) == false)
                            {
                                smoother.SetConstraint(nbr_vid, smoothMesh.GetVertex(nbr_vid), w, false);
                                next_layer.Add(nbr_vid);
                            }
                        }
                    }

                    constrained.UnionWith(next_layer);
                    w = Math.Sqrt(w);
                }
            }


            smoother.SolveAndUpdateMesh();
            region.BackPropropagateVertices(true);
        }
Esempio n. 3
0
        public RegionOperator(DMesh3 mesh, int[] regionTris)
        {
            BaseMesh = mesh;
            Region   = new DSubmesh3(mesh, regionTris);
            Region.ComputeBoundaryInfo(regionTris);

            cur_base_tris = (int[])regionTris.Clone();
        }
Esempio n. 4
0
        /// <summary>
        /// Automatically construct fastest projection target for region of mesh
        /// </summary>
        public static MeshProjectionTarget Auto(DMesh3 mesh, IEnumerable <int> triangles, int nExpandRings = 5)
        {
            var targetRegion = new MeshFaceSelection(mesh);

            targetRegion.Select(triangles);
            targetRegion.ExpandToOneRingNeighbours(nExpandRings);
            var submesh = new DSubmesh3(mesh, targetRegion);

            return(new MeshProjectionTarget(submesh.SubMesh));
        }
        /// <summary>
        /// extract largest shell of meshIn
        /// </summary>
        public static DMesh3 LargestT(DMesh3 meshIn)
        {
            var c = new MeshConnectedComponents(meshIn);

            c.FindConnectedT();
            c.SortByCount(false);
            var submesh = new DSubmesh3(meshIn, c.Components[0].Indices);

            return(submesh.SubMesh);
        }
Esempio n. 6
0
        public RegionOperator(DMesh3 mesh, IEnumerable <int> regionTris)
        {
            BaseMesh = mesh;
            Region   = new DSubmesh3(mesh, regionTris);
            int count = regionTris.Count();

            Region.ComputeBoundaryInfo(regionTris, count);

            cur_base_tris = regionTris.ToArray();
        }
        public RegionOperator(DMesh3 mesh, int[] regionTris, Action <DSubmesh3> submeshConfigF = null)
        {
            BaseMesh = mesh;
            Region   = new DSubmesh3(mesh);
            if (submeshConfigF != null)
            {
                submeshConfigF(Region);
            }
            Region.Compute(regionTris);
            Region.ComputeBoundaryInfo(regionTris);

            cur_base_tris = (int[])regionTris.Clone();
        }
Esempio n. 8
0
        public RegionRemesher(DMesh3 mesh, int[] regionTris)
        {
            BaseMesh = mesh;
            Region   = new DSubmesh3(mesh, regionTris);
            Region.ComputeBoundaryInfo(regionTris);
            base.mesh = Region.SubMesh;

            cur_base_tris = (int[])regionTris.Clone();

            // constrain region-boundary edges
            bdry_constraints = new MeshConstraints();
            MeshConstraintUtil.FixSubmeshBoundaryEdges(bdry_constraints, Region);
            SetExternalConstraints(bdry_constraints);
        }
        public RegionOperator(DMesh3 mesh, IEnumerable <int> regionTris, Action <DSubmesh3> submeshConfigF = null)
        {
            BaseMesh = mesh;
            Region   = new DSubmesh3(mesh);
            if (submeshConfigF != null)
            {
                submeshConfigF(Region);
            }
            Region.Compute(regionTris);
            int count = regionTris.Count();

            Region.ComputeBoundaryInfo(regionTris, count);

            cur_base_tris = regionTris.ToArray();
        }
Esempio n. 10
0
        // loop through submesh border edges on basemesh, map to submesh, and
        // pin those edges / vertices
        public static void FixSubmeshBoundaryEdges(MeshConstraints cons, DSubmesh3 sub)
        {
            Debug.Assert(sub.BaseBorderE != null);
            foreach (int base_eid in sub.BaseBorderE)
            {
                Index2i base_ev = sub.BaseMesh.GetEdgeV(base_eid);
                Index2i sub_ev  = sub.MapVerticesToSubmesh(base_ev);
                int     sub_eid = sub.SubMesh.FindEdge(sub_ev.a, sub_ev.b);
                Debug.Assert(sub_eid != DMesh3.InvalidID);
                Debug.Assert(sub.SubMesh.IsBoundaryEdge(sub_eid));

                cons.SetOrUpdateEdgeConstraint(sub_eid, EdgeConstraint.FullyConstrained);
                cons.SetOrUpdateVertexConstraint(sub_ev.a, VertexConstraint.Pinned);
                cons.SetOrUpdateVertexConstraint(sub_ev.b, VertexConstraint.Pinned);
            }
        }
Esempio n. 11
0
        public RegionRemesher(DMesh3 mesh, IEnumerable <int> regionTris)
        {
            BaseMesh = mesh;
            Region   = new DSubmesh3(mesh, regionTris);
            int count = regionTris.Count();

            Region.ComputeBoundaryInfo(regionTris, count);
            base.mesh = Region.SubMesh;

            cur_base_tris = regionTris.ToArray();

            // constrain region-boundary edges
            bdry_constraints = new MeshConstraints();
            MeshConstraintUtil.FixSubmeshBoundaryEdges(bdry_constraints, Region);
            SetExternalConstraints(bdry_constraints);
        }
Esempio n. 12
0
        /// <summary>
        /// Separate input mesh into disconnected shells
        /// </summary>
        public static DMesh3[] Separate(DMesh3 meshIn)
        {
            MeshConnectedComponents c = new MeshConnectedComponents(meshIn);

            c.FindConnectedT();

            DMesh3[] result = new DMesh3[c.Components.Count];

            int ri = 0;

            foreach (Component comp in c.Components)
            {
                DSubmesh3 submesh = new DSubmesh3(meshIn, comp.Indices);
                result[ri++] = submesh.SubMesh;
            }

            return(result);
        }
Esempio n. 13
0
        public static DMesh3 QuickSubmesh(DMesh3 mesh, int[] triangles)
        {
            DSubmesh3 submesh = new DSubmesh3(mesh, triangles);

            return(submesh.SubMesh);
        }
Esempio n. 14
0
        // Assumption here is that Submesh has been modified, but boundary loop has
        // been preserved, and that old submesh has already been removed from this mesh.
        // So, we just have to append new vertices and then rewrite triangles
        // If new_tris or new_verts is non-null, we will return this info.
        // new_tris should be set to TriangleCount (ie it is not necessarily a map)
        // For new_verts, if we used an existing bdry vtx instead, we set the value to -(existing_index+1),
        // otherwise the value is new_index (+1 is to handle 0)
        //
        // Returns true if submesh successfully inserted, false if any triangles failed
        // (which happens if triangle would result in non-manifold mesh)
        public bool ReinsertSubmesh(DSubmesh3 sub, ref int[] new_tris, out IndexMap SubToNewV)
        {
            if (sub.BaseBorderV == null)
            {
                throw new Exception("MeshEditor.ReinsertSubmesh: Submesh does not have required boundary info. Call ComputeBoundaryInfo()!");
            }

            DMesh3 submesh = sub.SubMesh;
            bool   bAllOK  = true;

            IndexFlagSet done_v = new IndexFlagSet(submesh.MaxVertexID, submesh.TriangleCount / 2);

            SubToNewV = new IndexMap(submesh.MaxVertexID, submesh.VertexCount);

            int nti = 0;
            int NT  = submesh.MaxTriangleID;

            for (int ti = 0; ti < NT; ++ti)
            {
                if (submesh.IsTriangle(ti) == false)
                {
                    continue;
                }

                Index3i sub_t = submesh.GetTriangle(ti);
                int     gid   = submesh.GetTriangleGroup(ti);

                Index3i new_t = Index3i.Zero;
                for (int j = 0; j < 3; ++j)
                {
                    int sub_v = sub_t[j];
                    int new_v = -1;
                    if (done_v[sub_v] == false)
                    {
                        // first check if this is a boundary vtx on submesh and maps to a bdry vtx on base mesh
                        if (submesh.vertex_is_boundary(sub_v))
                        {
                            int base_v = (sub_v < sub.SubToBaseV.size) ? sub.SubToBaseV[sub_v] : -1;
                            if (base_v >= 0 && Mesh.IsVertex(base_v) && sub.BaseBorderV[base_v] == true)
                            {
                                // [RMS] this should always be true, but assert in tests to find out
                                Debug.Assert(Mesh.vertex_is_boundary(base_v));
                                if (Mesh.vertex_is_boundary(base_v))
                                {
                                    new_v = base_v;
                                }
                            }
                        }

                        // if that didn't happen, append new vtx
                        if (new_v == -1)
                        {
                            new_v = Mesh.AppendVertex(submesh, sub_v);
                        }

                        SubToNewV[sub_v] = new_v;
                        done_v[sub_v]    = true;
                    }
                    else
                    {
                        new_v = SubToNewV[sub_v];
                    }

                    new_t[j] = new_v;
                }

                Debug.Assert(Mesh.FindTriangle(new_t.a, new_t.b, new_t.c) == DMesh3.InvalidID);

                int new_tid = Mesh.AppendTriangle(new_t, gid);
                Debug.Assert(new_tid != DMesh3.InvalidID && new_tid != DMesh3.NonManifoldID);
                if (!Mesh.IsTriangle(new_tid))
                {
                    bAllOK = false;
                }

                if (new_tris != null)
                {
                    new_tris[nti++] = new_tid;
                }
            }

            return(bAllOK);
        }
        /// <summary>
        /// Apply LaplacianMeshSmoother to subset of mesh triangles.
        /// border of subset always has soft constraint with borderWeight,
        /// but is then snapped back to original vtx pos after solve.
        /// nConstrainLoops inner loops are also soft-constrained, with weight falloff via square roots (defines continuity)
        /// interiorWeight is soft constraint added to all vertices
        /// </summary>
        public static void RegionSmooth(DMesh3 mesh, IEnumerable <int> triangles,
                                        int nConstrainLoops,
                                        int nIncludeExteriorRings,
                                        bool bPreserveExteriorRings,
                                        double borderWeight = 10.0, double interiorWeight = 0.0)
        {
            HashSet <int> fixedVerts = new HashSet <int>();

            if (nIncludeExteriorRings > 0)
            {
                MeshFaceSelection expandTris = new MeshFaceSelection(mesh);
                expandTris.Select(triangles);
                if (bPreserveExteriorRings)
                {
                    MeshEdgeSelection bdryEdges = new MeshEdgeSelection(mesh);
                    bdryEdges.SelectBoundaryTriEdges(expandTris);
                    expandTris.ExpandToOneRingNeighbours(nIncludeExteriorRings);
                    MeshVertexSelection startVerts = new MeshVertexSelection(mesh);
                    startVerts.SelectTriangleVertices(triangles);
                    startVerts.DeselectEdges(bdryEdges);
                    MeshVertexSelection expandVerts = new MeshVertexSelection(mesh, expandTris);
                    foreach (int vid in expandVerts)
                    {
                        if (startVerts.IsSelected(vid) == false)
                        {
                            fixedVerts.Add(vid);
                        }
                    }
                }
                else
                {
                    expandTris.ExpandToOneRingNeighbours(nIncludeExteriorRings);
                }
                triangles = expandTris;
            }

            RegionOperator        region     = new RegionOperator(mesh, triangles);
            DSubmesh3             submesh    = region.Region;
            DMesh3                smoothMesh = submesh.SubMesh;
            LaplacianMeshSmoother smoother   = new LaplacianMeshSmoother(smoothMesh);

            // map fixed verts to submesh
            HashSet <int> subFixedVerts = new HashSet <int>();

            foreach (int base_vid in fixedVerts)
            {
                subFixedVerts.Add(submesh.MapVertexToSubmesh(base_vid));
            }

            // constrain borders
            double w = borderWeight;

            HashSet <int> constrained = (submesh.BaseBorderV.Count > 0) ? new HashSet <int>() : null;

            foreach (int base_vid in submesh.BaseBorderV)
            {
                int sub_vid = submesh.BaseToSubV[base_vid];
                smoother.SetConstraint(sub_vid, smoothMesh.GetVertex(sub_vid), w, true);
                if (constrained != null)
                {
                    constrained.Add(sub_vid);
                }
            }

            if (constrained.Count > 0)
            {
                w = Math.Sqrt(w);
                for (int k = 0; k < nConstrainLoops; ++k)
                {
                    HashSet <int> next_layer = new HashSet <int>();

                    foreach (int sub_vid in constrained)
                    {
                        foreach (int nbr_vid in smoothMesh.VtxVerticesItr(sub_vid))
                        {
                            if (constrained.Contains(nbr_vid) == false)
                            {
                                if (smoother.IsConstrained(nbr_vid) == false)
                                {
                                    smoother.SetConstraint(nbr_vid, smoothMesh.GetVertex(nbr_vid), w, subFixedVerts.Contains(nbr_vid));
                                }
                                next_layer.Add(nbr_vid);
                            }
                        }
                    }

                    constrained.UnionWith(next_layer);
                    w = Math.Sqrt(w);
                }
            }

            // soft constraint on all interior vertices, if requested
            if (interiorWeight > 0)
            {
                foreach (int vid in smoothMesh.VertexIndices())
                {
                    if (smoother.IsConstrained(vid) == false)
                    {
                        smoother.SetConstraint(vid, smoothMesh.GetVertex(vid), interiorWeight, subFixedVerts.Contains(vid));
                    }
                }
            }
            else if (subFixedVerts.Count > 0)
            {
                foreach (int vid in subFixedVerts)
                {
                    if (smoother.IsConstrained(vid) == false)
                    {
                        smoother.SetConstraint(vid, smoothMesh.GetVertex(vid), 0, true);
                    }
                }
            }

            smoother.SolveAndUpdateMesh();
            region.BackPropropagateVertices(true);
        }