private Iterator sortedChildren(final NodeItem n) {
    double base = 0;
    // update base angle for node ordering
    NodeItem p = (NodeItem) n.getParent();
    if (p != null) {
      base = normalize(Math.atan2(p.getY() - n.getY(), p.getX() - n.getX()));
    }
    int cc = n.getChildCount();
    if (cc == 0) return null;

    NodeItem c = (NodeItem) n.getFirstChild();

    if (!c.isStartVisible()) {
      // use natural ordering for previously invisible nodes
      return n.children();
    }

    double angle[] = new double[cc];
    final int idx[] = new int[cc];
    for (int i = 0; i < cc; ++i, c = (NodeItem) c.getNextSibling()) {
      idx[i] = i;
      angle[i] = normalize(-base + Math.atan2(c.getY() - n.getY(), c.getX() - n.getX()));
    }
    ArrayLib.sort(angle, idx);

    // return iterator over sorted children
    return new Iterator() {
      int cur = 0;

      public Object next() {
        return n.getChild(idx[cur++]);
      }

      public boolean hasNext() {
        return cur < idx.length;
      }

      public void remove() {
        throw new UnsupportedOperationException();
      }
    };
  }
  /**
   * Compute the layout.
   *
   * @param n the root of the current subtree under consideration
   * @param r the radius, current distance from the center
   * @param theta1 the start (in radians) of this subtree's angular region
   * @param theta2 the end (in radians) of this subtree's angular region
   */
  protected void layout(NodeItem n, double r, double theta1, double theta2) {
    double dtheta = (theta2 - theta1);
    double dtheta2 = dtheta / 2.0;
    double width = ((Params) n.get(PARAMS)).width;
    double cfrac, nfrac = 0.0;

    Iterator childIter = sortedChildren(n);
    while (childIter != null && childIter.hasNext()) {
      NodeItem c = (NodeItem) childIter.next();
      Params cp = (Params) c.get(PARAMS);
      cfrac = cp.width / width;
      if (c.isExpanded() && c.getChildCount() > 0) {
        layout(c, r + m_radiusInc, theta1 + nfrac * dtheta, theta1 + (nfrac + cfrac) * dtheta);
      }
      setPolarLocation(c, n, r, theta1 + nfrac * dtheta + cfrac * dtheta2);

      cp.angle = cfrac * dtheta;
      nfrac += cfrac;
    }
  }
  /**
   * Computes relative measures of the angular widths of each expanded subtree. Node diameters are
   * taken into account to improve space allocation for variable-sized nodes.
   *
   * <p>This method also updates the base angle value for nodes to ensure proper ordering of nodes.
   */
  private double calcAngularWidth(NodeItem n, int d) {
    if (d > m_maxDepth) m_maxDepth = d;
    double aw = 0;

    Rectangle2D bounds = n.getBounds();
    double w = bounds.getWidth(), h = bounds.getHeight();
    double diameter = d == 0 ? 0 : Math.sqrt(w * w + h * h) / d;

    if (n.isExpanded() && n.getChildCount() > 0) {
      Iterator childIter = n.children();
      while (childIter.hasNext()) {
        NodeItem c = (NodeItem) childIter.next();
        aw += calcAngularWidth(c, d + 1);
      }
      aw = Math.max(diameter, aw);
    } else {
      aw = diameter;
    }
    ((Params) n.get(PARAMS)).width = aw;
    return aw;
  }