/// <summary>
        ///    Internal method evaluates all collapse costs from this vertex and picks the lowest for a single buffer
        /// </summary>
        float ComputeEdgeCostAtVertexForBuffer(PMWorkingData workingData, uint vertIndex)
        {
            // compute the edge collapse cost for all edges that start
            // from vertex v.  Since we are only interested in reducing
            // the object by selecting the min cost edge at each step, we
            // only cache the cost of the least cost edge at this vertex
            // (in member variable collapse) as well as the value of the
            // cost (in member variable objdist).

            PMVertex v = workingData.vertList[(int)vertIndex];

            if (v.neighbors.Count == 0)
            {
                // v doesn't have neighbors so nothing to collapse
                v.NotifyRemoved();
                return(v.collapseCost);
            }

            // Init metrics
            v.collapseCost = float.MaxValue;
            v.collapseTo   = null;

            // search all neighboring edges for "least cost" edge
            foreach (PMVertex neighbor in v.neighbors)
            {
                float cost = ComputeEdgeCollapseCost(v, neighbor);
                if ((v.collapseTo == null) || cost < v.collapseCost)
                {
                    v.collapseTo   = neighbor; // candidate for edge collapse
                    v.collapseCost = cost;     // cost of the collapse
                }
            }

            return(v.collapseCost);
        }
Example #2
0
        /// <summary>
        ///    Internal method, collapses vertex onto it's saved collapse target.
        /// </summary>
        /// <remarks>
        ///    This updates the working triangle list to drop a triangle and recalculates
        ///    the edge collapse costs around the collapse target.
        ///    This also updates all the working vertex lists for the relevant buffer.
        /// </remarks>
        /// <pram name="src">the collapser</pram>
        private void Collapse(PMVertex src)
        {
            var dest         = src.collapseTo;
            var recomputeSet = new List <PMVertex>();

            // Abort if we're never supposed to collapse
            if (src.collapseCost == float.MaxValue)
            {
                return;
            }

            // Remove this vertex from the running for the next check
            src.collapseTo   = null;
            src.collapseCost = float.MaxValue;
            this.worstCosts[(int)src.index] = float.MaxValue;

            // Collapse the edge uv by moving vertex u onto v
            // Actually remove tris on uv, then update tris that
            // have u to have v, and then remove u.
            if (dest == null)
            {
                // src is a vertex all by itself
                return;
            }

            // Add dest and all the neighbours of source and dest to recompute list
            recomputeSet.Add(dest);

            foreach (var neighbor in src.neighbors)
            {
                if (!recomputeSet.Contains(neighbor))
                {
                    recomputeSet.Add(neighbor);
                }
            }
            foreach (var neighbor in dest.neighbors)
            {
                if (!recomputeSet.Contains(neighbor))
                {
                    recomputeSet.Add(neighbor);
                }
            }

            // delete triangles on edge src-dest
            // Notify others to replace src with dest
            // Queue of faces for removal / replacement
            // prevents us screwing up the iterators while we parse
            var faceRemovalList     = new List <PMTriangle>();
            var faceReplacementList = new List <PMTriangle>();

            foreach (var face in src.faces)
            {
                if (face.HasCommonVertex(dest))
                {
                    // Tri is on src-dest therefore is gone
                    faceRemovalList.Add(face);
                    // Reduce index count by 3 (useful for quick allocation later)
                    this.currNumIndexes -= 3;
                }
                else
                {
                    // Only src involved, replace with dest
                    faceReplacementList.Add(face);
                }
            }

            src.toBeRemoved = true;
            // Replace all the faces queued for replacement
            foreach (var face in faceReplacementList)
            {
                /* Locate the face vertex which corresponds with the common 'dest' vertex
                 * To to this, find a removed face which has the FACE vertex corresponding with
                 * src, and use it's FACE vertex version of dest.
                 */
                var          srcFaceVert  = face.GetFaceVertexFromCommon(src);
                PMFaceVertex destFaceVert = null;
                foreach (var removed in faceRemovalList)
                {
                    //if (removed.HasFaceVertex(srcFaceVert))
                    //{
                    destFaceVert = removed.GetFaceVertexFromCommon(dest);
                    //}
                }

                Debug.Assert(destFaceVert != null);

                face.ReplaceVertex(srcFaceVert, destFaceVert);
            }
            // Remove all the faces queued for removal
            foreach (var face in faceRemovalList)
            {
                face.NotifyRemoved();
            }

            // Notify the vertex that it is gone
            src.NotifyRemoved();

            // recompute costs
            foreach (var recomp in recomputeSet)
            {
                ComputeEdgeCostAtVertex(recomp.index);
            }
        }
        /// <summary>
        ///    Internal method, collapses vertex onto it's saved collapse target. 
        /// </summary>
        /// <remarks>
        ///    This updates the working triangle list to drop a triangle and recalculates
        ///    the edge collapse costs around the collapse target. 
        ///    This also updates all the working vertex lists for the relevant buffer. 
        /// </remarks>
        /// <pram name="src">the collapser</pram>
        void Collapse(PMVertex src)
        {
            PMVertex dest = src.collapseTo;
            List<PMVertex> recomputeSet = new List<PMVertex>();

            // Abort if we're never supposed to collapse
            if (src.collapseCost == float.MaxValue)
                return;

            // Remove this vertex from the running for the next check
            src.collapseTo = null;
            src.collapseCost = float.MaxValue;
            worstCosts[(int)src.index] = float.MaxValue;

            // Collapse the edge uv by moving vertex u onto v
            // Actually remove tris on uv, then update tris that
            // have u to have v, and then remove u.
            if (dest == null) {
                // src is a vertex all by itself
                return;
            }

            // Add dest and all the neighbours of source and dest to recompute list
            recomputeSet.Add(dest);
            // PMVertex temp; (unused)

            foreach (PMVertex neighbor in src.neighbors) {
                if (!recomputeSet.Contains(neighbor))
                    recomputeSet.Add(neighbor);
            }
            foreach (PMVertex neighbor in dest.neighbors) {
                if (!recomputeSet.Contains(neighbor))
                    recomputeSet.Add(neighbor);
            }

            // delete triangles on edge src-dest
            // Notify others to replace src with dest
            // Queue of faces for removal / replacement
            // prevents us screwing up the iterators while we parse
            List<PMTriangle> faceRemovalList = new List<PMTriangle>();
            List<PMTriangle> faceReplacementList = new List<PMTriangle>();

            foreach (PMTriangle face in src.faces)
            {
                if (face.HasCommonVertex(dest))
                {
                    // Tri is on src-dest therefore is gone
                    faceRemovalList.Add(face);
                    // Reduce index count by 3 (useful for quick allocation later)
                    currNumIndexes -= 3;
                }
                else
                {
                    // Only src involved, replace with dest
                    faceReplacementList.Add(face);
                }
            }

            src.toBeRemoved = true;
            // Replace all the faces queued for replacement
            foreach (PMTriangle face in faceReplacementList)
            {
                /* Locate the face vertex which corresponds with the common 'dest' vertex
                   To to this, find a removed face which has the FACE vertex corresponding with
                   src, and use it's FACE vertex version of dest.
                */
                PMFaceVertex srcFaceVert = face.GetFaceVertexFromCommon(src);
                PMFaceVertex destFaceVert = null;
                foreach (PMTriangle removed in faceRemovalList) {
                    //if (removed.HasFaceVertex(srcFaceVert))
                    //{
                    destFaceVert = removed.GetFaceVertexFromCommon(dest);
                    //}
                }

                Debug.Assert(destFaceVert != null);

                face.ReplaceVertex(srcFaceVert, destFaceVert);
            }
            // Remove all the faces queued for removal
            foreach (PMTriangle face in faceRemovalList) {
                face.NotifyRemoved();
            }

            // Notify the vertex that it is gone
            src.NotifyRemoved();

            // recompute costs
            foreach (PMVertex recomp in recomputeSet) {
                ComputeEdgeCostAtVertex(recomp.index);
            }
        }