/** * Copyright (c) 2004-2006 Regents of the University of California. * See "license-prefuse.txt" for licensing terms. */ package prefuse.data; import java.util.BitSet; import java.util.Iterator; import java.util.LinkedList; import prefuse.data.tuple.TupleManager; import prefuse.visual.tuple.TableEdgeItem; /** * Special tree instance for storing a spanning tree over a graph * instance. The spanning tree ensures that only Node and Edge instances * from the backing Graph are returned, so requesting nodes, edges, or * iterators over this spanning tree will return the desired Node or * Edge tuples from the backing graph this tree spans. * * @author <a href="http://jheer.org">jeffrey heer</a> */ public class SpanningTree extends Tree { /** Extra edge table data field recording the id of the source edge * a tree edge represents. */ public static final String SOURCE_EDGE = "source"; /** Edge table schema used by the spanning tree. */ protected static final Schema EDGE_SCHEMA = new Schema(); static { EDGE_SCHEMA.addColumn(DEFAULT_SOURCE_KEY, int.class, new Integer(-1)); EDGE_SCHEMA.addColumn(DEFAULT_TARGET_KEY, int.class, new Integer(-1)); EDGE_SCHEMA.addColumn(SOURCE_EDGE, int.class); } /** A reference to the backing graph that this tree spans. */ protected Graph m_backing; /** * Create a new SpanningTree. * @param g the backing Graph to span * @param root the Node to use as the root of the spanning tree */ public SpanningTree(Graph g, Node root) { super(g.getNodeTable(), EDGE_SCHEMA.instantiate()); m_backing = g; TupleManager etm = new TupleManager(getEdgeTable(), null, TableEdgeItem.class) { public Tuple getTuple(int row) { return m_backing.getEdge(m_table.getInt(row, SOURCE_EDGE)); } }; getEdgeTable().setTupleManager(etm); super.setTupleManagers(g.m_nodeTuples, etm); buildSpanningTree(root); } /** * Build the spanning tree, starting at the given root. Uses an * unweighted breadth first traversal to build the spanning tree. * @param root the root node of the spanning tree */ public void buildSpanningTree(Node root) { // re-use a previously allocated tree if possible super.clearEdges(); super.setRoot(root); // build unweighted spanning tree by BFS LinkedList q = new LinkedList(); BitSet visit = new BitSet(); q.add(root); visit.set(root.getRow()); Table edges = getEdgeTable(); while ( !q.isEmpty() ) { Node p = (Node)q.removeFirst(); for ( Iterator iter = p.edges(); iter.hasNext(); ) { Edge e = (Edge)iter.next(); Node n = e.getAdjacentNode(p); if ( !visit.get(n.getRow()) ) { q.add(n); visit.set(n.getRow()); int er = super.addChildEdge(p.getRow(), n.getRow()); edges.setInt(er, SOURCE_EDGE, e.getRow()); } } } } // ------------------------------------------------------------------------ // Disallow most mutator methods /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Tree#addChild(int) */ public int addChild(int parent) { throw new UnsupportedOperationException( "Changes to tree structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Tree#addChild(prefuse.data.Node) */ public Node addChild(Node parent) { throw new UnsupportedOperationException( "Changes to tree structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Tree#addChildEdge(int, int) */ public int addChildEdge(int parent, int child) { throw new UnsupportedOperationException( "Changes to tree structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Tree#addChildEdge(prefuse.data.Node, prefuse.data.Node) */ public Edge addChildEdge(Node parent, Node child) { throw new UnsupportedOperationException( "Changes to tree structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Tree#addRoot() */ public Node addRoot() { throw new UnsupportedOperationException( "Changes to tree structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Tree#addRootRow() */ public int addRootRow() { throw new UnsupportedOperationException( "Changes to tree structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Tree#removeChild(int) */ public boolean removeChild(int node) { throw new UnsupportedOperationException( "Changes to tree structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Tree#removeChild(prefuse.data.Node) */ public boolean removeChild(Node n) { throw new UnsupportedOperationException( "Changes to tree structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Tree#removeChildEdge(prefuse.data.Edge) */ public boolean removeChildEdge(Edge e) { throw new UnsupportedOperationException( "Changes to tree structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Tree#removeChildEdge(int) */ public boolean removeChildEdge(int edge) { throw new UnsupportedOperationException( "Changes to tree structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Tree#setRoot(prefuse.data.Node) */ void setRoot(Node root) { throw new UnsupportedOperationException( "Changes to tree structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Graph#addEdge(int, int) */ public int addEdge(int s, int t) { throw new UnsupportedOperationException( "Changes to graph structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Graph#addEdge(prefuse.data.Node, prefuse.data.Node) */ public Edge addEdge(Node s, Node t) { throw new UnsupportedOperationException( "Changes to graph structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Graph#addNode() */ public Node addNode() { throw new UnsupportedOperationException( "Changes to graph structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Graph#addNodeRow() */ public int addNodeRow() { throw new UnsupportedOperationException( "Changes to graph structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.tuple.TupleSet#clear() */ public void clear() { throw new UnsupportedOperationException( "Changes to graph structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Graph#removeEdge(prefuse.data.Edge) */ public boolean removeEdge(Edge e) { throw new UnsupportedOperationException( "Changes to graph structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Graph#removeEdge(int) */ public boolean removeEdge(int edge) { throw new UnsupportedOperationException( "Changes to graph structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Graph#removeNode(int) */ public boolean removeNode(int node) { throw new UnsupportedOperationException( "Changes to graph structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Graph#removeNode(prefuse.data.Node) */ public boolean removeNode(Node n) { throw new UnsupportedOperationException( "Changes to graph structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.tuple.TupleSet#removeTuple(prefuse.data.Tuple) */ public boolean removeTuple(Tuple t) { throw new UnsupportedOperationException( "Changes to graph structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Graph#setEdgeTable(prefuse.data.Table) */ public void setEdgeTable(Table edges) { throw new UnsupportedOperationException( "Changes to graph structure not allowed for spanning trees."); } /** * Unsupported operation. Spanning trees should not be edited. * @see prefuse.data.Graph#setTupleManagers(prefuse.data.tuple.TupleManager, prefuse.data.tuple.TupleManager) */ public void setTupleManagers(TupleManager ntm, TupleManager etm) { throw new UnsupportedOperationException( "Changes to graph structure not allowed for spanning trees."); } } // end of class SpanningTree