/* * JFLAP - Formal Languages and Automata Package * * * Susan H. Rodger * Computer Science Department * Duke University * August 27, 2009 * Copyright (c) 2002-2009 * All rights reserved. * JFLAP is open source software. Please see the LICENSE for terms. * */ package automata.graph.layout; import java.util.*; import java.awt.*; import javax.swing.*; import automata.graph.Graph; import automata.graph.LayoutAlgorithm; import java.awt.geom.Point2D; /** * This layout algorithm arranges vertices according to a circle algorithm. Vertices * with a relatively high degree are placed in an inner circle. Those with lower degrees * are placed in an outer circle. Outer circle vertices that link to a inner circle vertex * are placed near that vertex in the outer circle. All vertices are moved, despite any * that may be flagged as nonmovable. * * @see LayoutAlgorithm * @author Chris Morgan */ public class TwoCircleLayoutAlgorithm extends LayoutAlgorithm { /** * The graph onto which the vertices will be laid out */ public Graph graph; /** * The vertices associated with the graph */ ArrayList vertices; /** * Two lists that represent the division of the vertices into an inner and an outer circle */ ArrayList innerCircle, outerCircle; /** * VertexChains that represent values in the outer circle. Each VertexChain corresponds * to a vertex in the innerCircleChain, and values in each outerCircleChain are laid * up opposite to its corresponding vertex. The outerCircleChains, when laid out on the * graph, do not necessarily have the same radius in their layouts, as this varies based on the number * of vertices in each outerCircleChain. */ CircleChain[] outerCircleChains; /** * The VertexChain that represents values in the inner circle */ CircleChain innerCircleChain; /** * Assigns some default values. To have different values, use the other constructor. */ public TwoCircleLayoutAlgorithm() { super(); } /** * Constructor allowing the user to customize certain values. * * @param pSize * value for size. * @param vDim * value for vertexDim. * @param vBuffer * value for vertexBuffer. */ public TwoCircleLayoutAlgorithm(Dimension pSize, Dimension vDim, double vBuffer) { super(pSize, vDim, vBuffer); } public void layout(Graph g, Set notMoving) { //First, initialize classwide variables. graph = g; innerCircle = new ArrayList(); outerCircle = new ArrayList(); vertices = getMovableVertices(graph, notMoving); if (graph==null || vertices.size() == 0) return; //Put in the inner circle all vertices with degree >= 3 and all those pointing to two members of the inner circle. assignToCircles(); //Create inner circle chain and place it in graph innerCircleChain = new CircleChain(graph, vertexDim, vertexBuffer); for (int i=0; i0) { createOuterCircleChains(); shuffleOuterChains(); double radius, span, division; radius = innerCircleChain.getRadius(); division = 2*Math.PI / outerCircleChains.length; span = division * 4/5; for (int i=0; i 2) innerCircle.add(vertices.get(i)); else outerCircle.add(vertices.get(i)); if (innerCircle.size()==0) { innerCircle = outerCircle; outerCircle = new ArrayList(); return; } boolean innerCircleInsertion; int count; do { innerCircleInsertion = false; for (int i=0; i=2) { innerCircle.add(outerCircle.get(i)); outerCircle.remove(i); innerCircleInsertion = true; } } } while (innerCircleInsertion); } /** * Divides the vertices that are in the outer circle into VertexChains, which correspond to an inner circle * vertex. Outer circle vertices are assigned to a specific VertexChain according to the following priorities. *

1. Whether they link to an inner circle vertex
2. Whether they link to an existing outer circle item
* 3. If they link to two outer circle items in different VertexChains or have a degree = 0, they are * assigned to the smaller of the two VertexChains or the smallest existing VertexChain, * respectively. */ protected void createOuterCircleChains() { outerCircleChains = new CircleChain[innerCircle.size()]; int[] chainIndex = new int[outerCircle.size()]; for (int i=0; i -1 && match2 == -1) { outerCircleChains[match1].addVertex(outerCircle.get(i)); chainIndex[i] = match1; addedToChain = true; } else if (match1 > -1 && match2 > -1) { if (outerCircleChains[match1].size() < outerCircleChains[match2].size()) min = match1; else min = match2; outerCircleChains[min].addVertex(outerCircle.get(i)); chainIndex[i] = min; addedToChain = true; } } } } while (addedToChain); //If no vertex can be added, find the chain with minimum length, and then add all unplaceded vertices to it. min = 0; for (int i=0; i outerCircleChains[i].getVertices().size()) min = i; for (int i=0; iCircleChains in order to minimize overlapping * transitions between vertices in two different CircleChains. If a vertex from one CircleChain * has an edge to another vertex in an adjacent CircleChain, the two vertices will be moved to * their CircleChain's common border, and whatever other vertices to which the two vertices are linked * will be adjusted accordingly. */ protected void shuffleOuterChains() { CircleChain currentChain, nextChain; for (int i=0; i0) graph.addEdge(vertices[i], vertices[i-1]); // if (i>1 && i<5) // graph.addEdge(vertices[i], vertices[i-2]); } // graph.addEdge(vertices[4], vertices[8]); // graph.addEdge(vertices[13], vertices[8]); // graph.addEdge(vertices[4], vertices[13]); // graph.addEdge(vertices[13], vertices[16]); // graph.addEdge(vertices[4], vertices[16]); // graph.addEdge(vertices[39], vertices[17]); /* graph.addEdge(vertices[0], vertices[1]); graph.addEdge(vertices[2], vertices[0]); graph.addEdge(vertices[1], vertices[2]); graph.addEdge(vertices[3], vertices[1]); graph.addEdge(vertices[3], verticesadjacent(finalStates[i]).size()[0]); graph.addEdge(vertices[3], vertices[2]);*/ HashSet set = new HashSet(); //temp.add(vertices[6]); layout.layout(graph, set); for (int i=0; i