/*
* Copyright (c) 2003, 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.
*/
package edu.uci.ics.jung.algorithms.layout;
import java.awt.Dimension;
import java.awt.geom.Point2D;
import java.util.ConcurrentModificationException;
import org.apache.commons.collections15.Transformer;
import edu.uci.ics.jung.graph.Graph;
/**
* The SpringLayout package represents a visualization of a set of nodes. The
* SpringLayout, which is initialized with a Graph, assigns X/Y locations to
* each node. When called relax()
, the SpringLayout moves the
* visualization forward one step.
*
*
*
* @author Danyel Fisher
* @author Joshua O'Madadhain
*/
public class SpringLayout2 extends SpringLayout
{
protected int currentIteration;
protected int averageCounter;
protected int loopCountMax = 4;
protected boolean done;
protected Point2D averageDelta = new Point2D.Double();
/**
* Constructor for a SpringLayout for a raw graph with associated
* dimension--the input knows how big the graph is. Defaults to the unit
* length function.
*/
@SuppressWarnings("unchecked")
public SpringLayout2(Graph g) {
super(g);
}
/**
* Constructor for a SpringLayout for a raw graph with associated component.
*
* @param g the {@code Graph} to lay out
* @param length_function provides a length for each edge
*/
public SpringLayout2(Graph g, Transformer length_function)
{
super(g, length_function);
}
/**
* Relaxation step. Moves all nodes a smidge.
*/
@Override
public void step() {
super.step();
currentIteration++;
testAverageDeltas();
}
private void testAverageDeltas() {
double dx = this.averageDelta.getX();
double dy = this.averageDelta.getY();
if(Math.abs(dx) < .001 && Math.abs(dy) < .001) {
done = true;
System.err.println("done, dx="+dx+", dy="+dy);
}
if(currentIteration > loopCountMax) {
this.averageDelta.setLocation(0,0);
averageCounter = 0;
currentIteration = 0;
}
}
@Override
protected void moveNodes() {
synchronized (getSize()) {
try {
for (V v : getGraph().getVertices()) {
if (isLocked(v)) continue;
SpringVertexData vd = springVertexData.get(v);
if(vd == null) continue;
Point2D xyd = transform(v);
vd.dx += vd.repulsiondx + vd.edgedx;
vd.dy += vd.repulsiondy + vd.edgedy;
// int currentCount = currentIteration % this.loopCountMax;
// System.err.println(averageCounter+" --- vd.dx="+vd.dx+", vd.dy="+vd.dy);
// System.err.println("averageDelta was "+averageDelta);
averageDelta.setLocation(
((averageDelta.getX() * averageCounter) + vd.dx) / (averageCounter+1),
((averageDelta.getY() * averageCounter) + vd.dy) / (averageCounter+1)
);
// System.err.println("averageDelta now "+averageDelta);
// System.err.println();
averageCounter++;
// keeps nodes from moving any faster than 5 per time unit
xyd.setLocation(xyd.getX()+Math.max(-5, Math.min(5, vd.dx)),
xyd.getY()+Math.max(-5, Math.min(5, vd.dy)));
Dimension d = getSize();
int width = d.width;
int height = d.height;
if (xyd.getX() < 0) {
xyd.setLocation(0, xyd.getY());// setX(0);
} else if (xyd.getX() > width) {
xyd.setLocation(width, xyd.getY()); //setX(width);
}
if (xyd.getY() < 0) {
xyd.setLocation(xyd.getX(),0);//setY(0);
} else if (xyd.getY() > height) {
xyd.setLocation(xyd.getX(), height); //setY(height);
}
}
} catch(ConcurrentModificationException cme) {
moveNodes();
}
}
}
@Override
public boolean done() {
return done;
}
}