public virtual ValidationStatus Validate(double fDegenerateTol = MathUtil.ZeroTolerancef)
        {
            double dist_sqr_thresh = fDegenerateTol * fDegenerateTol;

            int nStop = IsLoop ? Curve.VertexCount - 1 : Curve.VertexCount;

            for (int k = 0; k < nStop; ++k)
            {
                Vector2d v0 = Curve[k];
                Vector2d v1 = Curve[(k + 1) % Curve.VertexCount];
                if (v0.DistanceSquared(v1) < dist_sqr_thresh)
                {
                    return(ValidationStatus.NearDenegerateInputGeometry);
                }
            }

            foreach (int eid in Mesh.EdgeIndices())
            {
                Index2i ev = Mesh.GetEdgeV(eid);
                if (PointF(ev.a).DistanceSquared(PointF(ev.b)) < dist_sqr_thresh)
                {
                    return(ValidationStatus.NearDegenerateMeshEdges);
                }
            }

            return(ValidationStatus.Ok);
        }
Example #2
0
        protected virtual void InitializeQueue()
        {
            int NE     = mesh.EdgeCount;
            int MaxEID = mesh.MaxEdgeID;

            EdgeQuadrics = new QEdge[MaxEID];
            EdgeQueue    = new IndexPriorityQueue(MaxEID);
            float[] edgeErrors = new float[MaxEID];

            // vertex quadrics can be computed in parallel
            gParallel.ForEach(mesh.EdgeIndices(), (eid) => {
                Index2i ev        = mesh.GetEdgeV(eid);
                QuadricError Q    = new QuadricError(ref vertQuadrics[ev.a], ref vertQuadrics[ev.b]);
                Vector3d opt      = OptimalPoint(eid, ref Q, ev.a, ev.b);
                edgeErrors[eid]   = (float)Q.Evaluate(opt);
                EdgeQuadrics[eid] = new QEdge(eid, Q, opt);
            });

            // sorted pq insert is faster, so sort edge errors array and index map
            int[] indices = new int[MaxEID];
            for (int i = 0; i < MaxEID; ++i)
            {
                indices[i] = i;
            }
            Array.Sort(edgeErrors, indices);

            // now do inserts
            for (int i = 0; i < edgeErrors.Length; ++i)
            {
                int eid = indices[i];
                if (mesh.IsEdge(eid))
                {
                    QEdge edge = EdgeQuadrics[eid];
                    EdgeQueue.Enqueue(edge.eid, edgeErrors[i]);
                }
            }

            /*
             * // previous code that does unsorted insert. This is marginally slower, but
             * // might get even slower on larger meshes? have only tried up to about 350k.
             * // (still, this function is not the bottleneck...)
             * int cur_eid = start_edges();
             * bool done = false;
             * do {
             *  if (mesh.IsEdge(cur_eid)) {
             *      QEdge edge = EdgeQuadrics[cur_eid];
             *      double err = errList[cur_eid];
             *      EdgeQueue.Enqueue(cur_eid, (float)err);
             *  }
             *  cur_eid = next_edge(cur_eid, out done);
             * } while (done == false);
             */
        }
Example #3
0
 /// <summary>
 /// we can vastly speed things up if we precompute some invariants.
 /// You need to re-run this if you are changing the mesh externally
 /// between remesh passes, otherwise you will get weird results.
 /// But you will probably still come out ahead, computation-time-wise
 /// </summary>
 public virtual void Precompute()
 {
     // if we know mesh is closed, we can skip is-boundary checks, which makes
     // the flip-valence tests much faster!
     MeshIsClosed = true;
     foreach (int eid in mesh.EdgeIndices())
     {
         if (mesh.IsBoundaryEdge(eid))
         {
             MeshIsClosed = false;
             break;
         }
     }
 }
Example #4
0
        // convert vertex selection to edge selection. Require at least minCount verts of edge to be selected
        public MeshEdgeSelection(DMesh3 mesh, MeshVertexSelection convertV, int minCount = 2) : this(mesh)
        {
            minCount = MathUtil.Clamp(minCount, 1, 2);

            // [TODO] if minCount == 1, and convertV is small, it is faster to iterate over convertV!!

            foreach (int eid in mesh.EdgeIndices())
            {
                Index2i ev = mesh.GetEdgeV(eid);
                int     n  = (convertV.IsSelected(ev.a) ? 1 : 0) +
                             (convertV.IsSelected(ev.b) ? 1 : 0);
                if (n >= minCount)
                {
                    add(eid);
                }
            }
        }
Example #5
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);
                    }
                }
            }
        }
Example #6
0
 // iterators allow us to work with gaps in index space
 public IEnumerable <int> VertexIndices()
 {
     return(Mesh.EdgeIndices());
 }
        public static DMesh3 RemeshMesh(g3.DMesh3 mesh, float minEdgeLength, float maxEdgeLength, float contraintAngle, float smoothSpeed, int smoothPasses, List <Line3d> constrainedLines)
        {
            // construct mesh projection target
            DMesh3         meshCopy = new DMesh3(mesh);
            DMeshAABBTree3 tree     = new DMeshAABBTree3(meshCopy);

            tree.Build();
            MeshProjectionTarget target = new MeshProjectionTarget()
            {
                Mesh    = meshCopy,
                Spatial = tree
            };

            MeshConstraints cons     = new MeshConstraints();
            EdgeRefineFlags useFlags = EdgeRefineFlags.NoFlip;

            foreach (int eid in mesh.EdgeIndices())
            {
                double fAngle = MeshUtil.OpeningAngleD(mesh, eid);

                Index2i ev = mesh.GetEdgeV(eid);

                if (fAngle > contraintAngle)
                {
                    cons.SetOrUpdateEdgeConstraint(eid, new EdgeConstraint(useFlags));


                    // TODO Ids based off of ?? What?
                    int nSetID0 = (mesh.GetVertex(ev[0]).y > 1) ? 1 : 2;
                    int nSetID1 = (mesh.GetVertex(ev[1]).y > 1) ? 1 : 2;
                    cons.SetOrUpdateVertexConstraint(ev[0], new VertexConstraint(true, nSetID0));
                    cons.SetOrUpdateVertexConstraint(ev[1], new VertexConstraint(true, nSetID1));
                }

                Vector3d p1 = mesh.GetVertex(ev.a);
                Vector3d p2 = mesh.GetVertex(ev.b);


                foreach (var v in constrainedLines)
                {
                    if (p1.CompareTo(v.Origin) == 0)
                    {
                        Vector3d p = v.PointAt(1.0);

                        if (p2.CompareTo(p) == 0)
                        {
                            cons.SetOrUpdateEdgeConstraint(eid, EdgeConstraint.FullyConstrained);
                            break;
                        }
                    }
                }

                foreach (var v in constrainedLines)
                {
                    if (p2.CompareTo(v.Origin) == 0)
                    {
                        Vector3d p = v.PointAt(1.0);

                        if (p1.CompareTo(p) == 0)
                        {
                            cons.SetOrUpdateEdgeConstraint(eid, EdgeConstraint.FullyConstrained);
                            break;
                        }
                    }
                }
            }

            Remesher r = new Remesher(mesh);

            r.SetExternalConstraints(cons);
            r.SetProjectionTarget(target);
            r.Precompute();
            r.EnableFlips     = r.EnableSplits = r.EnableCollapses = true;
            r.MinEdgeLength   = minEdgeLength;     //0.1f;
            r.MaxEdgeLength   = maxEdgeLength;     // 0.2f;
            r.EnableSmoothing = true;
            r.SmoothSpeedT    = smoothSpeed;       // .5;
            for (int k = 0; k < smoothPasses; ++k) // smoothPasses = 20
            {
                r.BasicRemeshPass();
            }
            return(mesh);
        }
        //

        public static DMesh3 RemeshMeshNew(g3.DMesh3 mesh, float minEdgeLength, float maxEdgeLength, float contraintAngle, float smoothSpeed, int smoothPasses, g3.DMesh3 projectMeshInput = null, float projectAmount = 1.0f, float projectedDistance = float.MaxValue)
        {
            g3.DMesh3 projectMesh = projectMeshInput;

            if (projectMesh == null)
            {
                projectMesh = mesh;
            }

            DMesh3         projectMeshCopy = new DMesh3(projectMesh);
            DMeshAABBTree3 treeProject     = new DMeshAABBTree3(projectMeshCopy);

            treeProject.Build();
            GopherMeshProjectionTarget targetProject = new GopherMeshProjectionTarget()
            {
                Mesh        = projectMeshCopy,
                Spatial     = treeProject,
                amount      = projectAmount,
                maxDistance = projectedDistance
            };

            MeshConstraints cons     = new MeshConstraints();
            EdgeRefineFlags useFlags = EdgeRefineFlags.NoFlip;

            foreach (int eid in mesh.EdgeIndices())
            {
                double fAngle = MeshUtil.OpeningAngleD(mesh, eid);
                if (fAngle > contraintAngle)
                {
                    cons.SetOrUpdateEdgeConstraint(eid, new EdgeConstraint(useFlags));
                    Index2i ev = mesh.GetEdgeV(eid);
                    //int nSetID0 = (mesh.GetVertex(ev[0]).y > 1) ? 1 : 2;
                    //int nSetID1 = (mesh.GetVertex(ev[1]).y > 1) ? 1 : 2;
                    cons.SetOrUpdateVertexConstraint(ev[0], new VertexConstraint(true));
                    cons.SetOrUpdateVertexConstraint(ev[1], new VertexConstraint(true));
                }
            }

            // TODO Constrain Vertices too far away
            foreach (int vid in mesh.VertexIndices())
            {
                var v = mesh.GetVertex(vid);

                //v.Distance()
                //targetProject.Project()
            }

            Remesher rProjected = new Remesher(mesh);

            rProjected.SetExternalConstraints(cons);
            rProjected.SetProjectionTarget(targetProject);
            rProjected.Precompute();
            rProjected.EnableFlips     = rProjected.EnableSplits = rProjected.EnableCollapses = true;
            rProjected.MinEdgeLength   = minEdgeLength; //0.1f;
            rProjected.MaxEdgeLength   = maxEdgeLength; // 0.2f;
            rProjected.EnableSmoothing = true;
            rProjected.SmoothSpeedT    = smoothSpeed;   // .5;

            if (projectMeshInput != null)
            {
                float bestSmoothPassProjectAmount     = projectAmount / smoothPasses;
                float testbestSmoothPassProjectAmount = float.MaxValue;
                for (float smoothPassProjectAmount = -.1f; smoothPassProjectAmount < 1.1f; smoothPassProjectAmount += 0.005f)
                {
                    double test = 0;

                    for (int i = 0; i < smoothPasses; i++)
                    {
                        test = 1.0 * smoothPassProjectAmount + test * (1 - smoothPassProjectAmount);
                    }

                    if (Math.Abs(test - projectAmount) < Math.Abs(testbestSmoothPassProjectAmount - projectAmount))
                    {
                        bestSmoothPassProjectAmount     = (float)smoothPassProjectAmount;
                        testbestSmoothPassProjectAmount = (float)test;
                    }
                }

                targetProject.amount      = bestSmoothPassProjectAmount;
                targetProject.maxDistance = projectedDistance;

                for (int k = 0; k < smoothPasses; ++k) // smoothPasses = 20
                {
                    rProjected.BasicRemeshPass();
                }
            }
            else
            {
                for (int k = 0; k < smoothPasses; ++k) // smoothPasses = 20
                {
                    rProjected.BasicRemeshPass();
                }
            }


            return(mesh);
        }