/*
* 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