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(); } }; }
/** * Calculates the angular bounds of the layout, attempting to preserve the angular orientation of * the display across transitions. */ private void calcAngularBounds(NodeItem r) { if (m_prevRoot == null || !m_prevRoot.isValid() || r == m_prevRoot) { m_prevRoot = r; return; } // try to find previous parent of root NodeItem p = m_prevRoot; while (true) { NodeItem pp = (NodeItem) p.getParent(); if (pp == r) { break; } else if (pp == null) { m_prevRoot = r; return; } p = pp; } // compute offset due to children's angular width double dt = 0; Iterator iter = sortedChildren(r); while (iter.hasNext()) { Node n = (Node) iter.next(); if (n == p) break; dt += ((Params) n.get(PARAMS)).width; } double rw = ((Params) r.get(PARAMS)).width; double pw = ((Params) p.get(PARAMS)).width; dt = -MathLib.TWO_PI * (dt + pw / 2) / rw; // set angular bounds m_theta1 = dt + Math.atan2(p.getY() - r.getY(), p.getX() - r.getX()); m_theta2 = m_theta1 + MathLib.TWO_PI; m_prevRoot = r; }