コード例 #1
0
    InteractiveRemesher make_remesher(DMesh3 mesh)
    {
        var m = new InteractiveRemesher(mesh);

        m.PreventNormalFlips = true;

        double mine, maxe, avge;

        MeshQueries.EdgeLengthStats(mesh, out mine, out avge, out maxe);
        m.SetTargetEdgeLength(avge * EdgeLengthMultiplier);

        m.SmoothSpeedT = SmoothSpeed;

        if (Reproject)
        {
            m.SetProjectionTarget(MeshProjectionTarget.Auto(mesh));
        }

        if (RemeshBoundary)
        {
            MeshBoundaryLoops loops = new MeshBoundaryLoops(mesh);
            int k = 1;
            foreach (var loop in loops)
            {
                MeshConstraintUtil.ConstrainVtxLoopTo(m, loop.Vertices, new DCurveProjectionTarget(loop.ToCurve()), k++);
            }
        }
        else if (PreserveBoundary)
        {
            MeshConstraintUtil.FixAllBoundaryEdges(m);
        }

        return(m);
    }
コード例 #2
0
        DMesh3 GenerateRemesh(DMesh3 mesh)
        {
            DMesh3 remeshed = new DMesh3(mesh);

            DMeshAABBTree3 project = new DMeshAABBTree3(mesh);

            project.Build();
            MeshProjectionTarget Target = new MeshProjectionTarget(project.Mesh, project);

            double minlen, maxlen, avglen;

            MeshQueries.EdgeLengthStats(mesh, out minlen, out maxlen, out avglen);
            double edge_len = (TargetEdgeLength == 0) ? Loop.AverageEdgeLength : avglen;

            Remesher r = new Remesher(remeshed);

            r.SetTargetEdgeLength(edge_len);
            r.SetProjectionTarget(Target);
            MeshConstraintUtil.FixAllBoundaryEdges(r);

            for (int k = 0; k < 20; ++k)
            {
                r.BasicRemeshPass();
            }

            return(remeshed);
        }
コード例 #3
0
        DMesh3 BuildPlanarMesh(bool bPreservePolygon)
        {
            DMesh3 planarMesh = new DMesh3();

            Vector2d center    = CurveUtils2.CentroidVtx(Loop.Vertices);
            int      center_id = planarMesh.AppendVertex(new Vector3d(center.x, center.y, 0));

            int prev_id  = -1;
            int first_id = -1;

            foreach (Vector2d v in Loop.Vertices)
            {
                int next_id = planarMesh.AppendVertex(new Vector3d(v.x, v.y, Thickness));
                if (prev_id > 0)
                {
                    planarMesh.AppendTriangle(center_id, prev_id, next_id);
                    prev_id = next_id;
                }
                else
                {
                    first_id = next_id;
                    prev_id  = next_id;
                }
            }
            planarMesh.AppendTriangle(center_id, prev_id, first_id);

            if (ReverseOrientation)
            {
                planarMesh.ReverseOrientation();
            }

            Debug.Assert(planarMesh.CheckValidity());


            double   edge_len = (TargetEdgeLength == 0) ? Loop.AverageEdgeLength : TargetEdgeLength;
            Remesher r        = new Remesher(planarMesh);

            r.SetTargetEdgeLength(edge_len);
            r.SmoothSpeedT = 1.0f;
            if (bPreservePolygon)
            {
                MeshConstraintUtil.FixAllBoundaryEdges(r);
            }
            else
            {
                MeshConstraintUtil.PreserveBoundaryLoops(r);
            }

            for (int k = 0; k < 20; ++k)
            {
                r.BasicRemeshPass();
            }

            return(planarMesh);
        }
コード例 #4
0
        protected void generate(float fDiameter, float fHeight, float fWallThickness, float fBaseThickness)
        {
            base.reset_holes();

            CappedCylinderGenerator outer_cylgen = new CappedCylinderGenerator()
            {
                BaseRadius = fDiameter / 2, TopRadius = fDiameter / 2,
                Height     = fHeight + 10,
                Slices     = 60,
                Clockwise  = true
            };
            DMesh3 outer_mesh = outer_cylgen.Generate().MakeDMesh();

            float fInnerDiam = fDiameter - 2 * fWallThickness;
            CappedCylinderGenerator inner_cylgen = new CappedCylinderGenerator()
            {
                BaseRadius = fInnerDiam / 2, TopRadius = fInnerDiam / 2,
                Height     = fHeight + 10,
                Slices     = 60,
                Clockwise  = false
            };
            DMesh3 inner_mesh = inner_cylgen.Generate().MakeDMesh();

            MeshTransforms.Translate(inner_mesh, fBaseThickness * Vector3d.AxisY);

            DMesh3[] meshes = new DMesh3[2] {
                outer_mesh, inner_mesh
            };

            foreach (DMesh3 mesh in meshes)
            {
                Remesher r = new Remesher(mesh);
                r.SetTargetEdgeLength(TargetEdgeLength);
                r.SmoothSpeedT = 0.5f;
                r.SetExternalConstraints(new MeshConstraints());
                MeshConstraintUtil.FixAllGroupBoundaryEdges(r.Constraints, mesh, true);
                r.SetProjectionTarget(MeshProjectionTarget.Auto(mesh));
                for (int k = 0; k < 10; ++k)
                {
                    r.BasicRemeshPass();
                }
            }

            Vector3d vCutPos    = new Vector3d(0, fHeight, 0);
            Vector3d vCutNormal = Vector3d.AxisY;

            foreach (DMesh3 mesh in meshes)
            {
                MeshPlaneCut cut = new MeshPlaneCut(mesh, new Vector3d(0, fHeight, 0), Vector3d.AxisY);
                cut.Cut();
            }

            base.set_output_meshes(inner_mesh, outer_mesh);
        }
コード例 #5
0
        void optimize_mesh(DMesh3 mesh)
        {
            Reducer         reducer     = new Reducer(mesh);
            MeshConstraints constraints = new MeshConstraints();

            MeshConstraintUtil.FixAllBoundaryEdges(constraints, mesh);
            reducer.SetExternalConstraints(constraints);
            reducer.ReduceToTriangleCount(1);

            Vector3d a, b, c, d;

            a = b = c = d = Vector3d.Zero;

            bool done = false;

            while (!done)
            {
                done = true;

                for (int eid = 0; eid < mesh.MaxEdgeID; ++eid)
                {
                    if (mesh.IsEdge(eid) == false)
                    {
                        continue;
                    }

                    Index4i evt = mesh.GetEdge(eid);
                    if (evt.d == DMesh3.InvalidID)
                    {
                        continue;
                    }
                    a = mesh.GetVertex(evt.a); b = mesh.GetVertex(evt.b);
                    Index2i ov = mesh.GetEdgeOpposingV(eid);
                    c = mesh.GetVertex(ov.a); d = mesh.GetVertex(ov.b);

                    if (c.DistanceSquared(d) > a.DistanceSquared(b))
                    {
                        continue;
                    }
                    if (MeshUtil.CheckIfEdgeFlipCreatesFlip(mesh, eid))
                    {
                        continue;
                    }

                    DMesh3.EdgeFlipInfo flipInfo;
                    if (mesh.FlipEdge(eid, out flipInfo) == MeshResult.Ok)
                    {
                        done = false;
                    }
                }
            }
        }
コード例 #6
0
        private DMesh3 Decimate(DMesh3 mesh, int targetCount)
        {
            Reducer r = new Reducer(mesh);

            if (_options.ReduceMeshPreserveEdges)
            {
                r.SetExternalConstraints(new MeshConstraints());
                MeshConstraintUtil.FixAllBoundaryEdges(r.Constraints, mesh);
            }
            r.ReduceToTriangleCount(targetCount);

            return(mesh);
        }
コード例 #7
0
ファイル: Old_ZRemeshDMesh3.cs プロジェクト: joelhi/g3-gh
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            DMesh3_goo dMsh_goo = null;
            double     targetL  = 0;
            int        numI     = 0;
            bool       fixB     = false;
            bool       projBack = false;

            DA.GetData(0, ref dMsh_goo);
            DA.GetData(1, ref targetL);
            DA.GetData(2, ref numI);
            DA.GetData(3, ref fixB);
            DA.GetData(4, ref projBack);

            DMesh3 dMsh_copy = new DMesh3(dMsh_goo.Value);

            Remesher r = new Remesher(dMsh_copy);

            r.PreventNormalFlips = true;
            r.SetTargetEdgeLength(targetL);
            r.SmoothSpeedT = 0.5;

            if (fixB)
            {
                MeshConstraintUtil.FixAllBoundaryEdges(r);
            }

            if (projBack)
            {
                r.SetProjectionTarget(MeshProjectionTarget.Auto(dMsh_goo.Value));
            }

            for (int k = 0; k < numI; ++k)
            {
                r.BasicRemeshPass();
            }

            bool isValid = dMsh_copy.CheckValidity();

            if (!isValid)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Mesh seems to have been corrupted during remeshing. Please check...");
            }

            DA.SetData(0, dMsh_copy);
        }
コード例 #8
0
        public static DMesh3 ReduceTriangles(this DMesh3 dMesh,
                                             int triangleCount,
                                             bool computeNormals      = true,
                                             bool fixAllBoundaryEdges = true)
        {
            Reducer reducer = new Reducer(dMesh);

            if (fixAllBoundaryEdges)
            {
                reducer.SetExternalConstraints(meshConstraints);
                MeshConstraintUtil.FixAllBoundaryEdges(reducer.Constraints, dMesh);
            }
            reducer.ReduceToTriangleCount(triangleCount);

            if (computeNormals)
            {
                MeshNormals.QuickCompute(dMesh);
            }

            return(dMesh);
        }
コード例 #9
0
ファイル: ReduceDMesh3.cs プロジェクト: joelhi/g3-gh
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            DMesh3_goo dMsh_goo = null;
            int        numF     = 0;
            bool       fixB     = false;
            bool       projBack = false;

            DA.GetData(0, ref dMsh_goo);
            DA.GetData(1, ref numF);
            DA.GetData(2, ref fixB);
            DA.GetData(3, ref projBack);

            DMesh3  dMsh_copy = new DMesh3(dMsh_goo.Value);
            Reducer r         = new Reducer(dMsh_copy);

            if (fixB)
            {
                r.SetExternalConstraints(new MeshConstraints());
                MeshConstraintUtil.PreserveBoundaryLoops(r.Constraints, dMsh_copy);
            }
            if (projBack)
            {
                DMeshAABBTree3 tree = new DMeshAABBTree3(new DMesh3(dMsh_copy));
                tree.Build();
                MeshProjectionTarget target = new MeshProjectionTarget(tree.Mesh, tree);
                r.SetProjectionTarget(target);
            }

            r.ReduceToTriangleCount(numF);
            bool isValid = dMsh_copy.CheckValidity();

            if (!isValid)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Mesh seems to have been corrupted during reduction. Please check...");
            }

            DA.SetData(0, dMsh_copy);
        }
コード例 #10
0
        /// <summary>
        /// add topological edges/vertices as constraints for remeshing
        /// </summary>
        public void AddRemeshConstraints(MeshConstraints constraints)
        {
            validate_topology();

            int set_index = 10;

            foreach (EdgeSpan span in Spans)
            {
                var target = new DCurveProjectionTarget(span.ToCurve());
                MeshConstraintUtil.ConstrainVtxSpanTo(constraints, Mesh, span.Vertices, target, set_index++);
            }

            foreach (EdgeLoop loop in Loops)
            {
                var target = new DCurveProjectionTarget(loop.ToCurve());
                MeshConstraintUtil.ConstrainVtxLoopTo(constraints, Mesh, loop.Vertices, target, set_index++);
            }

            VertexConstraint corners = VertexConstraint.Pinned;

            corners.FixedSetID = -1;
            foreach (int vid in JunctionVertices)
            {
                if (constraints.HasVertexConstraint(vid))
                {
                    VertexConstraint v = constraints.GetVertexConstraint(vid);
                    v.Target     = null;
                    v.Fixed      = true;
                    v.FixedSetID = -1;
                    constraints.SetOrUpdateVertexConstraint(vid, v);
                }
                else
                {
                    constraints.SetOrUpdateVertexConstraint(vid, corners);
                }
            }
        }
コード例 #11
0
        protected virtual DMesh3 compute_sharp_edge_flow()
        {
            DMesh3   sourceMesh   = MeshSource.GetDMeshUnsafe();
            ISpatial inputSpatial = MeshSource.GetSpatial();

            DMesh3   targetMesh    = TargetSource.GetDMeshUnsafe();
            ISpatial targetSpatial = TargetSource.GetSpatial();

            DMesh3 meshIn = new DMesh3(sourceMesh);

            if (is_invalidated())
            {
                return(null);
            }

            RemesherPro remesher = new RemesherPro(meshIn);

            remesher.SetTargetEdgeLength(TargetEdgeLength);
            remesher.PreventNormalFlips = this.PreventNormalFlips;
            remesher.EnableFlips        = this.EnableFlips;
            remesher.EnableSplits       = this.EnableSplits;
            remesher.EnableCollapses    = this.EnableCollapses;
            remesher.EnableSmoothing    = this.EnableSmoothing;
            remesher.SmoothSpeedT       = this.SmoothingSpeed;

            TransformedMeshProjectionTarget target =
                new TransformedMeshProjectionTarget(targetMesh, targetSpatial)
            {
                SourceToTargetXForm = source_to_target,
                TargetToSourceXForm = target_to_source
            };

            remesher.SetProjectionTarget(target);

            if (sourceMesh.CachedIsClosed == false)
            {
                if (remesher.Constraints == null)
                {
                    remesher.SetExternalConstraints(new MeshConstraints());
                }

                if (BoundaryMode == BoundaryModes.FreeBoundaries)
                {
                    MeshConstraintUtil.PreserveBoundaryLoops(remesher.Constraints, meshIn);
                }
                else if (BoundaryMode == BoundaryModes.FixedBoundaries)
                {
                    MeshConstraintUtil.FixAllBoundaryEdges(remesher.Constraints, meshIn);
                }
                else if (BoundaryMode == BoundaryModes.ConstrainedBoundaries)
                {
                    MeshConstraintUtil.FixAllBoundaryEdges_AllowSplit(remesher.Constraints, meshIn, 0);
                }
            }
            if (is_invalidated())
            {
                return(null);
            }

            remesher.Progress = new ProgressCancel(is_invalidated);
            remesher.SharpEdgeReprojectionRemesh(RemeshRounds, ProjectionRounds);

            if (is_invalidated())
            {
                return(null);
            }
            return(meshIn);
        }
コード例 #12
0
        public static void quick_test_2()
        {
            DMesh3         target        = TestUtil.LoadTestInputMesh("cylinder_orig.obj");
            DMeshAABBTree3 targetSpatial = new DMeshAABBTree3(target, true);

            DMesh3         mesh        = TestUtil.LoadTestInputMesh("cylinder_approx.obj");
            DMeshAABBTree3 meshSpatial = new DMeshAABBTree3(mesh, true);

            double search_dist = 10.0;

            MeshTopology topo = new MeshTopology(target);

            topo.Compute();

            RemesherPro r = new RemesherPro(mesh);

            r.SetTargetEdgeLength(2.0);
            r.SmoothSpeedT = 0.5;
            r.SetProjectionTarget(MeshProjectionTarget.Auto(target));
            MeshConstraints cons = new MeshConstraints();

            r.SetExternalConstraints(cons);


            int set_id = 1;

            foreach (var loop in topo.Loops)
            {
                DCurveProjectionTarget curveTarget = new DCurveProjectionTarget(loop.ToCurve(target));
                set_id++;

                // pick a set of points we will find paths between. We will chain
                // up those paths and constrain them to target loops.
                // (this part is the hack!)
                List <int> target_verts = new List <int>();
                List <int> mesh_verts   = new List <int>();
                for (int k = 0; k < loop.VertexCount; k += 5)
                {
                    target_verts.Add(loop.Vertices[k]);

                    Vector3d vCurve   = target.GetVertex(loop.Vertices[k]);
                    int      mesh_vid = meshSpatial.FindNearestVertex(vCurve, search_dist);
                    mesh_verts.Add(mesh_vid);
                }
                int NT = target_verts.Count;

                // find the paths to assemble the edge chain
                // [TODO] need to filter out junction vertices? or will they just handle themselves
                //   because they can be collapsed away?
                List <int> vert_seq = new List <int>();
                for (int k = 0; k < NT; k++)
                {
                    EdgeSpan e = find_edge_path(mesh, mesh_verts[k], mesh_verts[(k + 1) % NT]);
                    int      n = e.Vertices.Length;
                    for (int i = 0; i < n - 1; ++i)
                    {
                        vert_seq.Add(e.Vertices[i]);
                    }
                }

                // now it's easy, just add the loop constraint
                EdgeLoop full_loop = EdgeLoop.FromVertices(mesh, vert_seq);
                MeshConstraintUtil.ConstrainVtxLoopTo(cons, mesh, full_loop.Vertices, curveTarget, set_id);
            }


            r.FastestRemesh();

            TestUtil.WriteTestOutputMesh(mesh, "curves_test_out.obj");
        }
コード例 #13
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);
        }
コード例 #14
0
ファイル: RemeshOp.cs プロジェクト: tomleetv/gsShapeModels
        protected virtual DMesh3 compute_standard()
        {
            DMesh3   sourceMesh    = MeshSource.GetDMeshUnsafe();
            ISpatial sourceSpatial = MeshSource.GetSpatial();
            DMesh3   meshIn        = new DMesh3(sourceMesh);

            RemesherPro remesh = new RemesherPro(meshIn);

            //Remesher remesh = new Remesher(meshIn);

            remesh.SetTargetEdgeLength(TargetEdgeLength);
            remesh.PreventNormalFlips = this.PreventNormalFlips;
            remesh.EnableFlips        = this.EnableFlips;
            remesh.EnableSplits       = this.EnableSplits;
            remesh.EnableCollapses    = this.EnableCollapses;
            remesh.EnableSmoothing    = this.EnableSmoothing;
            remesh.SmoothSpeedT       = this.SmoothingSpeed;

            if (ReprojectToInput)
            {
                MeshProjectionTarget target = new MeshProjectionTarget(sourceMesh, sourceSpatial);
                remesh.SetProjectionTarget(target);
            }


            // if we are preserving creases, this will also automatically constrain boundary
            // edges boundary loops/spans.
            if (preserve_creases)
            {
                if (remesh.Constraints == null)
                {
                    remesh.SetExternalConstraints(new MeshConstraints());
                }

                MeshTopology topo = new MeshTopology(meshIn);
                topo.CreaseAngle = this.CreaseAngle;
                topo.AddRemeshConstraints(remesh.Constraints);

                // replace boundary edge constraints if we want other behaviors
                if (BoundaryMode == BoundaryModes.FixedBoundaries)
                {
                    MeshConstraintUtil.FixEdges(remesh.Constraints, meshIn, topo.BoundaryEdges);
                }
            }
            else if (sourceMesh.CachedIsClosed == false)
            {
                if (remesh.Constraints == null)
                {
                    remesh.SetExternalConstraints(new MeshConstraints());
                }

                if (BoundaryMode == BoundaryModes.FreeBoundaries)
                {
                    MeshConstraintUtil.PreserveBoundaryLoops(remesh.Constraints, meshIn);
                }
                else if (BoundaryMode == BoundaryModes.FixedBoundaries)
                {
                    MeshConstraintUtil.FixAllBoundaryEdges(remesh.Constraints, meshIn);
                }
                else if (BoundaryMode == BoundaryModes.ConstrainedBoundaries)
                {
                    MeshConstraintUtil.FixAllBoundaryEdges_AllowSplit(remesh.Constraints, meshIn, 0);
                }
            }

            remesh.Progress = new ProgressCancel(is_invalidated);

            remesh.FastestRemesh(RemeshRounds, true);
            //for (int k = 0; k < RemeshRounds; ++k)
            //    remesh.BasicRemeshPass();

            // free boundary remesh can leave sliver triangles around the border. clean that up.
            if (sourceMesh.CachedIsClosed == false && BoundaryMode == BoundaryModes.FreeBoundaries)
            {
                MeshEditor.RemoveFinTriangles(meshIn, (mesh, tid) => {
                    Index3i tv = mesh.GetTriangle(tid);
                    return(MathUtil.AspectRatio(mesh.GetVertex(tv.a), mesh.GetVertex(tv.b), mesh.GetVertex(tv.c)) > 2);
                });
            }

            if (is_invalidated())
            {
                return(null);
            }
            return(meshIn);
        }
コード例 #15
0
ファイル: ZRemeshDMesh3.cs プロジェクト: joelhi/g3-gh
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            DMesh3_goo     dMsh_goo = null;
            List <Point3d> points   = new List <Point3d>();
            double         targetL  = 0;
            int            numI     = 0;
            int            fixB     = 0;
            bool           projBack = false;
            double         smooth   = 0;

            DA.GetData(0, ref dMsh_goo);
            DA.GetDataList(2, points);
            DA.GetData(1, ref targetL);
            DA.GetData(6, ref numI);
            DA.GetData(3, ref fixB);
            DA.GetData(5, ref projBack);
            DA.GetData(7, ref smooth);

            List <EdgeConstraint_goo> edgeC = new List <EdgeConstraint_goo>();

            DA.GetDataList(4, edgeC);

            DMesh3 dMsh_copy = new DMesh3(dMsh_goo.Value);

            Remesher r = new Remesher(dMsh_copy);

            r.PreventNormalFlips = true;
            r.SetTargetEdgeLength(targetL);
            r.SmoothSpeedT = smooth;


            if (fixB == 2)
            {
                MeshConstraintUtil.FixAllBoundaryEdges(r);
            }
            else if (fixB == 1)
            {
                MeshConstraintUtil.PreserveBoundaryLoops(r);
            }
            else
            {
                r.SetExternalConstraints(new MeshConstraints());
            }

            if (edgeC.Count > 0)
            {
                for (int i = 0; i < edgeC.Count; i++)
                {
                    var tempEC = edgeC[i];

                    IProjectionTarget target = new DCurveProjectionTarget(tempEC.crv);

                    for (int j = 0; j < tempEC.edges.Length; j++)
                    {
                        tempEC.constraint.Target = target;
                        r.Constraints.SetOrUpdateEdgeConstraint(tempEC.edges[j], tempEC.constraint);
                    }

                    for (int j = 0; j < tempEC.vertices.Length; j++)
                    {
                        if (tempEC.PinVerts)
                        {
                            r.Constraints.SetOrUpdateVertexConstraint(tempEC.vertices[j], VertexConstraint.Pinned);
                        }
                        else
                        {
                            r.Constraints.SetOrUpdateVertexConstraint(tempEC.vertices[j], new VertexConstraint(target));
                        }
                    }
                }
            }

            if (points.Count > 0)
            {
                DMeshAABBTree3 mshAABB = new DMeshAABBTree3(dMsh_copy, true);

                var v3pts = points.Select(pt => pt.ToVec3d());

                foreach (var p in v3pts)
                {
                    int id = mshAABB.FindNearestVertex(p, 0.1);

                    if (id != -1)
                    {
                        r.Constraints.SetOrUpdateVertexConstraint(id, VertexConstraint.Pinned);
                    }
                }
            }

            if (projBack)
            {
                r.SetProjectionTarget(MeshProjectionTarget.Auto(dMsh_goo.Value));
            }


            for (int k = 0; k < numI; ++k)
            {
                r.BasicRemeshPass();
            }

            bool isValid = dMsh_copy.CheckValidity();

            if (!isValid)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Mesh seems to have been corrupted during remeshing. Please check...");
            }

            DA.SetData(0, dMsh_copy);
        }
コード例 #16
0
ファイル: MinimalHoleFill.cs プロジェクト: CallAndGus/ViRGIS
        public bool Apply()
        {
            // do a simple fill
            SimpleHoleFiller simplefill = new SimpleHoleFiller(Mesh, FillLoop);
            int  fill_gid = Mesh.AllocateTriangleGroup();
            bool bOK      = simplefill.Fill(fill_gid);

            if (bOK == false)
            {
                return(false);
            }

            if (FillLoop.Vertices.Length <= 3)
            {
                FillTriangles = simplefill.NewTriangles;
                FillVertices  = new int[0];
                return(true);
            }

            // extract the simple fill mesh as a submesh, via RegionOperator, so we can backsub later
            HashSet <int> intial_fill_tris = new HashSet <int>(simplefill.NewTriangles);

            regionop = new RegionOperator(Mesh, simplefill.NewTriangles,
                                          (submesh) => { submesh.ComputeTriMaps = true; });
            fillmesh = regionop.Region.SubMesh;

            // for each boundary vertex, compute the exterior angle sum
            // we will use this to compute gaussian curvature later
            boundaryv           = new HashSet <int>(MeshIterators.BoundaryEdgeVertices(fillmesh));
            exterior_angle_sums = new Dictionary <int, double>();
            if (IgnoreBoundaryTriangles == false)
            {
                foreach (int sub_vid in boundaryv)
                {
                    double angle_sum = 0;
                    int    base_vid  = regionop.Region.MapVertexToBaseMesh(sub_vid);
                    foreach (int tid in regionop.BaseMesh.VtxTrianglesItr(base_vid))
                    {
                        if (intial_fill_tris.Contains(tid) == false)
                        {
                            Index3i et  = regionop.BaseMesh.GetTriangle(tid);
                            int     idx = IndexUtil.find_tri_index(base_vid, ref et);
                            angle_sum += regionop.BaseMesh.GetTriInternalAngleR(tid, idx);
                        }
                    }
                    exterior_angle_sums[sub_vid] = angle_sum;
                }
            }


            // try to guess a reasonable edge length that will give us enough geometry to work with in simplify pass
            double loop_mine, loop_maxe, loop_avge, fill_mine, fill_maxe, fill_avge;

            MeshQueries.EdgeLengthStatsFromEdges(Mesh, FillLoop.Edges, out loop_mine, out loop_maxe, out loop_avge);
            MeshQueries.EdgeLengthStats(fillmesh, out fill_mine, out fill_maxe, out fill_avge);
            double remesh_target_len = loop_avge;

            if (fill_maxe / remesh_target_len > 10)
            {
                remesh_target_len = fill_maxe / 10;
            }
            //double remesh_target_len = Math.Min(loop_avge, fill_avge / 4);

            // remesh up to target edge length, ideally gives us some triangles to work with
            RemesherPro remesh1 = new RemesherPro(fillmesh);

            remesh1.SmoothSpeedT = 1.0;
            MeshConstraintUtil.FixAllBoundaryEdges(remesh1);
            //remesh1.SetTargetEdgeLength(remesh_target_len / 2);       // would this speed things up? on large regions?
            //remesh1.FastestRemesh();
            remesh1.SetTargetEdgeLength(remesh_target_len);
            remesh1.FastestRemesh();

            /*
             * first round: collapse to minimal mesh, while flipping to try to
             * get to ballpark minimal mesh. We stop these passes as soon as
             * we have done two rounds where we couldn't do another collapse
             *
             * This is the most unstable part of the algorithm because there
             * are strong ordering effects. maybe we could sort the edges somehow??
             */

            int zero_collapse_passes = 0;
            int collapse_passes      = 0;

            while (collapse_passes++ < 20 && zero_collapse_passes < 2)
            {
                // collapse pass
                int NE        = fillmesh.MaxEdgeID;
                int collapses = 0;
                for (int ei = 0; ei < NE; ++ei)
                {
                    if (fillmesh.IsEdge(ei) == false || fillmesh.IsBoundaryEdge(ei))
                    {
                        continue;
                    }
                    Index2i ev = fillmesh.GetEdgeV(ei);
                    bool    a_bdry = boundaryv.Contains(ev.a), b_bdry = boundaryv.Contains(ev.b);
                    if (a_bdry && b_bdry)
                    {
                        continue;
                    }
                    int      keepv  = (a_bdry) ? ev.a : ev.b;
                    int      otherv = (keepv == ev.a) ? ev.b : ev.a;
                    Vector3d newv   = fillmesh.GetVertex(keepv);
                    if (MeshUtil.CheckIfCollapseCreatesFlip(fillmesh, ei, newv))
                    {
                        continue;
                    }
                    DMesh3.EdgeCollapseInfo info;
                    MeshResult result = fillmesh.CollapseEdge(keepv, otherv, out info);
                    if (result == MeshResult.Ok)
                    {
                        collapses++;
                    }
                }
                if (collapses == 0)
                {
                    zero_collapse_passes++;
                }
                else
                {
                    zero_collapse_passes = 0;
                }

                // flip pass. we flip in these cases:
                //  1) if angle between current triangles is too small (slightly more than 90 degrees, currently)
                //  2) if angle between flipped triangles is smaller than between current triangles
                //  3) if flipped edge length is shorter *and* such a flip won't flip the normal
                NE = fillmesh.MaxEdgeID;
                Vector3d n1, n2, on1, on2;
                for (int ei = 0; ei < NE; ++ei)
                {
                    if (fillmesh.IsEdge(ei) == false || fillmesh.IsBoundaryEdge(ei))
                    {
                        continue;
                    }
                    bool do_flip = false;

                    Index2i ev = fillmesh.GetEdgeV(ei);
                    MeshUtil.GetEdgeFlipNormals(fillmesh, ei, out n1, out n2, out on1, out on2);
                    double dot_cur  = n1.Dot(n2);
                    double dot_flip = on1.Dot(on2);
                    if (n1.Dot(n2) < 0.1 || dot_flip > dot_cur + MathUtil.Epsilonf)
                    {
                        do_flip = true;
                    }

                    if (do_flip == false)
                    {
                        Index2i otherv   = fillmesh.GetEdgeOpposingV(ei);
                        double  len_e    = fillmesh.GetVertex(ev.a).Distance(fillmesh.GetVertex(ev.b));
                        double  len_flip = fillmesh.GetVertex(otherv.a).Distance(fillmesh.GetVertex(otherv.b));
                        if (len_flip < len_e)
                        {
                            if (MeshUtil.CheckIfEdgeFlipCreatesFlip(fillmesh, ei) == false)
                            {
                                do_flip = true;
                            }
                        }
                    }

                    if (do_flip)
                    {
                        DMesh3.EdgeFlipInfo info;
                        MeshResult          result = fillmesh.FlipEdge(ei, out info);
                    }
                }
            }

            // Sometimes, for some reason, we have a remaining interior vertex (have only ever seen one?)
            // Try to force removal of such vertices, even if it makes ugly mesh
            remove_remaining_interior_verts();


            // enable/disable passes.
            bool DO_FLATTER_PASS   = true;
            bool DO_CURVATURE_PASS = OptimizeDevelopability && true;
            bool DO_AREA_PASS      = OptimizeDevelopability && OptimizeTriangles && true;


            /*
             * In this pass we repeat the flipping iterations from the previous pass.
             *
             * Note that because of the always-flip-if-dot-is-small case (commented),
             * this pass will frequently not converge, as some number of edges will
             * be able to flip back and forth (because neither has large enough dot).
             * This is not ideal, but also, if we remove this behavior, then we
             * generally get worse fills. This case basically introduces a sort of
             * randomization factor that lets us escape local minima...
             *
             */

            HashSet <int> remaining_edges = new HashSet <int>(fillmesh.EdgeIndices());
            HashSet <int> updated_edges   = new HashSet <int>();

            int flatter_passes    = 0;
            int zero_flips_passes = 0;

            while (flatter_passes++ < 40 && zero_flips_passes < 2 && remaining_edges.Count() > 0 && DO_FLATTER_PASS)
            {
                zero_flips_passes++;
                foreach (int ei in remaining_edges)
                {
                    if (fillmesh.IsBoundaryEdge(ei))
                    {
                        continue;
                    }

                    bool do_flip = false;

                    Index2i  ev = fillmesh.GetEdgeV(ei);
                    Vector3d n1, n2, on1, on2;
                    MeshUtil.GetEdgeFlipNormals(fillmesh, ei, out n1, out n2, out on1, out on2);
                    double dot_cur  = n1.Dot(n2);
                    double dot_flip = on1.Dot(on2);
                    if (flatter_passes < 20 && dot_cur < 0.1)   // this check causes oscillatory behavior
                    {
                        do_flip = true;
                    }
                    if (dot_flip > dot_cur + MathUtil.Epsilonf)
                    {
                        do_flip = true;
                    }

                    if (do_flip)
                    {
                        DMesh3.EdgeFlipInfo info;
                        MeshResult          result = fillmesh.FlipEdge(ei, out info);
                        if (result == MeshResult.Ok)
                        {
                            zero_flips_passes = 0;
                            add_all_edges(ei, updated_edges);
                        }
                    }
                }

                var tmp = remaining_edges;
                remaining_edges = updated_edges;
                updated_edges   = tmp; updated_edges.Clear();
            }


            int curvature_passes = 0;

            if (DO_CURVATURE_PASS)
            {
                curvatures = new double[fillmesh.MaxVertexID];
                foreach (int vid in fillmesh.VertexIndices())
                {
                    update_curvature(vid);
                }

                remaining_edges = new HashSet <int>(fillmesh.EdgeIndices());
                updated_edges   = new HashSet <int>();

                /*
                 *  In this pass we try to minimize gaussian curvature at all the vertices.
                 *  This will recover sharp edges, etc, and do lots of good stuff.
                 *  However, this pass will not make much progress if we are not already
                 *  relatively close to a minimal mesh, so it really relies on the previous
                 *  passes getting us in the ballpark.
                 */
                while (curvature_passes++ < 40 && remaining_edges.Count() > 0 && DO_CURVATURE_PASS)
                {
                    foreach (int ei in remaining_edges)
                    {
                        if (fillmesh.IsBoundaryEdge(ei))
                        {
                            continue;
                        }

                        Index2i ev = fillmesh.GetEdgeV(ei);
                        Index2i ov = fillmesh.GetEdgeOpposingV(ei);

                        int find_other = fillmesh.FindEdge(ov.a, ov.b);
                        if (find_other != DMesh3.InvalidID)
                        {
                            continue;
                        }

                        double total_curv_cur = curvature_metric_cached(ev.a, ev.b, ov.a, ov.b);
                        if (total_curv_cur < MathUtil.ZeroTolerancef)
                        {
                            continue;
                        }

                        DMesh3.EdgeFlipInfo info;
                        MeshResult          result = fillmesh.FlipEdge(ei, out info);
                        if (result != MeshResult.Ok)
                        {
                            continue;
                        }

                        double total_curv_flip = curvature_metric_eval(ev.a, ev.b, ov.a, ov.b);

                        bool keep_flip = total_curv_flip < total_curv_cur - MathUtil.ZeroTolerancef;
                        if (keep_flip == false)
                        {
                            result = fillmesh.FlipEdge(ei, out info);
                        }
                        else
                        {
                            update_curvature(ev.a); update_curvature(ev.b);
                            update_curvature(ov.a); update_curvature(ov.b);
                            add_all_edges(ei, updated_edges);
                        }
                    }
                    var tmp = remaining_edges;
                    remaining_edges = updated_edges;
                    updated_edges   = tmp; updated_edges.Clear();
                }
            }
            //System.Console.WriteLine("collapse {0}   flatter {1}   curvature {2}", collapse_passes, flatter_passes, curvature_passes);

            /*
             * In this final pass, we try to improve triangle quality. We flip if
             * the flipped triangles have better total aspect ratio, and the
             * curvature doesn't change **too** much. The .DevelopabilityTolerance
             * parameter determines what is "too much" curvature change.
             */
            if (DO_AREA_PASS)
            {
                remaining_edges = new HashSet <int>(fillmesh.EdgeIndices());
                updated_edges   = new HashSet <int>();
                int area_passes = 0;
                while (remaining_edges.Count() > 0 && area_passes < 20)
                {
                    area_passes++;
                    foreach (int ei in remaining_edges)
                    {
                        if (fillmesh.IsBoundaryEdge(ei))
                        {
                            continue;
                        }

                        Index2i ev = fillmesh.GetEdgeV(ei);
                        Index2i ov = fillmesh.GetEdgeOpposingV(ei);

                        int find_other = fillmesh.FindEdge(ov.a, ov.b);
                        if (find_other != DMesh3.InvalidID)
                        {
                            continue;
                        }

                        double total_curv_cur = curvature_metric_cached(ev.a, ev.b, ov.a, ov.b);

                        double a = aspect_metric(ei);
                        if (a > 1)
                        {
                            continue;
                        }

                        DMesh3.EdgeFlipInfo info;
                        MeshResult          result = fillmesh.FlipEdge(ei, out info);
                        if (result != MeshResult.Ok)
                        {
                            continue;
                        }

                        double total_curv_flip = curvature_metric_eval(ev.a, ev.b, ov.a, ov.b);

                        bool keep_flip = Math.Abs(total_curv_cur - total_curv_flip) < DevelopabilityTolerance;
                        if (keep_flip == false)
                        {
                            result = fillmesh.FlipEdge(ei, out info);
                        }
                        else
                        {
                            update_curvature(ev.a); update_curvature(ev.b);
                            update_curvature(ov.a); update_curvature(ov.b);
                            add_all_edges(ei, updated_edges);
                        }
                    }
                    var tmp = remaining_edges;
                    remaining_edges = updated_edges;
                    updated_edges   = tmp; updated_edges.Clear();
                }
            }


            regionop.BackPropropagate();
            FillTriangles = regionop.CurrentBaseTriangles;
            FillVertices  = regionop.CurrentBaseInteriorVertices().ToArray();

            return(true);
        }
コード例 #17
0
        protected virtual DMesh3 compute_bounded_distance()
        {
            DMesh3   sourceMesh   = MeshSource.GetDMeshUnsafe();
            ISpatial inputSpatial = MeshSource.GetSpatial();

            DMesh3   targetMesh    = TargetSource.GetDMeshUnsafe();
            ISpatial targetSpatial = TargetSource.GetSpatial();

            double max_dist = (TargetMaxDistance == double.MaxValue) ? double.MaxValue : TargetMaxDistance;

            DMesh3 meshIn = new DMesh3(sourceMesh);

            bool target_closed           = targetMesh.IsClosed();
            MeshVertexSelection roiV     = new MeshVertexSelection(meshIn);
            SpinLock            roi_lock = new SpinLock();

            gParallel.ForEach(meshIn.VertexIndices(), (vid) => {
                Vector3d pos       = meshIn.GetVertex(vid);
                Vector3d posTarget = TransformToTarget.TransformP(pos);
                double dist        = MeshQueries.NearestPointDistance(targetMesh, targetSpatial, posTarget, max_dist);
                bool inside        = (target_closed && targetSpatial.IsInside(posTarget));
                if (dist < max_dist || inside)
                {
                    bool taken = false;
                    roi_lock.Enter(ref taken);
                    roiV.Select(vid);
                    roi_lock.Exit();
                }
            });
            if (is_invalidated())
            {
                return(null);
            }

            MeshFaceSelection roi_faces = new MeshFaceSelection(meshIn, roiV, 1);

            roi_faces.ExpandToOneRingNeighbours(3);
            roi_faces.LocalOptimize();
            if (is_invalidated())
            {
                return(null);
            }

            RegionOperator op      = new RegionOperator(meshIn, roi_faces);
            DMesh3         meshROI = op.Region.SubMesh;

            if (is_invalidated())
            {
                return(null);
            }

            RemesherPro remesher = new RemesherPro(meshROI);

            remesher.SetTargetEdgeLength(TargetEdgeLength);
            remesher.PreventNormalFlips = this.PreventNormalFlips;
            remesher.EnableFlips        = this.EnableFlips;
            remesher.EnableSplits       = this.EnableSplits;
            remesher.EnableCollapses    = this.EnableCollapses;
            remesher.EnableSmoothing    = this.EnableSmoothing;
            remesher.SmoothSpeedT       = this.SmoothingSpeed;

            BoundedProjectionTarget target = new BoundedProjectionTarget()
            {
                Source = sourceMesh, SourceSpatial = inputSpatial,
                Target = targetMesh, TargetSpatial = targetSpatial,
                SourceToTargetXForm = source_to_target,
                TargetToSourceXForm = target_to_source,
                MaxDistance         = max_dist,
                Smoothness          = transition_smoothness
            };

            remesher.SetProjectionTarget(target);

            if (remesher.Constraints == null)
            {
                remesher.SetExternalConstraints(new MeshConstraints());
            }
            MeshConstraintUtil.FixAllBoundaryEdges(remesher.Constraints, meshROI);
            if (is_invalidated())
            {
                return(null);
            }

            remesher.Progress = new ProgressCancel(is_invalidated);
            remesher.FastestRemesh(RemeshRounds);
            if (is_invalidated())
            {
                return(null);
            }

            op.BackPropropagate();

            return(meshIn);
        }
コード例 #18
0
ファイル: RemeshDMesh3.cs プロジェクト: joelhi/g3-gh
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            DMesh3_goo dMsh_goo = null;
            double     targetL  = 0;
            bool       fixB     = false;
            bool       projBack = false;
            bool       run      = false;
            bool       reset    = false;
            int        maxIter  = 0;

            DA.GetData(0, ref dMsh_goo);
            DA.GetData(1, ref targetL);
            DA.GetData(3, ref fixB);
            DA.GetData(4, ref projBack);
            DA.GetData(2, ref maxIter);
            DA.GetData(5, ref run);
            DA.GetData(6, ref reset);

            if (passes >= maxIter)
            {
                run = false;
            }


            if (r is null || reset)
            {
                dMsh_copy = new DMesh3(dMsh_goo.Value);

                r = new Remesher(dMsh_copy);
                r.PreventNormalFlips = true;
                r.SetTargetEdgeLength(targetL);
                r.SmoothSpeedT = 0.5;

                passes = 0;

                if (fixB)
                {
                    MeshConstraintUtil.FixAllBoundaryEdges(r);
                }

                if (projBack)
                {
                    r.SetProjectionTarget(MeshProjectionTarget.Auto(dMsh_goo.Value));
                }
            }

            if (run && !reset)
            {
                r.BasicRemeshPass();
                passes++;
                Update();
            }

            bool isValid = dMsh_copy.CheckValidity();

            if (!isValid)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Mesh seems to have been corrupted during remeshing. Please check...");
            }

            this.Message = "Pass: " + passes.ToString();

            DA.SetData(0, dMsh_copy);
        }
コード例 #19
0
ファイル: Remesh.cs プロジェクト: petrasvestartas/NGon
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            Mesh           m          = DA.Fetch <Mesh>("Mesh");
            bool           fixEdges   = DA.Fetch <bool>("FixEdges");
            double         l          = DA.Fetch <double>("EdgeLength");
            int            iterations = DA.Fetch <int>("Iterations");
            List <Point3d> fixPt      = DA.FetchList <Point3d>("FixPt");
            bool           project    = DA.Fetch <bool>("Project");
            bool           loops      = DA.Fetch <bool>("Loops");

            Mesh mesh = m.DuplicateMesh();

            mesh.Faces.ConvertQuadsToTriangles();

            double len = (l == 0) ? mesh.GetBoundingBox(false).Diagonal.Length * 0.1 : l;



            //r.PreventNormalFlips = true;

            List <int> ids = new List <int>();

            Point3d[] pts = mesh.Vertices.ToPoint3dArray();
            foreach (Point3d p in fixPt)
            {
                ids.Add(NGonsCore.PointUtil.ClosestPoint(p, pts));
            }



            DMesh3   dmesh = mesh.ToDMesh3();
            Remesher r     = new Remesher(dmesh);

            r.Precompute();
            r.SetTargetEdgeLength(len);
            r.SmoothSpeedT = 0.5;
            if (project)
            {
                r.SetProjectionTarget(MeshProjectionTarget.Auto(dmesh));
            }

            r.EnableFlips     = r.EnableSplits = r.EnableCollapses = true;
            r.EnableSmoothing = true;


            MeshConstraints cons = new MeshConstraints();


            if (ids.Count > 0)
            {
                foreach (int id in ids)
                {
                    //cons.SetOrUpdateVertexConstraint(id, new VertexConstraint(true, 1));
                    cons.SetOrUpdateVertexConstraint(id, VertexConstraint.Pinned);
                }
            }
            r.SetExternalConstraints(cons);

            r.Precompute();

            if (fixEdges)
            {
                //r.SetExternalConstraints(new MeshConstraints());
                MeshConstraintUtil.FixAllBoundaryEdges(r);
                MeshConstraintUtil.FixAllBoundaryEdges_AllowSplit(cons, dmesh, 0);
                //MeshConstraintUtil.FixAllBoundaryEdges_AllowCollapse(cons, dmesh, 0);
            }

            if (loops)
            {
                MeshConstraintUtil.PreserveBoundaryLoops(r); //project to edge
                                                             //MeshConstraintUtil.PreserveBoundaryLoops(cons,dmesh);//project to edge
            }
            r.SetExternalConstraints(cons);


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



            //output
            if (ids.Count > 0 && !fixEdges)
            {
                this.Message = "Vertices";
            }
            else if (ids.Count == 0 && fixEdges)
            {
                this.Message = "Edges";
            }
            else if (ids.Count > 0 && fixEdges)
            {
                this.Message = "Vertices + Edges";
            }
            else
            {
                this.Message = "";
            }



            dmesh = new DMesh3(dmesh, true);
            Mesh rmesh = dmesh.ToRhinoMesh();

            if (loops)
            {
                Mesh mesh_ = rmesh.DuplicateMesh();
                Rhino.IndexPair[] closestEdges = new Rhino.IndexPair[fixPt.Count];

                int counter = 0;
                foreach (Point3d p in fixPt)
                {
                    double[] d   = new double[rmesh.TopologyEdges.Count];
                    int[]    eid = new int[rmesh.TopologyEdges.Count];

                    for (int i = 0; i < rmesh.TopologyEdges.Count; i++)
                    {
                        if (rmesh.TopologyEdges.GetConnectedFaces(i).Length == 1)
                        {
                            Line line = rmesh.TopologyEdges.EdgeLine(i);
                            line.ClosestPoint(p, true);
                            d[i] = line.ClosestPoint(p, true).DistanceToSquared(p); //line.From.DistanceToSquared(p) + line.To.DistanceToSquared(p);
                        }
                        else
                        {
                            d[i] = 99999;
                        }
                        eid[i] = i;
                    }



                    Array.Sort(d, eid);

                    closestEdges[counter++] = rmesh.TopologyEdges.GetTopologyVertices(eid[0]);
                }

                for (int i = 0; i < fixPt.Count; i++)
                {
                    mesh_.Vertices.Add(fixPt[i]);
                    mesh_.Faces.AddFace(rmesh.Vertices.Count + i, closestEdges[i].I, closestEdges[i].J);
                }
                rmesh = mesh_;
            }
            rmesh.UnifyNormals();
            rmesh.RebuildNormals();
            // rmesh.UnifyNormals();



            DA.SetData(0, rmesh);
        }