Java tutorial
/* * 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 com.mycompany.complexity.tool.mvn; import edu.uci.ics.jung.algorithms.layout.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; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Function; /** * @author Karlheinz Toni * @author Tom Nelson - converted to jung2 * */ public class TreeLayoutDois<V extends Comparable, E> implements Layout<V, E> { protected Dimension size = new Dimension(600, 600); protected Forest<V, E> graph; protected Map<V, Integer> basePositions = new HashMap<V, Integer>(); protected Map<V, Point2D> locations = LazyMap.decorate(new HashMap<V, Point2D>(), new Transformer<V, Point2D>() { public Point2D transform(V arg0) { return new Point2D.Double(); } }); // LazyMap.decorate(new HashMap<V, Point2D>(), // new Function<V,Point2D>() { // public Point2D transform(V arg0) { // return new Point2D.Double(); // }}); protected transient Set<V> alreadyDone = new HashSet<V>(); /** * 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(); protected Set<V> alreadyCalculatedY = new HashSet<>(); protected int maxHeight; /** * Creates an instance for the specified graph with default X and Y * distances. */ public TreeLayoutDois(Forest<V, E> g) { this(g, DEFAULT_DISTX, DEFAULT_DISTY); } /** * Creates an instance for the specified graph and X distance with default Y * distance. */ public TreeLayoutDois(Forest<V, E> g, int distx) { this(g, distx, DEFAULT_DISTY); } /** * Creates an instance for the specified graph, X distance, and Y distance. */ public TreeLayoutDois(Forest<V, E> 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; this.maxHeight = calculateDimensionY(TreeUtils.getRoots(graph)); buildTree(); } protected void buildTree() { this.m_currentPoint = new Point(0, 20); Collection<V> 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); this.m_currentPoint.x = x; if (graph.inDegree(v) > 4) { this.m_currentPoint.y += maxHeight; this.m_currentPoint.x = size.width / 2; } else { //go one level further down this.m_currentPoint.y += this.distY; } 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; } if (graph.inDegree(v) > 5) { this.m_currentPoint.y -= this.maxHeight; } else { 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<V> 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; } private int calculateDimensionY(V v) { int size = 0; int childrenNum = graph.getSuccessors(v).size(); List<Integer> maxSize = new ArrayList<>(); if (childrenNum != 0) { for (V element : graph.getSuccessors(v)) { if (!alreadyCalculatedY.contains(element)) { alreadyCalculatedY.add(element); size += calculateDimensionY(element) + distY; } } } size = Math.max(0, size - distY); maxSize.add(size); return Collections.max(maxSize); } private int calculateDimensionY(Collection<V> roots) { int size = 0; List<Integer> maxSize = new ArrayList<>(); for (V v : roots) { int childrenNum = graph.getSuccessors(v).size(); if (childrenNum != 0) { for (V element : graph.getSuccessors(v)) { if (!alreadyCalculatedY.contains(element)) { alreadyCalculatedY.add(element); size += calculateDimensionY(element) + distY; } } } size = Math.max(0, size - distY); maxSize.add(size); } return Collections.max(maxSize); } /** * 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<V, E> 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<V, E> graph) { if (graph instanceof Forest) { this.graph = (Forest<V, E>) graph; buildTree(); } else { throw new IllegalArgumentException("graph must be a Forest"); } } public void setInitializer(Function<V, Point2D> 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); } public void setInitializer(Transformer<V, Point2D> initializer) { } }