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; }