Example #1
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
        // [TODO] use geodesic distance instead of fixed # of rings?
        public static void cleanup_boundary(NGonsCore.geometry3Sharp.mesh.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();
        }
Example #2
0
        public DMesh3 remesh_region(int iterations, DMesh3 mesh, double min, double max, double angle)
        {
            int[] tris = GetTrisOnPositiveSide(mesh, new Frame3f(Vector3F.Zero, Vector3F.AxisY));

            RegionRemesher r = new RegionRemesher(mesh, tris);

            r.Region.SubMesh.CheckValidity(true);

            r.Precompute();
            r.EnableFlips     = r.EnableSplits = r.EnableCollapses = true;
            r.MinEdgeLength   = min;
            r.MaxEdgeLength   = max;
            r.EnableSmoothing = true;
            r.SmoothSpeedT    = 1.0f;

            for (int k = 0; k < iterations; ++k)
            {
                r.BasicRemeshPass();
                mesh.CheckValidity();
            }


            r.BackPropropagate();

            for (int k = 0; k < iterations; ++k)
            {
                r.BasicRemeshPass();
                mesh.CheckValidity();
            }

            r.BackPropropagate();

            return(mesh);
        }
        public static void test_remesh_region()
        {
            int    Slices = 16;
            DMesh3 mesh   = TestUtil.MakeCappedCylinder(false, Slices);

            MeshUtil.ScaleMesh(mesh, Frame3f.Identity, new Vector3f(1, 2, 1));
            mesh.CheckValidity();

            int[] tris = TestUtil.GetTrisOnPositiveSide(mesh, new Frame3f(Vector3f.Zero, Vector3f.AxisY));

            RegionRemesher r = new RegionRemesher(mesh, tris);

            r.Region.SubMesh.CheckValidity(true);

            TestUtil.WriteTestOutputMesh(r.Region.SubMesh, "remesh_region_submesh.obj");

            r.Precompute();
            double fResScale = 0.5f;

            r.EnableFlips     = r.EnableSplits = r.EnableCollapses = true;
            r.MinEdgeLength   = 0.1f * fResScale;
            r.MaxEdgeLength   = 0.2f * fResScale;
            r.EnableSmoothing = true;
            r.SmoothSpeedT    = 1.0f;

            for (int k = 0; k < 5; ++k)
            {
                r.BasicRemeshPass();
                mesh.CheckValidity();
            }

            TestUtil.WriteTestOutputMesh(r.Region.SubMesh, "remesh_region_submesh_refined.obj");

            r.BackPropropagate();

            TestUtil.WriteTestOutputMesh(mesh, "remesh_region_submesh_merged_1.obj");


            for (int k = 0; k < 5; ++k)
            {
                r.BasicRemeshPass();
                mesh.CheckValidity();
            }

            r.BackPropropagate();

            TestUtil.WriteTestOutputMesh(mesh, "remesh_region_submesh_merged_2.obj");
        }
Example #4
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
            cleanup_boundary(Mesh, InitialBorderLoop, avglen, 3);

            // find new border loop
            // [TODO] this just assumes there is only one!!
            MeshBoundaryLoops loops     = new MeshBoundaryLoops(Mesh);
            EdgeLoop          fill_loop = loops.Loops[0];

            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
            MeshExtrusion extrude = new MeshExtrusion(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 = mesh.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);
        }