⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sugiyamalayoutalgorithm.java

📁 用JGraph编的软件
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
// This file is part of the Echidna project
// (C) 2002 Forschungszentrum Informatik (FZI) Karlsruhe
// Please visit our website at http://echidna.sf.net
package org.jgraph.layout;

import java.awt.Frame;
import java.awt.Point;
import java.awt.Rectangle;
import java.text.NumberFormat;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;

import javax.swing.JOptionPane;

import org.jgraph.JGraph;
import org.jgraph.graph.CellView;
import org.jgraph.graph.GraphConstants;
import org.jgraph.graph.GraphModel;
import org.jgraph.graph.VertexView;
import org.jgraph.pad.resources.Translator;

/**
 * Arranges the nodes with the Sugiyama Layout Algorithm.<br>
 *
 * <a href="http://plg.uwaterloo.ca/~itbowman/CS746G/Notes/Sugiyama1981_MVU/">
 *  Link to the algorithm</a>
 *
 *<br>
 *<br>
 * @author Sven Luzar<br>
 * @version 1.0 init
 */
public class SugiyamaLayoutAlgorithm implements LayoutAlgorithm {

	/** Field for debug output
	 */
	protected final boolean verbose = false;

	/** Const to add Attributes at the Nodes
	 *
	 */
	public static final String SUGIYAMA_VISITED = "SugiyamaVisited" /*#Frozen*/;

	/** Const to add the Cell Wrapper to the Nodes
	 */
	public static final String SUGIYAMA_CELL_WRAPPER =
		"SugiyamaCellWrapper" /*#Frozen*/;

	/** represents the size of the grid in horizontal grid elements
	 *
	 */
	protected int gridAreaSize = Integer.MIN_VALUE;

	/** Progressbar is shown while the algorithm is running
	 */
	protected ProgressDialog dlgProgress =
		new ProgressDialog(
			(Frame) null,
			Translator.getString("Progress") + ":",
			false);
	/* #Finished */

	/** A vector with Integer Objects. The Vector contains the
	 *  history of movements per loop
	 *  It was needed for the progress dialog
	 */
	Vector movements = null;
	/** Represents the movements in the current loop.
	 *  It was needed for the progress dialog
	 */
	int movementsCurrentLoop = -1;
	/** Represents the maximum of movements in the current loop.
	 *  It was needed for the progress dialog
	 */
	int movementsMax = Integer.MIN_VALUE;
	/** Represents the current loop number
	 *  It was needed for the progress dialog
	 */
	int iteration = 0;

	/**
	 * Implementation.
	 *
	 * First of all the Algorithm searches the roots from the
	 * Graph. Starting from this roots the Algorithm creates
	 * levels and stores them in the member <code>levels</code>.
	 * The Member levels contains Vector Objects and the Vector per level
	 * contains Cell Wrapper Objects. After that the Algorithm
	 * tries to solve the edge crosses from level to level and
	 * goes top down and bottom up. After minimization of the
	 * edge crosses the algorithm moves each node to its
	 * bary center. Last but not Least the method draws the Graph.
	 *
	 * @see LayoutAlgorithm
	 *
	 */
	public void perform(
		JGraph jgraph,
		boolean applyToAll,
		Properties configuration) {

		Object[] selectedCells =
			(applyToAll ? jgraph.getRoots() : jgraph.getSelectionCells());
		CellView[] selectedCellViews =
			jgraph.getGraphLayoutCache().getMapping(selectedCells);

		Point spacing = new Point();
		/*  The Algorithm distributes the nodes on a grid.
		 *  For this grid you can configure the horizontal spacing.
		 *  This field specifies the configured value
		 *
		 */
		spacing.x =
			Integer.parseInt(
				configuration.getProperty(
					SugiyamaLayoutController.KEY_HORIZONTAL_SPACING));

		/*  The Algorithm distributes the nodes on a grid.
		 *  For this grid you can configure the vertical spacing.
		 *  This field specifies the configured value
		 *
		 */

		spacing.y =
			Integer.parseInt(
				configuration.getProperty(
					SugiyamaLayoutController.KEY_VERTICAL_SPACING));

		// set the progress dialog visible
		dlgProgress.setVisible(true);

		// search all roots
		Vector roots = searchRoots(jgraph, selectedCellViews);

		// return if no root found
		if (roots.size() == 0)
			return;

		// create levels
		Vector levels = fillLevels(jgraph, selectedCellViews, roots);

		// solves the edge crosses
		solveEdgeCrosses(jgraph, levels);

		// move all nodes into the barycenter
		moveToBarycenter(jgraph, selectedCellViews, levels);

		Point min = findMinimumAndSpacing(selectedCellViews, spacing);

		// draw the graph in the window
		drawGraph(jgraph, levels, min, spacing);

		// clean temp values from the nodes / cells
		// the clean up was made in drawGraph
		//cleanUp(selectedCellViews);

		// sets the progress dialog unvisible
		dlgProgress.setVisible(false);
	}

	/** Debugdisplay for the edge crosses indicators on the System out
	 */
	protected void displayEdgeCrossesValues(Vector levels) {
		System.out.println("----------------Edge Crosses Indicator Values"
		/*#Frozen*/
		);

		for (int i = 0; i < levels.size() - 1; i++) {
			// Get the current level
			Vector currentLevel = (Vector) levels.get(i);
			System.out.print("Level (" + i + "):" /*#Frozen*/
			);
			for (int j = 0; j < currentLevel.size(); j++) {
				CellWrapper sourceWrapper = (CellWrapper) currentLevel.get(j);

				System
					.out
					.print(
						NumberFormat.getNumberInstance().format(
							sourceWrapper.getEdgeCrossesIndicator())
						+ " - " /*#Frozen*/
				);
			}
			System.out.println();
		}
	}

	/** Debugdisplay for the grid positions on the System out
	 */
	protected void displayGridPositions(Vector levels) {

		System.out.println("----------------GridPositions" /*#Frozen*/
		);

		for (int i = 0; i < levels.size() - 1; i++) {
			// Get the current level
			Vector currentLevel = (Vector) levels.get(i);
			System.out.print("Level (" + i + "):" /*#Frozen*/
			);
			for (int j = 0; j < currentLevel.size(); j++) {
				CellWrapper sourceWrapper = (CellWrapper) currentLevel.get(j);
				System
					.out
					.print(
						NumberFormat.getNumberInstance().format(
							sourceWrapper.getGridPosition())
						+ " - " /*#Frozen*/
				);
			}
			System.out.println();
		}
	}

	/** Debugdisplay for the priorities on the System out
	 */
	protected void displayPriorities(Vector levels) {

		System.out.println("----------------down Priorities" /*#Frozen*/
		);

		for (int i = 0; i < levels.size() - 1; i++) {
			// Get the current level
			Vector currentLevel = (Vector) levels.get(i);
			System.out.print("Level (" + i + "):" /*#Frozen*/
			);
			for (int j = 0; j < currentLevel.size(); j++) {
				CellWrapper sourceWrapper = (CellWrapper) currentLevel.get(j);
				System.out.print(sourceWrapper.getPriority() +
				/*" (" +
				                   sourceWrapper.nearestDownNeighborLevel + ") " +*/
				" - " /*#Frozen*/
				);
			}
			System.out.println();
		}
	}

	/** Searches all Roots for the current Graph
	 *  First the method marks any Node as not visited.
	 *  Than calls searchRoots(MyGraphCell) for each
	 *  not visited Cell.
	 *  The Roots are stored in the Vector named roots
	 *
	 * 	@return returns a Vector with the roots
	 *  @see #searchRoots(JGraph, CellView[])
	 */
	protected Vector searchRoots(JGraph jgraph, CellView[] selectedCellViews) {

		// get all cells and relations
		Vector vertexViews = new Vector(selectedCellViews.length);
		Vector roots = new Vector();

		// first: mark all as not visited
		// O(allCells&Edges)
		for (int i = 0; i < selectedCellViews.length; i++) {
			if (selectedCellViews[i] instanceof VertexView) {
				VertexView vertexView = (VertexView) selectedCellViews[i];
				vertexView.getAttributes().remove(SUGIYAMA_VISITED);
				vertexViews.add(selectedCellViews[i]);
			}
		}

		// O(graphCells)
		for (int i = 0; i < vertexViews.size(); i++) {
			VertexView vertexView = (VertexView) vertexViews.get(i);
			if (vertexView.getAttributes().get(SUGIYAMA_VISITED) == null) {
				searchRoots(jgraph, vertexView, roots);
			}
		}

		// Error Msg if the graph has no roots
		if (roots.size() == 0) {
			JOptionPane
				.showMessageDialog(
					null,
					Translator.getString("TheGraphIsNotADAG"
			/*#Finished:Original="The Graph is not a DAG. Can't use Sugiyama Algorithm!"*/
			), null, JOptionPane.ERROR_MESSAGE);
		}
		return roots;
	}

	/** Searches Roots for the current Cell.
	 *
	 *  Therefore he looks at all Ports from the Cell.
	 *  At the Ports he looks for Edges.
	 *  At the Edges he looks for the Target.
	 *  If the Ports of the current Cell contains the target ReViewNodePort
	 *  he follows the edge to the source and looks at the
	 *  Cell for this source.
	 *
	 *  @param graphCell The current cell
	 */
	protected void searchRoots(
		JGraph jgraph,
		VertexView vertexViewToInspect,
		Vector roots) {
		// the node already visited
		if (vertexViewToInspect.getAttributes().get(SUGIYAMA_VISITED)
			!= null) {
			return;
		}

		// mark as visited for cycle tests
		vertexViewToInspect.getAttributes().put(
			SUGIYAMA_VISITED,
			new Boolean(true));

		GraphModel model = jgraph.getModel();

		// get all Ports and search the relations at the ports
		//List vertexPortViewList = new ArrayList() ;

		Object vertex = vertexViewToInspect.getCell();

		int portCount = model.getChildCount(vertex);
		for (int j = 0; j < portCount; j++) {
			Object port = model.getChild(vertex, j);

			// Test all relations for where
			// the current node is a target node
			// for roots

			boolean isRoot = true;
			Iterator itrEdges = model.edges(port);
			while (itrEdges.hasNext()) {
				Object edge = itrEdges.next();

				// if the current node is a target node
				// get the source node and test
				// the source node for roots

				if (model.getTarget(edge) == port) {
					Object sourcePort = model.getSource(edge);

					Object sourceVertex = model.getParent(sourcePort);

					CellView sourceVertexView =
						jgraph.getGraphLayoutCache().getMapping(
							sourceVertex,
							false);
					if (sourceVertexView instanceof VertexView) {
						searchRoots(
							jgraph,
							(VertexView) sourceVertexView,
							roots);
						isRoot = false;
					}
				}
			}
			// The current node is never a Target Node
			// -> The current node is a root node
			if (isRoot) {
				roots.add(vertexViewToInspect);
			}
		}
	}

	/** Method fills the levels and stores them in the member levels.
	
	 *  Each level was represended by a Vector with Cell Wrapper objects.
	 *  These Vectors are the elements in the <code>levels</code> Vector.
	 *
	 */
	protected Vector fillLevels(
		JGraph jgraph,
		CellView[] selectedCellViews,
		Vector rootVertexViews) {
		Vector levels = new Vector();

		// mark as not visited
		// O(allCells)
		for (int i = 0; i < selectedCellViews.length; i++) {
			CellView cellView = selectedCellViews[i];

			// more stabile
			if (cellView == null)
				continue;

			cellView.getAttributes().remove(SUGIYAMA_VISITED);
		}

		Enumeration enumRoots = rootVertexViews.elements();
		while (enumRoots.hasMoreElements()) {
			VertexView vertexView = (VertexView) enumRoots.nextElement();
			fillLevels(jgraph, levels, 0, vertexView);
		}

		return levels;

	}

	/** Fills the Vector for the specified level with a wrapper
	 *  for the MyGraphCell. After that the method called for
	 *  each neighbor graph cell.
	 *
	 *  @param level        The level for the graphCell

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -