package org.andork.j3d; import java.util.Iterator; import java.util.Stack; import javax.media.j3d.Group; import javax.media.j3d.Node; import org.omg.CORBA.IntHolder; /** * Iterates through the scene graph. There are two types of SceneGraphIterators: bounded and unbounded. A bounded iterator will only iterate through the start * node an all of its descendants. An unbounded iterator will continue a depth-first iteration through the entire scene graph after it finishes with the start * node and its descendants. */ public class SceneGraphIterator implements Iterator<Node> { public SceneGraphIterator( Node start ) { this( start , false ); } public SceneGraphIterator( Node start , boolean bounded ) { current = start; if( !bounded ) { initStack( current ); } } void initStack( Node start ) { Node child = start; Node parent = child.getParent( ); final Stack<IntHolder> revStack = new Stack<IntHolder>( ); while( parent != null ) { if( parent instanceof Group ) { revStack.push( new IntHolder( ( ( Group ) parent ).indexOfChild( child ) ) ); } child = parent; parent = child.getParent( ); } while( !revStack.isEmpty( ) ) { indexStack.push( revStack.pop( ) ); } } Node current; Stack<IntHolder> indexStack = new Stack<IntHolder>( ); @Override public boolean hasNext( ) { return current != null; } public static Node next( Node node ) { if( node instanceof Group ) { return ( ( Group ) node ).getChild( 0 ); } Node current = node; while( current != null ) { final Node parent = current.getParent( ); if( parent == null ) { return null; } if( parent instanceof Group ) { final Group g = ( Group ) parent; final int nextIndex = g.indexOfChild( current ) + 1; if( nextIndex < g.numChildren( ) ) { return g.getChild( nextIndex ); } } current = parent; } return null; } @Override public Node next( ) { final Node result = current; if( current instanceof Group && ( ( Group ) current ).numChildren( ) > 0 ) { indexStack.push( new IntHolder( 0 ) ); current = ( ( Group ) current ).getChild( 0 ); return result; } while( current != null && !indexStack.isEmpty( ) ) { final Node parent = current.getParent( ); final IntHolder index = indexStack.peek( ); if( parent == null ) { indexStack.clear( ); current = null; break; } if( parent instanceof Group ) { final Group g = ( Group ) parent; index.value++ ; if( index.value < g.numChildren( ) ) { current = g.getChild( index.value ); break; } } indexStack.pop( ); current = parent; } if( indexStack.isEmpty( ) ) { current = null; } return result; } @Override public void remove( ) { throw new UnsupportedOperationException( ); } public static Iterable<Node> boundedIterable( final Node start ) { return new Iterable<Node>( ) { @Override public Iterator<Node> iterator( ) { return new SceneGraphIterator( start , true ); } }; } public static Iterable<Node> unboundedIterable( final Node start ) { return new Iterable<Node>( ) { @Override public Iterator<Node> iterator( ) { return new SceneGraphIterator( start ); } }; } public static Iterator<Node> childIterator( final Group g ) { return new Iterator<Node>( ) { int i = 0; @Override public boolean hasNext( ) { return i < g.numChildren( ); } @Override public Node next( ) { return g.getChild( i++ ); } @Override public void remove( ) { g.removeChild( i - 1 ); } }; } public static Iterable<Node> childIterable( final Group g ) { return new Iterable<Node>( ) { @Override public Iterator<Node> iterator( ) { return childIterator( g ); } }; } }