Ejemplo n.º 1
0
    // Dissolves adjacent edges when face normals are equal. Adjecent vertices are dissolved

    /*public static int RemoveAdjecentEdges(HMesh hmesh, double thresholdDistance = 0.001, double thresholdAngle = 0.1)
     * {
     *  bool changed = false;
     *  int count = 0;
     *  do
     *  {
     *      changed = false;
     *      var heCopy = new List<Halfedge>(hmesh.GetHalfedgesRaw());
     *      for (int i = 0; i < heCopy.Count; i++)
     *      {
     *          var he1 = heCopy[i];
     *          if (he1.IsDestroyed())
     *          {
     *              continue;
     *          }
     *          for (int j = i + 1; j < heCopy.Count; j++)
     *          {
     *              var he2 = heCopy[j];
     *              if (he2.IsDestroyed())
     *              {
     *                  continue;
     *              }
     *              if (he1.opp == he2)
     *              {
     *                  continue;
     *              }
     *              var distVert1 = he1.prev.vert.positionD - he2.vert.positionD;
     *              var distVert2 = he1.vert.positionD - he2.prev.vert.positionD;
     *
     *              bool isAdjacentHalfedges = distVert1.magnitude < thresholdDistance &&
     *                                         distVert2.magnitude < thresholdDistance;
     *              if (isAdjacentHalfedges){
     *                  var he1Normal = he1.face.GetNormal();
     *                  var he2Normal = he2.face.GetNormal();
     *                  bool isSameNormal = Vector3D.Angle(he1Normal, he2Normal) < thresholdAngle;
     *                  if (isSameNormal)
     *                  {
     *                      changed = true;
     *
     *                      //Debug.Log("Joining he "+he1.id+" and "+he2.id);
     *                      //Debug.Log("Joining he "+he1.face.ToString() +" and "+he2.face.ToString());
     *
     *                      var he2Vert = he2.vert;
     *                      var he2PrevVert = he2.prev.vert;
     *                      //Debug.Log("Replace "+he2Vert.id+" with "+he1.prev.vert.id);
     *                      //Debug.Log("Replace "+he2PrevVert.id+" with "+he1.vert.id);
     *                      he2Vert.ReplaceVertex(he1.prev.vert);
     *                      he2PrevVert.ReplaceVertex(he1.vert);
     *
     *                      //Debug.Log("Destroy vert "+he2Vert.id);
     *                      //Debug.Log("Destroy vert "+he2PrevVert.id);
     *                      hmesh.Destroy(he2Vert);
     *                      hmesh.Destroy(he2PrevVert);
     *
     *                      he1.Glue(he2);
     *                      //hmesh.IsValid(HMeshValidationRules.All);
     *                      //he1.Dissolve();
     *                      hmesh.IsValid(HMeshValidationRules.All);
     *                      count++;
     *                  }
     *              }
     *          }
     *      }
     *  } while (changed);
     *  return count;
     * }*/

    /// <summary>
    /// Enforces triangular mesh
    /// </summary>
    /// <param name="hmesh"></param>
    /// <returns></returns>
    public static int FixDegenerateFaces(HMesh hmesh)
    {
        int count = 0;
        var faces = new List <Face>(hmesh.GetFaces());

        for (int i = 0; i < faces.Count; i++)// (var face in hmesh.GetFaces())}
        {
            var face = faces[i];
            //var faceWas = face.ToString();
            if (face.IsDestroyed())
            {
                continue;
            }

            // triangulate
            if (face.Circulate().Count > 3)
            {
                count++;
#if HMDebug
                var str                   = face.ToString();
                var debugFaceExp          = face.ExportLocalNeighbourhoodToObj();
                System.IO.StringWriter sw = new System.IO.StringWriter();
                var res                   = face.Triangulate(false, sw);
#else
                var res = face.Triangulate();
#endif
                if (res.Count == 0)
                {
#if HMDebug
                    Debug.LogWarning("Cannot triangulate " + str + " face is now " + face.ToString() + " " + sw.ToString());
                    Debug.LogWarning(debugFaceExp);
#endif
                    // face destroyed
                    continue;
                }
                // add new faces
                for (int j = 0; j < res.Count; j++)
                {
                    if (res[j] != face)
                    {
                        faces.Add(res[j]);
                    }
                }
            }

            // fix degenerate due to zero length edge
            foreach (var he in face.Circulate())
            {
                if (he.IsDestroyed())
                {
                    continue;
                }

                if (he.GetDirection().sqrMagnitude <= hmesh.zeroMagnitudeTresholdSqr)
                {
                    Vector3D[] positions = { he.GetCenter(), he.vert.positionD, he.prev.vert.positionD };
                    bool       collapsed = false;
                    foreach (var p in positions)
                    {
                        var collapsePrecondition = he.CollapsePrecondition(p, Halfedge.CollapsePreconditionReason.EdgeIsBoundary | Halfedge.CollapsePreconditionReason.VertexIsBoundary | Halfedge.CollapsePreconditionReason.NormalFlipped);
                        if (collapsePrecondition == Halfedge.CollapsePreconditionReason.Ok)
                        {
                            count++;
                            he.Collapse();
                            collapsed = true;
                            break;
                        }
                        else
                        {
                            Debug.Log("Cannot collapse - precondition failed " + collapsePrecondition);
                        }
                    }
                    if (!collapsed)
                    {
                        he.Collapse();
                    }
                }
            }
        }

        RemoveFacesWithTwoEdges(hmesh);

        // fix degenerate due to zero area
        faces = new List <Face>(hmesh.GetFaces());
        for (int i = faces.Count - 1; i >= 0; i--)// (var face in hmesh.GetFaces())}
        {
            var face = faces[i];
            if (face.IsDestroyed())
            {
                continue;
            }

            if (face.IsDegenerate())
            {
                // find longest edge
                Halfedge longestEdge = null;
                double   maxLength   = -1;

                var edges = face.Circulate();

                Debug.Assert(edges.Count == 3, "Edges was " + edges.Count);

                foreach (var he in edges)
                {
                    double length = he.GetDirection().sqrMagnitude;
                    if (length > maxLength)
                    {
                        maxLength   = length;
                        longestEdge = he;
                    }
                }
                if (longestEdge == null)
                {
                    Debug.LogError("Face " + face.id + " only has zero length edges");
                    continue;
                }
                var    oppVert      = longestEdge.next.vert;
                Vertex oppHeOppVert = null;
                if (longestEdge.opp != null)
                {
                    oppHeOppVert = longestEdge.opp.next.vert;
                }
                var newVert = longestEdge.Split();
                newVert.positionD = oppVert.positionD;
                var longestEdgeFace = longestEdge.face;
                var res             = longestEdgeFace.Cut(oppVert, newVert);

                if (res == longestEdgeFace)
                {
                    Debug.Log("vertices");
                }

                if (oppHeOppVert != null)
                {
                    var longestEdgeOppFace = longestEdge.opp.face;
                    var newFace            = longestEdgeOppFace.Cut(newVert, oppHeOppVert);
                    faces.Add(newFace);
                    faces.Add(longestEdgeOppFace); // reevaluate face
                }
                var sharedEdge = oppVert.GetSharedEdge(newVert);
                if (sharedEdge == null)
                {
                    Debug.Log("Cannot find shared edge between " + oppVert + " " + newVert);
                    continue;
                }
                var sharedEdgeFace1 = sharedEdge.face;
                var sharedEdgeFace2 = sharedEdge.opp.face; // ensured to exist (just created)
                var precond         = sharedEdge.CollapsePrecondition(true, Halfedge.CollapsePreconditionReason.NormalFlipped);
                if (precond == Halfedge.CollapsePreconditionReason.Ok)
                {
                    sharedEdge.Collapse(true);
                    Debug.Assert(sharedEdgeFace1.IsDestroyed());
                    Debug.Assert(sharedEdgeFace2.IsDestroyed());
                    count++;
                }
                else
                {
                    Debug.Log(precond);
                }
            }
        }
        return(count);
    }