Ejemplo n.º 1
0
    /// <summary>
    /// Return true if the collapse results in a valid mesh (otherwise normals may be flipped)
    /// Return false if boundary face
    /// </summary>
    /// <returns></returns>
    public bool Collapse()
    {
        var hm  = hmesh;
        var hes = Circulate();

        var      center    = GetCenter();
        Halfedge opp       = null;
        var      firstVert = hes[0].vert;

        List <Vector3D> potentialCollapsedPositions = new List <Vector3D>();
        // faces that share edges with this face
        List <Face> adjacentFaces = new List <Face>();

        potentialCollapsedPositions.Add(center);
        foreach (var he in hes)
        {
            potentialCollapsedPositions.Add(he.vert.positionD);
            if (he.opp != null)
            {
                adjacentFaces.Add(he.opp.face);
            }
            if (he.vert.IsBoundary())
            {
                // cannot collapse boundary
                return(false);
            }
        }
        adjacentFaces.Add(this);

        // faces that are affected by a collapse and their associated face normal
        Dictionary <Face, Vector3D> affectedFaceNormals = new Dictionary <Face, Vector3D>();

        foreach (var he in hes)
        {
            if (!he.vert.IsBoundary())
            {
                foreach (var halfedge in he.vert.Circulate())
                {
                    var face = halfedge.face;
                    if (!adjacentFaces.Contains(face))
                    {
                        affectedFaceNormals.Add(face, face.GetNormal());
                    }
                }
            }
        }

        // prepare removal/disconnect of face
        foreach (var he in hes)
        {
            if (he.opp != null)
            {
                opp        = he.opp;
                he.opp.opp = null;                 // remove reference to opp
            }
        }

        Vertex survivingVertes = null;

        foreach (var he in hes)
        {
            hm.Destroy(he);
        }
        hm.Destroy(this);
        if (opp != null)
        {
            var  vert          = opp.CollapseBoundaryLoop();
            bool validPosition = true;
            // find position where adjacent faces are not flipped
            for (int i = 0; i < potentialCollapsedPositions.Count; i++)
            {
                vert.positionD = potentialCollapsedPositions[i];
                validPosition  = true;
                foreach (var faceNormal in affectedFaceNormals)
                {
                    var  newNormal       = faceNormal.Key.GetNormal();
                    bool isNormalFlipped = Vector3D.Dot(newNormal, faceNormal.Value) < 0;
                    if (isNormalFlipped)
                    {
                        validPosition = false;
                    }
                }
                if (validPosition)
                {
                    return(true);
                }
                bool didNotSucceedInFindingValidPosition = (i == potentialCollapsedPositions.Count);
                if (didNotSucceedInFindingValidPosition)
                {
                    // assume center position has least damage
                    vert.positionD = potentialCollapsedPositions[i];
                }
            }
        }
        return(false);
    }