/// <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); }
/// <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); } }