/*
* Created on Oct 25, 2005
*/
package org.mindswap.swoop.utils.graph.hierarchy.layout;
import java.awt.Dimension;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.mindswap.swoop.utils.graph.hierarchy.OntologyGraphNode;
import org.mindswap.swoop.utils.graph.hierarchy.OntologyWithClassHierarchyGraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.Vertex;
import edu.uci.ics.jung.utils.Pair;
import edu.uci.ics.jung.utils.UserData;
import edu.uci.ics.jung.visualization.AbstractLayout;
import edu.uci.ics.jung.visualization.Coordinates;
/**
* @author Dave Wang
*
* Code taken, modified from edu.uci.ics.jung.visualization.contrib.CircleLayout
*
* Positions vertices equally spaced on a regular circle.
* Does not respect filter calls.
*
*/
public class SizeAwareCircleLayout extends AbstractLayout {
private static final Object CIRCLE_KEY = "swoop.Circle_Visualization_Key";
private Pair key;
private double radius;
public SizeAwareCircleLayout(Graph g) {
super(g);
key = new Pair(this, CIRCLE_KEY);
}
public String getStatus() {
return "SizeAwareCircleLayout";
}
/**
* This one is not incremental.
*/
public boolean isIncremental()
{ return false; }
/**
* Returns true;
*/
public boolean incrementsAreDone()
{ return true; }
public double getRadius()
{ return radius; }
public void setRadius(double radius)
{ this.radius = radius; }
/**
* Specifies the order of vertices. The first element of the
* specified array will be positioned with angle 0 (on the X
* axis), and the second one will be positioned with angle 1/n,
* and the third one will be positioned with angle 2/n, and so on.
* <p>
* The default implemention shuffles elements randomly.
*/
public void orderVertices(Vertex[] vertices)
{
List list = Arrays.asList(vertices);
Collections.shuffle(list);
}
/**
* Returns a visualization-specific key (that is, specific both
* to this instance and <tt>AbstractLayout</tt>) that can be used
* to access UserData related to the <tt>AbstractLayout</tt>.
*/
public Object getKey() {
if (key == null)
key = new Pair(this, CIRCLE_KEY);
return key;
}
protected void initialize_local_vertex(Vertex v) {
if (v.getUserDatum(getKey()) == null) {
v.addUserDatum(getKey(), new CircleVertexData(), UserData.REMOVE);
}
}
protected void initialize_local() {}
protected void initializeLocations() {
super.initializeLocations();
Vertex[] vertices =
(Vertex[]) getVisibleVertices().toArray(new Vertex[0]);
orderVertices(vertices);
int max1 = 0;
int max2 = 0;
for ( int i = 0; i < vertices.length; i++ )
{
Vertex v = vertices[i];
int r = ((OntologyGraphNode) v.getUserDatum(OntologyWithClassHierarchyGraph.DATA)).getRadius();
if ( r > max1 )
{
max2 = max1;
max1 = r;
}
else if ( r > max2 )
max2 = r;
}
radius = max1 + max2;
Dimension d = getCurrentSize();
double height = d.getHeight();
double width = d.getWidth();
if (radius <= 0) {
radius = 0.45 * (height < width ? height : width);
}
for (int i = 0; i < vertices.length; i++) {
Coordinates coord = getCoordinates(vertices[i]);
double angle = (2 * Math.PI * i) / vertices.length;
coord.setX(Math.cos(angle) * radius + width / 2);
coord.setY(Math.sin(angle) * radius + height / 2);
CircleVertexData data = getCircleData(vertices[i]);
data.setAngle(angle);
}
}
public CircleVertexData getCircleData(Vertex v) {
return (CircleVertexData) (v.getUserDatum(getKey()));
}
/**
* Do nothing.
*/
public void advancePositions()
{ }
public static class CircleVertexData {
private double angle;
public double getAngle() {
return angle;
}
public void setAngle(double angle) {
this.angle = angle;
}
public String toString() {
return "CircleVertexData: angle=" + angle;
}
}
}