/// <summary>
    /// Finds the coords. of the next item in the <see cref="PackedLayout"/> if it's
    /// added vertically.
    /// </summary>
    /// <param name="x">X coord. of previous node</param>
    /// <param name="y">Y coord. of previous node</param>
    /// <param name="verts">The list of all nodes</param>
    /// <param name="v">The index of the previous node in verts</param>
    /// <param name="newx">Returns the x coord. of the new node</param>
    /// <param name="newy">Returns the y coord. of the new node</param>
    /// <param name="dir">Whether the nodes are arranged Clockwise or Counterclockwise</param>
    /// <returns>true if a node can be added vertically and still be on the ellipse</returns>
    private bool nextv(double x, double y, CircularVertex[] verts, int v, out double newx, out double newy, CircularDirection dir) {
      newx = 0;
      newy = 0;
      bool inv = false; //true if it changes sides
      if (x >= 0 ^ dir == CircularDirection.Clockwise) {
        // y decreases
        newy = y - ((verts[v].Height + verts[v + 1].Height) / 2 + ESpacing);
        if (newy < -Yradius) {
          // y increases
          newy = y + ((verts[v].Height + verts[v + 1].Height) / 2 + ESpacing);
          if (newy > Yradius) { return false; }
          inv = true;
        }
      } else {
        // y increases
        newy = y + ((verts[v].Height + verts[v + 1].Height) / 2 + ESpacing);
        if (newy > Yradius) {
          // y decreases
          newy = y - ((verts[v].Height + verts[v + 1].Height) / 2 + ESpacing);
          if (newy < -Yradius) { return false; }
          inv = true;
        }
      }

      newx = Math.Sqrt(1 - newy * newy / (Yradius * Yradius)) * ERadius;
      if (x < 0 ^ inv) { newx = -newx; }
      if (Math.Abs(x - newx) > (verts[v].Width + verts[v + 1].Width) / 2) { return false; } else return true;
    }
    private Random rand; // Packed layout sometimes alternates between 2 radii.  If this happens, a random value is added to stop the cycle.

    /// <summary>
    /// Finds the coords. of the next item in the <see cref="PackedLayout"/> if it's
    /// added horizontally.
    /// </summary>
    /// <param name="x">X coord. of previous node</param>
    /// <param name="y">Y coord. of previous node</param>
    /// <param name="verts">The list of all nodes</param>
    /// <param name="v">The index of the previous node in verts</param>
    /// <param name="newx">Returns the x coord. of the new node</param>
    /// <param name="newy">Returns the y coord. of the new node</param>
    /// <param name="dir">Whether the nodes are arranged Clockwise or Counterclockwise</param>
    /// <returns>true if a node can be added horizontally and still be on the ellipse</returns>
    private bool nexth(double x, double y, CircularVertex[] verts, int v, out double newx, out double newy, CircularDirection dir) {
      newx = 0;
      newy = 0;
      bool inv = false; //true if it changes sides
      if (y >= 0 ^ dir == CircularDirection.Clockwise) {
        // x increases
        newx = x + ((verts[v].Width + verts[v + 1].Width) / 2 + ESpacing);
        if (newx > ERadius) {
          // x decreases
          newx = x - ((verts[v].Width + verts[v + 1].Width) / 2 + ESpacing);
          if (newx < -ERadius) { return false; }
          inv = true;
        }
      } else {

        // x decreases
        newx = x - ((verts[v].Width + verts[v + 1].Width) / 2 + ESpacing);
        if (newx < -ERadius) {
          newx = x + ((verts[v].Width + verts[v + 1].Width) / 2 + ESpacing);
          if (newx > ERadius) { return false; }
          inv = true;
        }
      }

      newy = Math.Sqrt(1 - newx * newx / (ERadius * ERadius)) * Yradius;
      if (y < 0 ^ inv) { newy = -newy; }
      if (Math.Abs(y - newy) > (verts[v].Height + verts[v + 1].Height) / 2) { return false; } else return true;
    }
 public Subset(CircularVertex n, List<Subset> gs) {
   List = new List<CircularVertex>(); Conns = new List<CircularVertex>();
   Head = n;
   List.Add(n);
   foreach (Subset g in gs) {
     foreach (CircularVertex nd in g.List) { this.List.Add(nd); }
   }
   foreach (CircularEdge li in n.SourceEdgesList) {
     CircularVertex nd = li.FromVertex;
     if (List.IndexOf(nd) < 0) { Conns.Add(nd); }
   }
   foreach (CircularEdge li in n.DestinationEdgesList) {
     CircularVertex nd = li.ToVertex;
     if (List.IndexOf(nd) < 0) { Conns.Add(nd); }
   }
 }
    /// <summary>
    /// Sorts the nodes based on connectivity.  The oth node is the one with the highest
    /// connectivity, and each subsequent node it the one with the greatest number of links with nodes
    /// already in the list
    /// </summary>
    /// <param name="l">The nodes to sort</param>
    /// <returns>The sorted list</returns>
    /// <remarks>This is used for cross reduction before <see cref="Optimize"/> is called because
    /// it makes the cross reduction much more effective.
    /// </remarks>
    private List<CircularVertex> ConnectivityArrange(CircularVertex[] l) {
      int[] conns = new int[l.Length];
      List<CircularVertex> res = new List<CircularVertex>();
      for (int i = 0; i < l.Length; i++) {
        int maxconn = -1;
        int maxind = -1;
        if (i == 0) {
          for (int j = 0; j < l.Length; j++) {
            CircularVertex vtx = l[j];
            int nconn = vtx.SourceEdgesCount + vtx.DestinationEdgesCount;
            if (nconn > maxconn) {
              maxconn = nconn;
              maxind = j;
            }
          }
        } else for (int j = 0; j < l.Length; j++) {
            int nconn = conns[j];
            if (nconn > maxconn) {
              maxconn = nconn;
              maxind = j;
            }
          }
        res.Add(l[maxind]);
        conns[maxind] = -1;

        CircularVertex v = l[maxind];
        foreach (CircularEdge li in v.SourceEdgesList) {
          CircularVertex f = li.FromVertex;
          int ind = Array.IndexOf(l, f);
          if (ind < 0) { continue; }
          if (conns[ind] >= 0) { conns[ind]++; }
        }
        foreach (CircularEdge li in v.DestinationEdgesList) {
          CircularVertex f = li.ToVertex;
          int ind = Array.IndexOf(l, f);
          if (ind < 0) { continue; }
          if (conns[ind] >= 0) { conns[ind]++; }
        }
      }
      return res;
    }
 /// <summary>
 /// Sorts the vertexes based on whatever <see cref="Sorting"/> specifies.
 /// </summary>
 /// <param name="vertexes">The vertexes to sort</param>
 private List<CircularVertex> Sort(CircularVertex[] vertexes) {
   switch (Sorting) {
     case CircularSorting.Forwards: break;
     case CircularSorting.Reverse: Array.Reverse(vertexes, 0, vertexes.Length); break;
     case CircularSorting.Ascending: if (Comparer != null) { Array.Sort(vertexes, Comparer); } break;
     case CircularSorting.Descending: if (Comparer != null) { Array.Sort(vertexes, Comparer); }
       Array.Reverse(vertexes, 0, vertexes.Length); break;
     case CircularSorting.Optimized: return Optimize(ConnectivityArrange(vertexes));
     //case CircularSorting.GroupedOptimized: return OptimizeGroup(ConnectivityArrange(new List<CircularVertex>(nodes)));
     default: throw new NotImplementedException("This CircularSorting is not yet implemented");
   }
   return new List<CircularVertex>(vertexes);
 }
 /// <summary>
 /// Compares a new gap with the current one.  If it's better, it updates <see cref="gap"/>, <see cref="xcoords"/>,and <see cref="ycoords"/>.
 /// This is for a partial sweep, where overshooting (gap less than 0) is no worse than undershooting (gap > 0).
 /// </summary>
 /// <param name="gap"></param>
 /// <param name="verts"></param>
 public void compare2(double gap, CircularVertex[] verts) {
   if (Math.Abs(gap) < Math.Abs(this.gap)) {
     this.gap = gap;
     xcoords = new double[verts.Length];
     ycoords = new double[verts.Length];
     for (int i = 0; i < verts.Length; i++) {
       xcoords[i] = verts[i].Position.X;
       ycoords[i] = verts[i].Position.Y;
     }
   }
 }