Ejemplo n.º 1
0
        public Mesh Repair(Mesh sourceMesh, CancellationToken cancellationToken)
        {
            var inMesh = sourceMesh;

            try
            {
                if (WeldVertices)
                {
                    inMesh = sourceMesh.Copy(cancellationToken);
                    if (WeldTolerance > 0)
                    {
                        inMesh.MergeVertices(.01);
                    }
                    else
                    {
                        inMesh.CleanAndMerge();
                    }

                    if (!FaceOrientation &&
                        RemoveMode == RemoveModes.None &&
                        !WeldEdges &&
                        !FillHoles)
                    {
                        return(inMesh);
                    }
                }

                var    mesh              = inMesh.ToDMesh3();
                int    repeatCount       = 0;
                int    erosionIterations = 5;
                double repairTolerance   = MathUtil.ZeroTolerancef;
                double minEdgeLengthTol  = 0.0001;

repeat_all:

                if (FaceOrientation)
                {
                    // make sure orientation of connected components is consistent
                    // TODO: what about mobius strip problems?
                    RepairOrientation(mesh, cancellationToken, true);
                }

                if (RemoveMode != RemoveModes.None)
                {
                    // Remove parts of the mesh we don't want before we bother with anything else
                    // TODO: maybe we need to repair orientation first? if we want to use MWN (MeshWindingNumber)...
                    RemoveInside(mesh);
                    cancellationToken.ThrowIfCancellationRequested();
                }

                if (WeldEdges || FillHoles)
                {
                    // Do safe close-cracks to handle easy cases
                    RepairCracks(mesh, true, repairTolerance);

                    if (mesh.IsClosed())
                    {
                        goto all_done;
                    }

                    cancellationToken.ThrowIfCancellationRequested();

                    // Collapse tiny edges and then try easy cases again, and
                    // then allow for handling of ambiguous cases
                    CollapseAllDegenerateEdges(mesh, cancellationToken, repairTolerance * 0.5, true);
                    cancellationToken.ThrowIfCancellationRequested();

                    RepairCracks(mesh, true, 2 * repairTolerance);
                    cancellationToken.ThrowIfCancellationRequested();

                    RepairCracks(mesh, false, 2 * repairTolerance);
                    cancellationToken.ThrowIfCancellationRequested();

                    if (mesh.IsClosed())
                    {
                        goto all_done;
                    }

                    // Possibly we have joined regions with different orientation (is it?), fix that
                    // TODO: mobius strips again
                    RepairOrientation(mesh, cancellationToken, true);
                    cancellationToken.ThrowIfCancellationRequested();

                    // get rid of any remaining single-triangles before we start filling holes
                    MeshEditor.RemoveIsolatedTriangles(mesh);
                }

                if (FillHoles)
                {
                    // Ok, fill simple holes.
                    int nRemainingBowties = 0;
                    FillTrivialHoles(mesh, cancellationToken, out int nHoles, out bool bSawSpans);
                    cancellationToken.ThrowIfCancellationRequested();

                    if (mesh.IsClosed())
                    {
                        goto all_done;
                    }

                    // Now fill harder holes. If we saw spans, that means boundary loops could
                    // not be resolved in some cases, do we disconnect bowties and try again.
                    FillAnyHoles(mesh, cancellationToken, out nHoles, out bSawSpans);
                    cancellationToken.ThrowIfCancellationRequested();

                    if (bSawSpans)
                    {
                        DisconnectBowties(mesh, out nRemainingBowties);
                        FillAnyHoles(mesh, cancellationToken, out nHoles, out bSawSpans);
                    }

                    cancellationToken.ThrowIfCancellationRequested();

                    if (mesh.IsClosed())
                    {
                        goto all_done;
                    }

                    // We may have a closed mesh now but it might still have bowties (eg
                    // tetrahedra sharing vtx case). So disconnect those.
                    DisconnectBowties(mesh, out nRemainingBowties);
                    cancellationToken.ThrowIfCancellationRequested();

                    // If the mesh is not closed, we will do one more round to try again.
                    if (repeatCount == 0 && mesh.IsClosed() == false)
                    {
                        repeatCount++;
                        goto repeat_all;
                    }

                    // Ok, we didn't get anywhere on our first repeat. If we are still not
                    // closed, we will try deleting boundary triangles and repeating.
                    // Repeat this N times.
                    if (repeatCount <= erosionIterations && mesh.IsClosed() == false)
                    {
                        repeatCount++;
                        var bdry_faces = new MeshFaceSelection(mesh);
                        foreach (int eid in MeshIterators.BoundaryEdges(mesh))
                        {
                            bdry_faces.SelectEdgeTris(eid);
                        }

                        MeshEditor.RemoveTriangles(mesh, bdry_faces, true);
                        goto repeat_all;
                    }
                }

all_done:

                // and do a final clean up of the model
                if (FillHoles)
                {
                    // Remove tiny edges
                    if (minEdgeLengthTol > 0)
                    {
                        CollapseAllDegenerateEdges(mesh, cancellationToken, minEdgeLengthTol, false);
                    }

                    cancellationToken.ThrowIfCancellationRequested();

                    // finally do global orientation
                    RepairOrientation(mesh, cancellationToken, true);
                    cancellationToken.ThrowIfCancellationRequested();
                }

                return(mesh.ToMesh());
            }
            catch (OperationCanceledException)
            {
                return(inMesh);
            }
        }
Ejemplo n.º 2
0
        public bool Apply()
        {
            bool do_checks = false;

            if (do_checks)
            {
                Mesh.CheckValidity();
            }


            /*
             * Remove parts of the mesh we don't want before we bother with anything else
             * TODO: maybe we need to repair orientation first? if we want to use MWN...
             */
            do_remove_inside();
            if (Cancelled())
            {
                return(false);
            }

            int repeat_count = 0;

repeat_all:

            /*
             * make sure orientation of connected components is consistent
             * TODO: what about mobius strip problems?
             */
            repair_orientation(false);
            if (Cancelled())
            {
                return(false);
            }

            /*
             *  Do safe close-cracks to handle easy cases
             */

            repair_cracks(true, RepairTolerance);
            if (Mesh.IsClosed())
            {
                goto all_done;
            }
            if (Cancelled())
            {
                return(false);
            }

            /*
             * Collapse tiny edges and then try easy cases again, and
             * then allow for handling of ambiguous cases
             */

            collapse_all_degenerate_edges(RepairTolerance * 0.5, true);
            if (Cancelled())
            {
                return(false);
            }
            repair_cracks(true, 2 * RepairTolerance);
            if (Cancelled())
            {
                return(false);
            }
            repair_cracks(false, 2 * RepairTolerance);
            if (Cancelled())
            {
                return(false);
            }
            if (Mesh.IsClosed())
            {
                goto all_done;
            }

            /*
             * Possibly we have joined regions with different orientation (is it?), fix that
             * TODO: mobius strips again
             */
            repair_orientation(false);
            if (Cancelled())
            {
                return(false);
            }

            if (do_checks)
            {
                Mesh.CheckValidity();
            }

            // get rid of any remaining single-triangles before we start filling holes
            remove_loners();

            /*
             * Ok, fill simple holes.
             */
            int nRemainingBowties = 0;
            int nHoles; bool bSawSpans;

            fill_trivial_holes(out nHoles, out bSawSpans);
            if (Cancelled())
            {
                return(false);
            }
            if (Mesh.IsClosed())
            {
                goto all_done;
            }

            /*
             * Now fill harder holes. If we saw spans, that means boundary loops could
             * not be resolved in some cases, do we disconnect bowties and try again.
             */
            fill_any_holes(out nHoles, out bSawSpans);
            if (Cancelled())
            {
                return(false);
            }
            if (bSawSpans)
            {
                disconnect_bowties(out nRemainingBowties);
                fill_any_holes(out nHoles, out bSawSpans);
            }
            if (Cancelled())
            {
                return(false);
            }
            if (Mesh.IsClosed())
            {
                goto all_done;
            }

            /*
             * We may have a closed mesh now but it might still have bowties (eg
             * tetrahedra sharing vtx case). So disconnect those.
             */
            disconnect_bowties(out nRemainingBowties);
            if (Cancelled())
            {
                return(false);
            }

            /*
             * If the mesh is not closed, we will do one more round to try again.
             */
            if (repeat_count == 0 && Mesh.IsClosed() == false)
            {
                repeat_count++;
                goto repeat_all;
            }

            /*
             * Ok, we didn't get anywhere on our first repeat. If we are still not
             * closed, we will try deleting boundary triangles and repeating.
             * Repeat this N times.
             */
            if (repeat_count <= ErosionIterations && Mesh.IsClosed() == false)
            {
                repeat_count++;
                MeshFaceSelection bdry_faces = new MeshFaceSelection(Mesh);
                foreach (int eid in MeshIterators.BoundaryEdges(Mesh))
                {
                    bdry_faces.SelectEdgeTris(eid);
                }
                MeshEditor.RemoveTriangles(Mesh, bdry_faces, true);
                goto repeat_all;
            }

all_done:

            /*
             * Remove tiny edges
             */
            if (MinEdgeLengthTol > 0)
            {
                collapse_all_degenerate_edges(MinEdgeLengthTol, false);
            }
            if (Cancelled())
            {
                return(false);
            }

            /*
             * finally do global orientation
             */
            repair_orientation(true);
            if (Cancelled())
            {
                return(false);
            }

            if (do_checks)
            {
                Mesh.CheckValidity();
            }

            /*
             * Might as well compact output mesh...
             */
            Mesh = new DMesh3(Mesh, true);
            MeshNormals.QuickCompute(Mesh);

            return(true);
        }