/// <summary>
        /// Get a face loop or ring from a set of winged edges.
        /// </summary>
        /// <param name="wings"></param>
        /// <param name="face"></param>
        /// <param name="ring"></param>
        /// <returns></returns>
        static HashSet <Face> GetFaceLoop(List <WingedEdge> wings, Face face, bool ring)
        {
            HashSet <Face> loop = new HashSet <Face>();

            if (face == null)
            {
                return(loop);
            }

            WingedEdge start = wings.FirstOrDefault(x => x.face == face);

            if (start == null)
            {
                return(loop);
            }

            if (ring)
            {
                start = start.next ?? start.previous;
            }

            for (int i = 0; i < 2; i++)
            {
                WingedEdge cur = start;

                if (i == 1)
                {
                    if (start.opposite != null && start.opposite.face != null)
                    {
                        cur = start.opposite;
                    }
                    else
                    {
                        break;
                    }
                }

                do
                {
                    if (!loop.Add(cur.face))
                    {
                        break;
                    }

                    if (cur.Count() != 4)
                    {
                        break;
                    }

                    // count == 4 assures us next.next is valid, but opposite can still be null
                    cur = cur.next.next.opposite;
                }while (cur != null && cur.face != null);
            }

            return(loop);
        }