Exemple #1
0
        bool _producesNonManifold(BaseMesh mesh, CollapseInfo ci)
        {
            // ... If v0 and v1 don't have nr of commonfaces common neighbours
            List <Vertex> vertices = mesh.vertices;
            List <Face>   faces    = mesh.faces;
            int           common   = commonFaces.Count;
            int           tag      = mesh.GetUniqueTag();

            int count = faces0.Count;

            int[] faceArray = faces0.array;
            for (int i = 0; i < count; ++i)
            {
                int[] v = faces[faceArray[i]].v;
                // known to be a valid triangle
                vertices[v[0]].mark = tag;
                vertices[v[1]].mark = tag;
                vertices[v[2]].mark = tag;
            }
            count     = faces1.Count;
            faceArray = faces1.array;
            for (int i = 0; i < count; ++i)
            {
                int[] v = faces[faceArray[i]].v;
                if (vertices[v[0]].mark == tag)
                {
                    common--; if (common < 0)
                    {
                        return(true);
                    }
                    vertices[v[0]].mark = 0;
                }
                if (vertices[v[1]].mark == tag)
                {
                    common--; if (common < 0)
                    {
                        return(true);
                    }
                    vertices[v[1]].mark = 0;
                }
                if (vertices[v[2]].mark == tag)
                {
                    common--; if (common < 0)
                    {
                        return(true);
                    }
                    vertices[v[2]].mark = 0;
                }
            }

            return(common != 0);
        }
Exemple #2
0
        // the mesh needs to have its edge list and creases calculated
        public void InitializeCollapsing(MeshEdges _mesh, SimplifyParameters parameters)
        {
            mesh        = _mesh;
            _parameters = parameters;
            // Gain some time by avoiding unecessary calculations
            if (_mesh.hasBoneWeights == false)
            {
                parameters.boneWeightProtection = 0.0f;
            }
            if (_mesh.hasVertexColors == false)
            {
                parameters.vertexColorProtection = 0.0f;
            }

            _calculatePdePerVertex();
            // construct heap
            int numEdges = mesh.edgeCount();

            heapNodes = new HeapNode <CollapseInfo> [numEdges];
            heap      = new MinHeap <CollapseInfo>();
            int   progressCounter = kProgressGroups;
            float t = Time.realtimeSinceStartup;

            for (int i = 0; i < numEdges; ++i)
            {
                CollapseInfo pc = new CollapseInfo();
                _calculateEdgeCost(i, pc);
                heapNodes[i] = heap.Insert(new HeapNode <CollapseInfo>(pc.cost, pc));
                progressCounter--;
                if (progressCounter <= 0)
                {
                    progressCounter = kProgressGroups;
                    if (Time.realtimeSinceStartup - t > kProgressInterval && progressDelegate != null)
                    {
                        t = Time.realtimeSinceStartup;
                        progressDelegate("Initialize Edge " + i + "/" + numEdges, 0.1f * ((float)i) / ((float)numEdges));
                    }
                }
            }

            // shortcut for fastest calc
            noPenalties = (parameters.checkTopology == false &&
                           parameters.maxEdgesPerVertex == 0 &&
                           parameters.preventNonManifoldEdges == false &&
                           parameters.boneWeightProtection <= 0.0f &&
                           parameters.vertexColorProtection <= 0.0f);
            //sharpnessLimitSqr = parameters.minTriangleShape*parameters.minTriangleShape;
            //if (parameters.minTriangleShape < 0.0f) sharpnessLimitSqr = 0.0f;
        }
Exemple #3
0
        //Vector3[] tr = new Vector3[3];

        /*
         * // rchecks result triangles against limit
         * bool _producesSharpTriangles(Mesh mesh, CollapseInfo ci, float limitSqr) {
         *      for (int k = 0; k < 2; ++k) {
         *              int vindex = ci.vp.v[k];
         *              List<int> linkedFaces = (k == 0) ? faces0 : faces1;
         *              for (int i = 0; i < linkedFaces.Count; ++i) {
         *                      Face f = mesh.faces[linkedFaces[i]];
         *                      if (f.v[0] == vindex)       { tr[0] = ci.targetPosition;            tr[1] = mesh.vertex(f.v[1]).coords; tr[2] = mesh.vertex(f.v[2]).coords; }
         *                      else if (f.v[1] == vindex)  { tr[0] = mesh.vertex(f.v[0]).coords;   tr[1] = ci.targetPosition;          tr[2] = mesh.vertex(f.v[2]).coords; }
         *                      else                        { tr[0] = mesh.vertex(f.v[0]).coords;   tr[1] = mesh.vertex(f.v[1]).coords;	tr[2] = ci.targetPosition;          }
         *                      float val = UnityUtils.TriangleCompactnessSqr(tr);
         *                      if (val < limitSqr) return true;
         *              }
         *      }
         *      return false;
         * }
         */

        // Check topology to avoid flipping the mesh by collapsing
        bool _producesBadTopology(BaseMesh mesh, CollapseInfo ci, int filterTag = 0)
        {
            Vector3       p1, origPos, vOpp, faceNormal, normal;
            List <Vertex> vertices = mesh.vertices;
            List <Face>   faces    = mesh.faces;

            for (int k = 0; k < 2; ++k)
            {
                int vindex = ci.vp.v[k];
                origPos = vertices[vindex].coords;
                IndexList linkedFacesList = (k == 0) ? faces0 : faces1;
                int[]     linkedFaces     = linkedFacesList.array;
                for (int i = 0; i < linkedFacesList.Count; ++i)
                {
                    Face f = faces[linkedFaces[i]];
                    if (f.mark >= filterTag)
                    {
                        // Construct a plane from opposing sides (p1->p2) && the face normal -> todo make this better (faster)
                        if (f.v[0] == vindex)
                        {
                            p1   = vertices[f.v[1]].coords;
                            vOpp = vertices[f.v[2]].coords - p1;
                        }
                        else if (f.v[1] == vindex)
                        {
                            p1   = vertices[f.v[2]].coords;
                            vOpp = vertices[f.v[0]].coords - p1;
                        }
                        else
                        {
                            p1   = vertices[f.v[0]].coords;
                            vOpp = vertices[f.v[1]].coords - p1;
                        }

                        faceNormal = Vector3.Cross(vOpp, origPos - p1);                   // the face normal
                        normal     = Vector3.Cross(faceNormal, vOpp);                     // normal of constructed plane
                        if (Vector3.Dot(ci.targetPosition - p1, normal) < 0.0f)
                        {
                            return(true);
                        }
                    }
                }
            }
            return(false);
        }
Exemple #4
0
        // REQUIRES triangulated mesh!
        public int CollapseVertexPair(CollapseInfo info)
        {
            if (topology != MeshTopology.Triangles)
            {
                Debug.LogError("KrablMesh: Collapsing a vertex pair requires a triangle mesh");
                return(0);
            }

            VertexPair pair = info.vp;
            int        vindex0 = pair.v[0];
            int        vindex1 = pair.v[1];
            Vertex     vertex0 = vertices[vindex0];
            Vertex     vertex1 = vertices[vindex1];
            int        i, j;

            changeFaces0.Clear();
            changeFaces1.Clear();
            removeFaces.Clear();
            CollectCollapseFacesForVertexPair(pair, changeFaces0, changeFaces1, removeFaces);

            // Adjust parameters of vertex0 to the new position
            float ratio1 = info.Ratio(this);

            // try baricentric projection on all the removeFaces (usually 2)
            int     projFaceIndex = -1;
            Face    projFace = null;
            int     projCorner0 = 0, projCorner1 = 0;
            Vector3 bari = Vector3.zero;

            int[] v = null;
            for (i = 0; i < removeFaces.Count; ++i)
            {
                Face f = faces[removeFaces[i]];
                v    = f.v;
                bari = UnityUtils.BaricentricProjection(info.targetPosition, vertices[v[0]].coords, vertices[v[1]].coords, vertices[v[2]].coords);
                if (UnityUtils.AreBaricentricCoordsInsideTriangle(bari))
                {
                    projFaceIndex = removeFaces[i];
                    projFace      = f;
                    projCorner0   = projFace.CornerIndexTriangle(vindex0);
                    projCorner1   = projFace.CornerIndexTriangle(vindex1);
                    break;
                }
            }
            // There must not be invalid faces in changeFaces0 or changeFaces1 !!!

            /*	for (i = 0; i < changeFaces0.Count; ++i) if (faces[changeFaces0[i]].valid == false) Debug.LogError("NOOO!");
             *      for (i = 0; i < changeFaces1.Count; ++i) if (faces[changeFaces1[i]].valid == false) Debug.LogError("NOOO!");
             *      for (i = 0; i < removeFaces.Count; ++i) if (faces[removeFaces[i]].valid == false) Debug.LogError("NOOO!");
             */
            // Deal with vertex colors and boneweights. these are per vertex.
            if (projFace != null)
            {
                if (hasVertexColors)
                {
                    vertex0.color = bari.x * vertices[v[0]].color + bari.y * vertices[v[1]].color + bari.z * vertices[v[2]].color;
                }
                if (hasBoneWeights)
                {
                    vertex0.boneWeight = UnityUtils.BoneWeightBaricentricInterpolation(vertices[v[0]].boneWeight, vertices[v[1]].boneWeight, vertices[v[2]].boneWeight, bari.x, bari.y, bari.z);
                }
            }
            else
            {
                if (hasVertexColors)
                {
                    vertex0.color = Color.Lerp(vertex0.color, vertex1.color, ratio1);
                }
                if (hasBoneWeights)
                {
                    vertex0.boneWeight = UnityUtils.BoneWeightLerp(vertex0.boneWeight, vertex1.boneWeight, ratio1);
                }
            }

            // Determine corner numbers for v0 in changefaces0 and v1 in changefaces1
            IndexList corners0 = new IndexList(changeFaces0.Count);

            for (i = 0; i < changeFaces0.Count; ++i)
            {
                corners0[i] = faces[changeFaces0[i]].CornerIndexTriangle(vindex0);
            }
            IndexList corners1 = new IndexList(changeFaces1.Count);

            for (i = 0; i < changeFaces1.Count; ++i)
            {
                corners1[i] = faces[changeFaces1[i]].CornerIndexTriangle(vindex1);
            }

            #region Face-Dependent Attributes (Vertex normals, uv1, uv2)

            // NORMALS
            int     count = 0, filterTag = GetUniqueTag();
            Vector3 projNormalNew = Vector3.zero;
            if (projFace != null)
            {
                projNormalNew = bari.x * projFace.vertexNormal[0] + bari.y * projFace.vertexNormal[1] + bari.z * projFace.vertexNormal[2];
                count         = _replaceCornerNormalInFaceGroup(projFace.vertexNormal[projCorner0], projNormalNew, changeFaces0, corners0, filterTag);
            }
            if (count < changeFaces0.Count)
            {
                // there are faces which cannot use baricentric projection
                for (j = 0; j < removeFaces.Count; ++j)
                {
                    if (removeFaces[j] != projFaceIndex)
                    {
                        Face    f2 = faces[removeFaces[j]]; int c0 = f2.CornerIndexTriangle(vindex0), c1 = f2.CornerIndexTriangle(vindex1);
                        Vector3 oldNormal = f2.vertexNormal[c0];
                        _replaceCornerNormalInFaceGroup(oldNormal, Vector3.Lerp(oldNormal, f2.vertexNormal[c1], ratio1), changeFaces0, corners0, filterTag);
                    }
                }
            }

            count = 0; filterTag = GetUniqueTag();
            if (projFace != null)
            {
                count = _replaceCornerNormalInFaceGroup(projFace.vertexNormal[projCorner1], projNormalNew, changeFaces1, corners1, filterTag);
            }
            if (count < changeFaces1.Count)
            {
                // there are faces which cannot use baricentric projection
                for (j = 0; j < removeFaces.Count; ++j)
                {
                    if (removeFaces[j] != projFaceIndex)
                    {
                        Face    f2 = faces[removeFaces[j]]; int c0 = f2.CornerIndexTriangle(vindex0), c1 = f2.CornerIndexTriangle(vindex1);
                        Vector3 oldNormal = f2.vertexNormal[c1];
                        _replaceCornerNormalInFaceGroup(oldNormal, Vector3.Lerp(f2.vertexNormal[c0], oldNormal, ratio1), changeFaces1, corners1, filterTag);
                    }
                }
            }

            if (hasUV1)
            {
                count = 0; filterTag = GetUniqueTag();
                Vector2 projUV1New = Vector2.zero;
                if (projFace != null)
                {
                    projUV1New = bari.x * projFace.uv1[0] + bari.y * projFace.uv1[1] + bari.z * projFace.uv1[2];
                    count      = _replaceCornerUV1InFaceGroup(projFace.uv1[projCorner0], projUV1New, changeFaces0, corners0, filterTag);
                }
                if (count < changeFaces0.Count)
                {
                    // there are faces which cannot use baricentric projection
                    for (j = 0; j < removeFaces.Count; ++j)
                    {
                        if (removeFaces[j] != projFaceIndex)
                        {
                            Face    f2 = faces[removeFaces[j]]; int c0 = f2.CornerIndexTriangle(vindex0), c1 = f2.CornerIndexTriangle(vindex1);
                            Vector2 oldUV1 = f2.uv1[c0];
                            _replaceCornerUV1InFaceGroup(oldUV1, Vector2.Lerp(oldUV1, f2.uv1[c1], ratio1), changeFaces0, corners0, filterTag);
                        }
                    }
                }

                count = 0; filterTag = GetUniqueTag();
                if (projFace != null)
                {
                    count = _replaceCornerUV1InFaceGroup(projFace.uv1[projCorner1], projUV1New, changeFaces1, corners1, filterTag);
                }
                if (count < changeFaces1.Count)
                {
                    // there are faces which cannot use baricentric projection
                    for (j = 0; j < removeFaces.Count; ++j)
                    {
                        if (removeFaces[j] != projFaceIndex)
                        {
                            Face    f2 = faces[removeFaces[j]]; int c0 = f2.CornerIndexTriangle(vindex0), c1 = f2.CornerIndexTriangle(vindex1);
                            Vector2 oldUV1 = f2.uv1[c1];
                            _replaceCornerUV1InFaceGroup(oldUV1, Vector2.Lerp(f2.uv1[c0], oldUV1, ratio1), changeFaces1, corners1, filterTag);
                        }
                    }
                }
            }

            if (hasUV2)
            {
                count = 0; filterTag = GetUniqueTag();
                Vector2 projUV2New = Vector2.zero;
                if (projFace != null)
                {
                    projUV2New = bari.x * projFace.uv2[0] + bari.y * projFace.uv2[1] + bari.z * projFace.uv2[2];
                    count      = _replaceCornerUV2InFaceGroup(projFace.uv2[projCorner0], projUV2New, changeFaces0, corners0, filterTag);
                }
                if (count < changeFaces0.Count)
                {
                    // there are faces which cannot use baricentric projection
                    for (j = 0; j < removeFaces.Count; ++j)
                    {
                        if (removeFaces[j] != projFaceIndex)
                        {
                            Face    f2 = faces[removeFaces[j]]; int c0 = f2.CornerIndexTriangle(vindex0), c1 = f2.CornerIndexTriangle(vindex1);
                            Vector2 oldUV2 = f2.uv2[c0];
                            _replaceCornerUV2InFaceGroup(oldUV2, Vector2.Lerp(oldUV2, f2.uv2[c1], ratio1), changeFaces0, corners0, filterTag);
                        }
                    }
                }

                count = 0; filterTag = GetUniqueTag();
                if (projFace != null)
                {
                    count = _replaceCornerUV2InFaceGroup(projFace.uv2[projCorner1], projUV2New, changeFaces1, corners1, filterTag);
                }
                if (count < changeFaces1.Count)
                {
                    // there are faces which cannot use baricentric projection
                    for (j = 0; j < removeFaces.Count; ++j)
                    {
                        if (removeFaces[j] != projFaceIndex)
                        {
                            Face    f2 = faces[removeFaces[j]]; int c0 = f2.CornerIndexTriangle(vindex0), c1 = f2.CornerIndexTriangle(vindex1);
                            Vector2 oldUV2 = f2.uv2[c1];
                            _replaceCornerUV2InFaceGroup(oldUV2, Vector2.Lerp(f2.uv2[c0], oldUV2, ratio1), changeFaces1, corners1, filterTag);
                        }
                    }
                }
            }
            #endregion
            // Move vertex to goal position
            vertex0.coords = info.targetPosition;

            // remove faces
            //	Debug.Log("Change faces 1 num: " + changeFaces0.Count);
            //	Debug.Log("Change faces 2 num: " + changeFaces1.Count);
            //	Debug.Log("Remove faces num: " + removeFaces.Count);
            for (i = 0; i < removeFaces.Count; ++i)
            {
                UnlinkFace(removeFaces[i]);
            }

            // change vertex on vindex1 faces, update surrounding faces on vindex0
            for (i = 0; i < changeFaces1.Count; ++i)
            {
                int  faceIndex = changeFaces1[i];
                Face f         = faces[faceIndex];
                if (f.valid)
                {
                    f.ReplaceVertex(vindex1, vindex0);
                    vertex0.linkedFaces.Add(faceIndex);
                }
            }

            // mark vindex1 as invalid
            vertex1.linkedFaces.Clear();
            if (vertex1.valid == true)
            {
                numValidVerts--;
                vertex1.valid = false;
            }
            else
            {
                Debug.LogError("vindex1 was already invalid");
            }
            return(vindex0);
        }
Exemple #5
0
 // Count number of surrounding faces after the collapse
 int _vertexDegreeAfterCollapse(BaseMesh mesh, CollapseInfo ci)
 {
     return(faces0.Count + faces1.Count);
 }
Exemple #6
0
        void _updateEdgePenalties(int edgeIndex, CollapseInfo cinfo, int movedVertexIndex = -1)
        {
            Edge   edge    = mesh.edges[edgeIndex];
            int    vindex0 = edge.v[0];
            int    vindex1 = edge.v[1];
            Vertex v0      = mesh.vertices[vindex0];
            Vertex v1      = mesh.vertices[vindex1];

            faces0.Clear();
            faces1.Clear();
            commonFaces.Clear();

            bool hadPenalty = (cinfo.cost >= kMeshPenaltyMaxEdgesPerVertex);

            cinfo.cost = cinfo.positionCost;             // reset cost
            // determine the faces involved in the collapse ..
            mesh.CollectCollapseFacesForVertexPair(mesh.edges[edgeIndex], faces0, faces1, commonFaces);

            // Penalties

            int filterTag = 0;

            if (_parameters.preventNonManifoldEdges && _producesNonManifold(mesh, cinfo))
            {
                cinfo.cost += kMeshPenaltyNonManifold;                 // largest penalty first
            }
            else
            {
                if (movedVertexIndex != -1 && hadPenalty == false)
                {
                    // For cinfos that are not new and had no penalty before, all faces besides the onces connected
                    // to the moved vertex can be skipped.
                    filterTag = mesh.GetUniqueTag();
                    IndexList linkedFaces = mesh.vertices[movedVertexIndex].linkedFaces;
                    int       count       = linkedFaces.Count;
                    for (int i = 0; i < count; ++i)
                    {
                        mesh.faces[linkedFaces[i]].mark = filterTag;
                    }
                }
                if (_parameters.checkTopology && _producesBadTopology(mesh, cinfo, filterTag))
                {
                    // Apply penalties for bad collapses
                    cinfo.cost += kMeshPenaltyBadTopology;
                }
                else if (_parameters.maxEdgesPerVertex > 0 && _vertexDegreeAfterCollapse(mesh, cinfo) > _parameters.maxEdgesPerVertex)                     // Hard coded at 18 for now.. rarely reached, but always check!
                // Avoid collapses leading to excessive stars (many verts connected to one)
                {
                    cinfo.cost += kMeshPenaltyMaxEdgesPerVertex;
                }
            }

            // Additional penalties:
            float val = 0.0f;

            if (_parameters.boneWeightProtection > 0.0f)
            {
                val += UnityUtils.BoneWeightDeltaSqr(v0.boneWeight, v1.boneWeight) * _parameters.boneWeightProtection;
            }
            if (_parameters.vertexColorProtection > 0.0f)
            {
                val += UnityUtils.ColorDeltaSqr(v0.color, v1.color) * _parameters.vertexColorProtection;
            }
            if (val != 0.0f)
            {
                cinfo.cost += 0.1f * val * mesh.EdgeLengthSqr(edgeIndex);
            }
        }
Exemple #7
0
        void _calculateEdgeCost(int edgeIndex, CollapseInfo cinfo)
        {
            Edge   edge    = mesh.edges[edgeIndex];
            int    vindex0 = edge.v[0];
            int    vindex1 = edge.v[1];
            Vertex v0      = mesh.vertices[vindex0];
            Vertex v1      = mesh.vertices[vindex1];

            cinfo.vp = edge;

            PlaneDistanceError pde = pdePerVertex[edge.v[0]] + pdePerVertex[edge.v[1]];

            if (_parameters.recalculateVertexPositions)
            {
                if (mesh.IsEdgeBorder(edgeIndex) == false && pde.OptimalVertex(ref cinfo.targetPosition))
                {
                    cinfo.cost = (float)pde.CalculateError(cinfo.targetPosition);
                    //	Debug.Log(">optimal placement");
                }
                else if (pde.OptimalVertexLinear(ref cinfo.targetPosition, v0.coords, v1.coords))
                {
                    // the error term is not solvable
                    // Try to find a vert on the line going from v0 to v1
                    cinfo.cost = (float)pde.CalculateError(cinfo.targetPosition);
                    //	Debug.Log(">line placement");
                }
                else
                {
                    // Choose vert from the two endpoints and the midpoint
                    Vector3 tp     = 0.5f * (v0.coords + v1.coords);
                    double  error0 = pde.CalculateError(v0.coords);
                    double  error1 = pde.CalculateError(v1.coords);
                    double  error2 = pde.CalculateError(tp);
                    if (error0 < error1)
                    {
                        if (error0 < error2)
                        {
                            cinfo.targetPosition = v0.coords; cinfo.cost = (float)error0;
                        }
                        else
                        {
                            cinfo.targetPosition = tp; cinfo.cost = (float)error2;
                        }
                    }
                    else
                    {
                        if (error1 < error2)
                        {
                            cinfo.targetPosition = v1.coords; cinfo.cost = (float)error1;
                        }
                        else
                        {
                            cinfo.targetPosition = tp; cinfo.cost = (float)error2;
                        }
                    }
                }
            }
            else
            {
                double error0 = pde.CalculateError(v0.coords);
                double error1 = pde.CalculateError(v1.coords);
                if (error0 < error1)
                {
                    cinfo.targetPosition = v0.coords;
                    cinfo.cost           = (float)error0;
                }
                else
                {
                    cinfo.targetPosition = v1.coords;
                    cinfo.cost           = (float)error1;
                }
            }

            // Choose minimal error point -> bad for border edges which are underdefined
            if (localizeErrors)
            {
                cinfo.cost *= 1.0f / ((float)pde.Factor());
            }

            cinfo.positionCost = cinfo.cost;

            if (noPenalties == false)
            {
                _updateEdgePenalties(edgeIndex, cinfo, -1);
            }
        }
Exemple #8
0
        public int Collapse(int numEdgesToCollapse = 1, float maxCost = 1e6f)
        {
            int collapsesDone = 0;

            while (numEdgesToCollapse > 0)
            {
                HeapNode <CollapseInfo> node;
                do
                {
                    node = heap.Extract();
                } while (node != null && mesh.isVertexPairValid(node.obj.vp) == false);
                if (node == null)
                {
                    break;
                }

                if (node.heapValue > maxCost)
                {
                    break;
                }

                CollapseInfo cinfo = node.obj;
                VertexPair   vp    = cinfo.vp;
                // Add the error terms .. v[0] is the vertex that survives the collapse
                pdePerVertex[vp.v[0]].OpAdd(pdePerVertex[vp.v[1]]);

                // DO THE COLLAPSE
                int vindex = mesh.CollapseVertexPair(cinfo);                 // vindex is the surviving vertex index

                // Need to update the cost of all edges around all linked faces of vindex
                // these are the edges connected to vindex + all the edges connected to vindex neighbours
                _edgesToUpdate.Clear();
                _surroundingVerts.Clear();

                mesh.CollectVerticesAroundVertex(vindex, ref _surroundingVerts);

                // TODO: do this better -> why?
                int mark = mesh.GetUniqueTag();
                for (int i = 0; i < _surroundingVerts.Count; ++i)
                {
                    List <int> lEdges = mesh.linkedEdgesForVert(_surroundingVerts[i]);
                    for (int j = 0; j < lEdges.Count; ++j)
                    {
                        int  edgeIndex = lEdges[j];
                        Edge e         = mesh.edges[edgeIndex];
                        if (e.mark != mark)
                        {
                            e.mark = mark;
                            if (mesh.IsEdgeValid(edgeIndex))
                            {
                                _edgesToUpdate.Add(edgeIndex);
                            }
                        }
                    }
                }

                // DO the update
                for (int i = 0; i < _edgesToUpdate.Count; ++i)
                {
                    int edgeIndex = _edgesToUpdate[i];
                    HeapNode <CollapseInfo> hnode = heapNodes[edgeIndex];
                    if (mesh.edges[edgeIndex].ContainsVertex(vindex))
                    {
                        _calculateEdgeCost(edgeIndex, hnode.obj);
                    }
                    else
                    {
                        _updateEdgePenalties(edgeIndex, hnode.obj, vindex);
                    }
                    heap.Update(hnode, hnode.obj.cost);
                }

                numEdgesToCollapse--;
                collapsesDone++;
            }
            return(collapsesDone);
        }
Exemple #9
0
        public new int CollapseVertexPair(CollapseInfo info)
        {
            VertexPair pair    = info.vp;
            int        v0      = pair.v[0];
            int        v1      = pair.v[1];
            List <int> v0Edges = linkedEdges[v0];
            List <int> v1Edges = linkedEdges[v1];
            int        i;

            // Update edges
            // Mark the vertices that are connected by edges
            for (i = 0; i < v1Edges.Count; ++i)
            {
                int edgeIndex = v1Edges[i];
                int other     = edges[edgeIndex].OtherVertex(v1);
                vertices[other].mark = -1;
            }
            for (i = 0; i < v0Edges.Count; ++i)
            {
                int edgeIndex = v0Edges[i];
                int other     = edges[edgeIndex].OtherVertex(v0);
                vertices[other].mark = edgeIndex;
            }
            // now v1 verts that are only connected to v1 have value -1, double edge-connected verts have the edgeindex as mark
            for (i = 0; i < v1Edges.Count; ++i)
            {
                int edgeIndex = v1Edges[i];
                if (vertices[edges[edgeIndex].OtherVertex(v1)].mark == -1)
                {
                    edges[edgeIndex].ReplaceVertex(v1, v0);
                    if (IsEdgeValid(edgeIndex))
                    {
                        v0Edges.Add(edgeIndex);
                    }
                }
                else
                {
                    Edge e1     = edges[edgeIndex];
                    int  vindex = e1.OtherVertex(v1);
                    Edge e0     = edges[vertices[vindex].mark];  // vertex mark is edge index!
                    // There has to be another edge connecting v0 to vertex vindex
                    e0.crease = Mathf.Max(e1.crease, e0.crease); // keep the max crease value
                    UnlinkEdge(edgeIndex);                       // no more need for this!
                }
            }
            // Remove invalid edges from mesh
            for (i = v0Edges.Count - 1; i >= 0; --i)               // backwards should be faster and i stays valid!
            {
                int edgeIndex = v0Edges[i];
                if (IsEdgeValid(edgeIndex) == false)
                {
                    UnlinkEdge(edgeIndex);
                    //v0Edges.Remove(edgeIndex);
                }
            }

            // Deal with vertices and faces in baseclass
            info.vp = new VertexPair(v0, v1);             // the original might have been invalidated THIS IS BAD
            base.CollapseVertexPair(info);
            v1Edges.Clear();

            // rebuild linkedfaces for the remaining edges
            for (i = 0; i < v0Edges.Count; ++i)
            {
                Edge edge = edges[v0Edges[i]];
                edge.linkedFaces.Clear();
                CollectVertexPairFaces(edge, edge.linkedFaces);
            }

            return(v0);
        }