Пример #1
0
        // convert vertex selection to face selection. Require at least minCount verts of
        // tri to be selected (valid values are 1,2,3)
        public MeshFaceSelection(DMesh3 mesh, MeshVertexSelection convertV, int minCount = 3) : this(mesh)
        {
            minCount = MathUtil.Clamp(minCount, 1, 3);

            foreach (int tid in mesh.TriangleIndices())
            {
                Index3i tri = mesh.GetTriangle(tid);

                if (minCount == 1)
                {
                    if (convertV.IsSelected(tri.a) || convertV.IsSelected(tri.b) || convertV.IsSelected(tri.c))
                    {
                        add(tid);
                    }
                }
                else if (minCount == 3)
                {
                    if (convertV.IsSelected(tri.a) && convertV.IsSelected(tri.b) && convertV.IsSelected(tri.c))
                    {
                        add(tid);
                    }
                }
                else
                {
                    int n = (convertV.IsSelected(tri.a) ? 1 : 0) +
                            (convertV.IsSelected(tri.b) ? 1 : 0) +
                            (convertV.IsSelected(tri.c) ? 1 : 0);
                    if (n >= minCount)
                    {
                        add(tid);
                    }
                }
            }
        }
Пример #2
0
        // convert vertex selection to edge selection. Require at least minCount verts of edge to be selected
        public MeshEdgeSelection(DMesh3 mesh, MeshVertexSelection convertV, int minCount = 2) : this(mesh)
        {
            minCount = MathUtil.Clamp(minCount, 1, 2);

            // [TODO] if minCount == 1, and convertV is small, it is faster to iterate over convertV!!

            foreach (int eid in mesh.EdgeIndices())
            {
                Index2i ev = mesh.GetEdgeV(eid);
                int     n  = (convertV.IsSelected(ev.a) ? 1 : 0) +
                             (convertV.IsSelected(ev.b) ? 1 : 0);
                if (n >= minCount)
                {
                    add(eid);
                }
            }
        }
        /// <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);
        }