All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.uci.ics.jung.algorithms.layout.TreeLayout Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
/*
 * Copyright (c) 2005, the JUNG Project and the Regents of the University of
 * California All rights reserved.
 *
 * This software is open-source under the BSD license; see either "license.txt"
 * or http://jung.sourceforge.net/license.txt for a description.
 *
 * Created on Jul 9, 2005
 */

package edu.uci.ics.jung.algorithms.layout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections15.Transformer;
import org.apache.commons.collections15.map.LazyMap;

import edu.uci.ics.jung.graph.Forest;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.util.TreeUtils;

/**
 * @author Karlheinz Toni
 * @author Tom Nelson - converted to jung2
 *  
 */

public class TreeLayout implements Layout {

	protected Dimension size = new Dimension(600,600);
	protected Forest graph;
	protected Map basePositions = new HashMap();

    protected Map locations = 
    	LazyMap.decorate(new HashMap(),
    			new Transformer() {
					public Point2D transform(V arg0) {
						return new Point2D.Double();
					}});
    
    protected transient Set alreadyDone = new HashSet();

    /**
     * The default horizontal vertex spacing.  Initialized to 50.
     */
    public static int DEFAULT_DISTX = 50;
    
    /**
     * The default vertical vertex spacing.  Initialized to 50.
     */
    public static int DEFAULT_DISTY = 50;
    
    /**
     * The horizontal vertex spacing.  Defaults to {@code DEFAULT_XDIST}.
     */
    protected int distX = 50;
    
    /**
     * The vertical vertex spacing.  Defaults to {@code DEFAULT_YDIST}.
     */
    protected int distY = 50;
    
    protected transient Point m_currentPoint = new Point();

    /**
     * Creates an instance for the specified graph with default X and Y distances.
     */
    public TreeLayout(Forest g) {
    	this(g, DEFAULT_DISTX, DEFAULT_DISTY);
    }

    /**
     * Creates an instance for the specified graph and X distance with
     * default Y distance.
     */
    public TreeLayout(Forest g, int distx) {
        this(g, distx, DEFAULT_DISTY);
    }

    /**
     * Creates an instance for the specified graph, X distance, and Y distance.
     */
    public TreeLayout(Forest g, int distx, int disty) {
        if (g == null)
            throw new IllegalArgumentException("Graph must be non-null");
        if (distx < 1 || disty < 1)
            throw new IllegalArgumentException("X and Y distances must each be positive");
    	this.graph = g;
        this.distX = distx;
        this.distY = disty;
        buildTree();
    }
    
	protected void buildTree() {
        this.m_currentPoint = new Point(0, 20);
        Collection roots = TreeUtils.getRoots(graph);
        if (roots.size() > 0 && graph != null) {
       		calculateDimensionX(roots);
       		for(V v : roots) {
        		calculateDimensionX(v);
        		m_currentPoint.x += this.basePositions.get(v)/2 + this.distX;
        		buildTree(v, this.m_currentPoint.x);
        	}
        }
        int width = 0;
        for(V v : roots) {
        	width += basePositions.get(v);
        }
    }

    protected void buildTree(V v, int x) {

        if (!alreadyDone.contains(v)) {
            alreadyDone.add(v);

            //go one level further down
            this.m_currentPoint.y += this.distY;
            this.m_currentPoint.x = x;

            this.setCurrentPositionFor(v);

            int sizeXofCurrent = basePositions.get(v);

            int lastX = x - sizeXofCurrent / 2;

            int sizeXofChild;
            int startXofChild;

            for (V element : graph.getSuccessors(v)) {
                sizeXofChild = this.basePositions.get(element);
                startXofChild = lastX + sizeXofChild / 2;
                buildTree(element, startXofChild);
                lastX = lastX + sizeXofChild + distX;
            }
            this.m_currentPoint.y -= this.distY;
        }
    }
    
    private int calculateDimensionX(V v) {

        int size = 0;
        int childrenNum = graph.getSuccessors(v).size();

        if (childrenNum != 0) {
            for (V element : graph.getSuccessors(v)) {
                size += calculateDimensionX(element) + distX;
            }
        }
        size = Math.max(0, size - distX);
        basePositions.put(v, size);

        return size;
    }

    private int calculateDimensionX(Collection roots) {

    	int size = 0;
    	for(V v : roots) {
    		int childrenNum = graph.getSuccessors(v).size();

    		if (childrenNum != 0) {
    			for (V element : graph.getSuccessors(v)) {
    				size += calculateDimensionX(element) + distX;
    			}
    		}
    		size = Math.max(0, size - distX);
    		basePositions.put(v, size);
    	}

    	return size;
    }
    
    /**
     * This method is not supported by this class.  The size of the layout
     * is determined by the topology of the tree, and by the horizontal 
     * and vertical spacing (optionally set by the constructor).
     */
    public void setSize(Dimension size) {
        throw new UnsupportedOperationException("Size of TreeLayout is set" +
                " by vertex spacing in constructor");
    }

    protected void setCurrentPositionFor(V vertex) {
    	int x = m_currentPoint.x;
    	int y = m_currentPoint.y;
    	if(x < 0) size.width -= x;
    	
    	if(x > size.width-distX) 
    		size.width = x + distX;
    	
    	if(y < 0) size.height -= y;
    	if(y > size.height-distY) 
    		size.height = y + distY;
    	locations.get(vertex).setLocation(m_currentPoint);

    }

	public Graph getGraph() {
		return graph;
	}

	public Dimension getSize() {
		return size;
	}

	public void initialize() {

	}

	public boolean isLocked(V v) {
		return false;
	}

	public void lock(V v, boolean state) {
	}

	public void reset() {
	}

	public void setGraph(Graph graph) {
		if(graph instanceof Forest) {
			this.graph = (Forest)graph;
			buildTree();
		} else {
			throw new IllegalArgumentException("graph must be a Forest");
		}
	}

	public void setInitializer(Transformer initializer) {
	}
	
    /**
     * Returns the center of this layout's area.
     */
	public Point2D getCenter() {
		return new Point2D.Double(size.getWidth()/2,size.getHeight()/2);
	}

	public void setLocation(V v, Point2D location) {
		locations.get(v).setLocation(location);
	}
	
	public Point2D transform(V v) {
		return locations.get(v);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy