/// <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);
        }
        // assumes PathT is contains set of triangles
        // that are fully connected, ie a flood-fill cannot escape!
        void find_interior_from_tris()
        {
            var pathNbrs = new MeshFaceSelection(Mesh);

            pathNbrs.Select(PathT);
            pathNbrs.ExpandToOneRingNeighbours();
            pathNbrs.Deselect(PathT);

            var connected = new MeshConnectedComponents(Mesh);

            connected.FilterSet = pathNbrs;
            connected.FindConnectedT();
            int N = connected.Count;

            if (N < 2)
            {
                throw new Exception("MeshFacesFromLoop.find_interior: only found one connected component!");
            }

            // only consider 2 largest. somehow we are sometimes getting additional
            // "outside" components, and if we do growing from there, it covers whole mesh??
            connected.SortByCount(false);
            N = 2;

            var selections = new MeshFaceSelection[N];

            bool[] done = new bool[N];
            for (int i = 0; i < N; ++i)
            {
                selections[i] = new MeshFaceSelection(Mesh);
                selections[i].Select(connected.Components[i].Indices);
                done[i] = false;
            }

            var border_tris          = new HashSet <int>(PathT);
            Func <int, bool> borderF = (tid) => { return(border_tris.Contains(tid) == false); };

            // 'largest' flood fill is expensive...if we had a sense of tooth size we could reduce cost?
            for (int i = 0; i < N; ++i)
            {
                selections[i].FloodFill(connected.Components[i].Indices, borderF);
            }
            Array.Sort(selections, (a, b) => { return(a.Count.CompareTo(b.Count)); });
            InteriorT = new List <int>(selections[0]);
        }
Example #3
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);
        }
        public static GenusResult Genus(DMesh3 mesh)
        {
            GenusResult result = new GenusResult()
            {
                Valid = false, Genus = -1
            };

            if (!mesh.CachedIsClosed)
            {
                result.HasBoundary = true;
                return(result);
            }

            MeshConnectedComponents compT = new MeshConnectedComponents(mesh);

            compT.FindConnectedT();
            if (compT.Count > 1)
            {
                result.MultipleConnectedComponents = true;
                return(result);
            }
            int isolated_verts = 0;

            foreach (int vid in mesh.VertexIndices())
            {
                if (mesh.IsBowtieVertex(vid))
                {
                    result.HasBowtieVertices = true;
                    return(result);
                }
                if (mesh.GetVtxTriangleCount(vid) == 0)
                {
                    isolated_verts++;
                }
            }

            int V = mesh.VertexCount - isolated_verts;
            int F = mesh.TriangleCount;
            int E = mesh.EdgeCount;

            result.Genus = (2 - (V + F - E)) / 2;
            result.Valid = true;
            return(result);
        }
Example #5
0
        /// <summary>
        /// Remove any connected components with volume &lt; min_volume area lt; min_area
        /// </summary>
        public int RemoveSmallComponents(double min_volume, double min_area)
        {
            MeshConnectedComponents C = new MeshConnectedComponents(Mesh);

            C.FindConnectedT();
            if (C.Count == 1)
            {
                return(0);
            }
            int nRemoved = 0;

            foreach (var comp in C.Components)
            {
                Vector2d vol_area = MeshMeasurements.VolumeArea(Mesh, comp.Indices, Mesh.GetVertex);
                if (vol_area.x < min_volume || vol_area.y < min_area)
                {
                    MeshEditor.RemoveTriangles(Mesh, comp.Indices);
                    nRemoved++;
                }
            }
            return(nRemoved);
        }
Example #6
0
        public virtual bool Trim()
        {
            if (Spatial == null)
            {
                Spatial = new DMeshAABBTree3(new DMesh3(Mesh, false, MeshComponents.None));
                Spatial.Build();
            }

            if (seed_tri == -1)
            {
                seed_tri = Spatial.FindNearestTriangle(seed_pt);
            }

            var loop = new MeshFacesFromLoop(Mesh, TrimLine, Spatial, seed_tri);

            MeshFaceSelection selection = loop.ToSelection();

            selection.LocalOptimize(true, true);
            var editor = new MeshEditor(Mesh);

            editor.RemoveTriangles(selection, true);

            var components = new MeshConnectedComponents(Mesh);

            components.FindConnectedT();
            if (components.Count > 1)
            {
                int keep = components.LargestByCount;
                for (int i = 0; i < components.Count; ++i)
                {
                    if (i != keep)
                    {
                        editor.RemoveTriangles(components[i].Indices, true);
                    }
                }
            }
            editor.RemoveAllBowtieVertices(true);

            var  loops   = new MeshBoundaryLoops(Mesh);
            bool loopsOK = false;

            try
            {
                loopsOK = loops.Compute();
            }
            catch (Exception)
            {
                return(false);
            }
            if (!loopsOK)
            {
                return(false);
            }


            // [TODO] to support trimming mesh w/ existing holes, we need to figure out which
            // loop we created in RemoveTriangles above!
            if (loops.Count > 1)
            {
                return(false);
            }

            int[] loopVerts = loops[0].Vertices;

            var borderTris = new MeshFaceSelection(Mesh);

            borderTris.SelectVertexOneRings(loopVerts);
            borderTris.ExpandToOneRingNeighbours(RemeshBorderRings);

            var remesh = new RegionRemesher(Mesh, borderTris.ToArray());

            remesh.Region.MapVerticesToSubmesh(loopVerts);

            double target_len = TargetEdgeLength;

            if (target_len <= 0)
            {
                double mine, maxe, avge;
                MeshQueries.EdgeLengthStatsFromEdges(Mesh, loops[0].Edges, out mine, out maxe, out avge);
                target_len = avge;
            }

            var meshTarget = new MeshProjectionTarget(Spatial.Mesh, Spatial);

            remesh.SetProjectionTarget(meshTarget);
            remesh.SetTargetEdgeLength(target_len);
            remesh.SmoothSpeedT = SmoothingAlpha;

            var curveTarget = new DCurveProjectionTarget(TrimLine);
            var multiTarget = new SequentialProjectionTarget(curveTarget, meshTarget);

            int set_id = 3;

            MeshConstraintUtil.ConstrainVtxLoopTo(remesh, loopVerts, multiTarget, set_id);

            for (int i = 0; i < RemeshRounds; ++i)
            {
                remesh.BasicRemeshPass();
            }

            remesh.BackPropropagate();

            // [TODO] output loop somehow...use MeshConstraints.FindConstrainedEdgesBySetID(set_id)...

            return(true);
        }         // Trim()