Exemple #1
0
        /// <summary>
        /// for each vertex of input triangle set, select vertex if all
        /// one-ring triangles are contained in triangle set (ie vertex is not on boundary of triangle set).
        /// </summary>
        public void SelectInteriorVertices(MeshFaceSelection triangles)
        {
            var borderv = new HashSet <int>();

            foreach (int tid in triangles)
            {
                Index3i tv = Mesh.GetTriangle(tid);
                for (int j = 0; j < 3; ++j)
                {
                    int vid = tv[j];
                    if (Selected.Contains(vid) || borderv.Contains(vid))
                    {
                        continue;
                    }

                    bool full_ring = true;
                    foreach (int ring_tid in Mesh.VtxTrianglesItr(vid))
                    {
                        if (triangles.IsSelected(ring_tid) == false)
                        {
                            full_ring = false;
                            break;
                        }
                    }
                    if (full_ring)
                    {
                        add(vid);
                    }
                    else
                    {
                        borderv.Add(vid);
                    }
                }
            }
        }
Exemple #2
0
        // smooths embedded loop in mesh, by first smoothing edge loop and then
        // smoothing vertex neighbourhood
        // [TODO] geodesic nbrhoold instead of # of rings
        // [TODO] reprojection?
        public static void smooth_loop(DMesh3 mesh, EdgeLoop loop, int nRings)
        {
            MeshFaceSelection roi_t = new MeshFaceSelection(mesh);

            roi_t.SelectVertexOneRings(loop.Vertices);
            for (int i = 0; i < nRings; ++i)
            {
                roi_t.ExpandToOneRingNeighbours();
            }
            roi_t.LocalOptimize(true, true);

            MeshVertexSelection roi_v = new MeshVertexSelection(mesh);

            roi_v.SelectTriangleVertices(roi_t.ToArray());
            roi_v.Deselect(loop.Vertices);

            MeshLoopSmooth loop_smooth = new MeshLoopSmooth(mesh, loop);

            loop_smooth.Rounds = 1;

            MeshIterativeSmooth mesh_smooth = new MeshIterativeSmooth(mesh, roi_v.ToArray(), true);

            mesh_smooth.Rounds = 1;

            for (int i = 0; i < 10; ++i)
            {
                loop_smooth.Smooth();
                mesh_smooth.Smooth();
            }
        }
Exemple #3
0
 public MeshFaceSelection(MeshFaceSelection copy)
 {
     Mesh     = copy.Mesh;
     Selected = new HashSet <int>(copy.Selected);
     temp     = new List <int>();
     temp2    = new List <int>();
 }
        // This function does local remeshing around a boundary loop within a fixed # of
        // rings, to try to 'massage' it into a cleaner shape/topology
        // [TODO] use geodesic distance instead of fixed # of rings?
        public static void cleanup_boundary(DMesh3 mesh, EdgeLoop loop, double target_edge_len, int nRings = 3)
        {
            Debug.Assert(loop.IsBoundaryLoop());

            MeshFaceSelection roi = new MeshFaceSelection(mesh);

            roi.SelectVertexOneRings(loop.Vertices);

            for (int i = 0; i < nRings; ++i)
            {
                roi.ExpandToOneRingNeighbours();
            }
            roi.LocalOptimize(true, true);

            RegionRemesher r = new RegionRemesher(mesh, roi.ToArray());

            r.Precompute();
            r.EnableFlips     = r.EnableSplits = r.EnableCollapses = true;
            r.MinEdgeLength   = target_edge_len;
            r.MaxEdgeLength   = 2 * target_edge_len;
            r.EnableSmoothing = true;
            r.SmoothSpeedT    = 0.1f;
            for (int k = 0; k < nRings * 3; ++k)
            {
                r.BasicRemeshPass();
            }
            Debug.Assert(mesh.CheckValidity());

            r.BackPropropagate();
        }
 public void SelectTriangleVertices(MeshFaceSelection triangles)
 {
     foreach (int tid in triangles)
     {
         Index3i tri = Mesh.GetTriangle(tid);
         add(tri.a); add(tri.b); add(tri.c);
     }
 }
        public MeshFaceSelection ToSelection()
        {
            MeshFaceSelection selection = new MeshFaceSelection(Mesh);

            //selection.Select(PathT);
            selection.Select(InteriorT);
            return(selection);
        }
Exemple #7
0
 // convert face selection to vertex selection.
 public MeshVertexSelection(DMesh3 mesh, MeshFaceSelection convertT) : this(mesh)
 {
     foreach (int tid in convertT)
     {
         Index3i tv = mesh.GetTriangle(tid);
         add(tv.a); add(tv.b); add(tv.c);
     }
 }
        // assumes PathT contains set of triangles
        // that are fully connected, ie a flood-fill cannot escape!
        void find_interior_from_seed(int tSeed)
        {
            MeshFaceSelection selection = new MeshFaceSelection(Mesh);

            selection.Select(PathT);
            selection.FloodFill(tSeed);

            InteriorT = new List <int>(selection);
        }
Exemple #9
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));
        }
Exemple #10
0
        /// <summary>
        /// Actually computes the insertion. In some cases we would like more info
        /// coming back than we get by using Generate() api. Note that resulting
        /// mesh is *not* compacted.
        /// </summary>
        public DMesh3 ComputeResult(out MeshInsertPolygon insertion)
        {
            AxisAlignedBox2d bounds  = Polygon.Bounds;
            double           padding = 0.1 * bounds.DiagonalLength;

            bounds.Expand(padding);

            TrivialRectGenerator rectgen = (Subdivisions == 1) ?
                                           new TrivialRectGenerator() : new GriddedRectGenerator()
            {
                EdgeVertices = Subdivisions
            };

            rectgen.Width      = (float)bounds.Width;
            rectgen.Height     = (float)bounds.Height;
            rectgen.IndicesMap = new Index2i(1, 2);
            rectgen.UVMode     = UVMode;
            rectgen.Clockwise  = true;              // MeshPolygonInserter assumes mesh faces are CW? (except code says CCW...)
            rectgen.Generate();
            var base_mesh = new DMesh3();

            rectgen.MakeMesh(base_mesh);

            var      shiftPolygon = new GeneralPolygon2d(Polygon);
            Vector2d shift        = bounds.Center;

            shiftPolygon.Translate(-shift);

            var insert = new MeshInsertPolygon()
            {
                Mesh    = base_mesh,
                Polygon = shiftPolygon
            };
            bool bOK = insert.Insert();

            if (!bOK)
            {
                throw new Exception("TriangulatedPolygonGenerator: failed to Insert()");
            }

            MeshFaceSelection selected = insert.InteriorTriangles;
            var editor = new MeshEditor(base_mesh);

            editor.RemoveTriangles((tid) => { return(selected.IsSelected(tid) == false); }, true);

            var shift3 = new Vector3d(shift.x, shift.y, 0);

            MeshTransforms.Translate(base_mesh, shift3);

            insertion = insert;
            return(base_mesh);
        }
Exemple #11
0
        // This function does local remeshing around a boundary loop within a fixed # of
        // rings, to try to 'massage' it into a cleaner shape/topology.
        // The result_edges list is the mapped edges of loop on the resulting mesh, but it is *not* in-order
        // [TODO] use geodesic distance instead of fixed # of rings?
        public static void cleanup_boundary(DMesh3 mesh, EdgeLoop loop, double target_edge_len, out List <int> result_edges, int nRings = 3)
        {
            Debug.Assert(loop.IsBoundaryLoop());

            var roi = new MeshFaceSelection(mesh);

            roi.SelectVertexOneRings(loop.Vertices);

            for (int i = 0; i < nRings; ++i)
            {
                roi.ExpandToOneRingNeighbours();
            }

            roi.LocalOptimize(true, true);

            var r = new RegionRemesher(mesh, roi.ToArray());

            // tag the input loop edges in the remesher, so that we can find this loop afterwards
            int[] init_loop_edges = new int[loop.EdgeCount];
            Array.Copy(loop.Edges, init_loop_edges, loop.EdgeCount);
            r.Region.MapEdgesToSubmesh(init_loop_edges);
            MeshConstraintUtil.AddTrackedEdges(r.Constraints, init_loop_edges, 100);
            //foreach (int eid in init_loop_edges)
            //    Debug.Assert(r.Region.SubMesh.IsBoundaryEdge(eid));

            r.Precompute();
            r.EnableFlips     = r.EnableSplits = r.EnableCollapses = true;
            r.MinEdgeLength   = target_edge_len;
            r.MaxEdgeLength   = 2 * target_edge_len;
            r.EnableSmoothing = true;
            r.SmoothSpeedT    = 0.1f;
            for (int k = 0; k < nRings * 3; ++k)
            {
                r.BasicRemeshPass();
            }

            Debug.Assert(mesh.CheckValidity());

            // extract the edges we tagged (they are unordered)
            List <int> new_loop_edges = r.Constraints.FindConstrainedEdgesBySetID(100);

            //foreach (int eid in new_loop_edges)
            //    Debug.Assert(r.Region.SubMesh.IsBoundaryEdge(eid));

            r.BackPropropagate();

            // map the extracted edges back to the backpropped input mesh
            result_edges = MeshIndexUtil.MapEdgesViaVertexMap(r.ReinsertSubToBaseMapV, r.Region.SubMesh, r.BaseMesh, new_loop_edges);
            //foreach (int eid in result_edges)
            //    Debug.Assert(mesh.IsBoundaryEdge(eid));
        }
 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]);
             }
         }
     }
 }
        // 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]);
        }
Exemple #14
0
        // local mesh smooth applied to all vertices in N-rings around input list
        public static void smooth_region(DMesh3 mesh, IEnumerable <int> vertices, int nRings)
        {
            MeshFaceSelection roi_t = new MeshFaceSelection(mesh);

            roi_t.SelectVertexOneRings(vertices);
            for (int i = 0; i < nRings; ++i)
            {
                roi_t.ExpandToOneRingNeighbours();
            }
            roi_t.LocalOptimize(true, true);

            MeshVertexSelection roi_v = new MeshVertexSelection(mesh);

            roi_v.SelectTriangleVertices(roi_t.ToArray());

            MeshIterativeSmooth mesh_smooth = new MeshIterativeSmooth(mesh, roi_v.ToArray(), true);

            mesh_smooth.Alpha  = 0.2f;
            mesh_smooth.Rounds = 10;
            mesh_smooth.Smooth();
        }
Exemple #15
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);
                    }
                }
            }
        }
        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()
        /// <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);
        }
Exemple #18
0
        public void Close_Flat()
        {
            double minlen, maxlen, avglen;

            MeshQueries.EdgeLengthStats(Mesh, out minlen, out maxlen, out avglen, 1000);
            double target_edge_len = (TargetEdgeLen <= 0) ? avglen : TargetEdgeLen;

            // massage around boundary loop
            List <int> refinedBorderEdges;

            cleanup_boundary(Mesh, InitialBorderLoop, avglen, out refinedBorderEdges, 3);

            // find new border loop. try to find new loop containing edges from loop we refined in cleanup_boundary,
            // if that fails just use largest loop.
            MeshBoundaryLoops loops = new MeshBoundaryLoops(Mesh);
            int iloop = loops.FindLoopContainingEdge(refinedBorderEdges[0]);

            if (iloop == -1)
            {
                iloop = loops.MaxVerticesLoopIndex;
            }
            EdgeLoop fill_loop = loops.Loops[iloop];

            int extrude_group = (ExtrudeGroup == -1) ? Mesh.AllocateTriangleGroup() : ExtrudeGroup;
            int fill_group    = (FillGroup == -1) ? Mesh.AllocateTriangleGroup() : FillGroup;

            // decide on projection plane
            //AxisAlignedBox3d loopbox = fill_loop.GetBounds();
            //Vector3d topPt = loopbox.Center;
            //if ( bIsUpper ) {
            //    topPt.y = loopbox.Max.y + 0.25 * dims.y;
            //} else {
            //    topPt.y = loopbox.Min.y - 0.25 * dims.y;
            //}
            //Frame3f plane = new Frame3f((Vector3f)topPt);

            // extrude loop to this plane
            MeshExtrudeLoop extrude = new MeshExtrudeLoop(Mesh, fill_loop);

            extrude.PositionF = (v, n, i) => {
                return(FlatClosePlane.ProjectToPlane((Vector3f)v, 1));
            };
            extrude.Extrude(extrude_group);
            MeshValidation.IsBoundaryLoop(Mesh, extrude.NewLoop);

            Debug.Assert(Mesh.CheckValidity());

            // smooth the extrude loop
            MeshLoopSmooth loop_smooth = new MeshLoopSmooth(Mesh, extrude.NewLoop);

            loop_smooth.ProjectF = (v, i) => {
                return(FlatClosePlane.ProjectToPlane((Vector3f)v, 1));
            };
            loop_smooth.Alpha  = 0.5f;
            loop_smooth.Rounds = 100;
            loop_smooth.Smooth();

            Debug.Assert(Mesh.CheckValidity());

            // fill result
            SimpleHoleFiller filler = new SimpleHoleFiller(Mesh, extrude.NewLoop);

            filler.Fill(fill_group);

            Debug.Assert(Mesh.CheckValidity());

            // make selection for remesh region
            MeshFaceSelection remesh_roi = new MeshFaceSelection(Mesh);

            remesh_roi.Select(extrude.NewTriangles);
            remesh_roi.Select(filler.NewTriangles);
            remesh_roi.ExpandToOneRingNeighbours();
            remesh_roi.ExpandToOneRingNeighbours();
            remesh_roi.LocalOptimize(true, true);
            int[] new_roi = remesh_roi.ToArray();

            // get rid of extrude group
            FaceGroupUtil.SetGroupToGroup(Mesh, extrude_group, 0);

            /*  clean up via remesh
             *     - constrain loop we filled to itself
             */

            RegionRemesher r = new RegionRemesher(Mesh, new_roi);

            DCurve3 top_curve = MeshUtil.ExtractLoopV(Mesh, extrude.NewLoop.Vertices);
            DCurveProjectionTarget curve_target = new DCurveProjectionTarget(top_curve);

            int[] top_loop = (int[])extrude.NewLoop.Vertices.Clone();
            r.Region.MapVerticesToSubmesh(top_loop);
            MeshConstraintUtil.ConstrainVtxLoopTo(r.Constraints, r.Mesh, top_loop, curve_target);

            DMeshAABBTree3 spatial = new DMeshAABBTree3(Mesh);

            spatial.Build();
            MeshProjectionTarget target = new MeshProjectionTarget(Mesh, spatial);

            r.SetProjectionTarget(target);

            bool bRemesh = true;

            if (bRemesh)
            {
                r.Precompute();
                r.EnableFlips     = r.EnableSplits = r.EnableCollapses = true;
                r.MinEdgeLength   = target_edge_len;
                r.MaxEdgeLength   = 2 * target_edge_len;
                r.EnableSmoothing = true;
                r.SmoothSpeedT    = 1.0f;
                for (int k = 0; k < 40; ++k)
                {
                    r.BasicRemeshPass();
                }
                r.SetProjectionTarget(null);
                r.SmoothSpeedT = 0.25f;
                for (int k = 0; k < 10; ++k)
                {
                    r.BasicRemeshPass();
                }
                Debug.Assert(Mesh.CheckValidity());

                r.BackPropropagate();
            }

            // smooth around the join region to clean up ugliness
            smooth_region(Mesh, r.Region.BaseBorderV, 3);
        }
Exemple #19
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);
        }