public class SpringGraphLayout extends GraphLayout
The main principle behind its operation is that graph nodes are subject to two forces: a spring force and a coulomb (electric charge) force. The edges are considered to be springs subject to Hooke's law where the force is attraction when the string is stretched (i.e., length greater than the equilibrium length desired) or repulsion when the spring is compressed to less than the equilibrium length. The nodes are considered to be electric point charges (all with the same positive charge) that repel each other according to Coulomb's reciprocalofthedistance law. There is a mass function which generally returns the same for all nodes, but can be adjusted (e.g., for immovable notes) depending on the kind of node. See the mass() method to override.
In order to handle contexts, the algorithm works in a depthfirst recursive way. That is, nested contexts are laid out before their enclosing graph. The context is treated as a pointnode, whose mass is equal to the sum of the masses of its constituents. If there is an edge that crosses into the context, a fake "edge" is temporarily created to directly connect the context itself for the purposes of determining the layout. This fake edge is only considered when laying out the outer graph; the context's layout is unaware of any edges that link to the outer context(s).
The displacement is merely the force interpreted as a position translation operation.
For unconnected components (in the graph theory sense), the algorithm will ordinarily cause them to push apart (since there's no spring force to balance), leaving lots of wide open space. Therefore there's a step that identifies unconnected components, and connects each one's centermost node with at least one other centermost node. This ensures that they will have at least one attractive force to help them stay together.Fine tuning of the layout parameters is crucial to the effective use of the algorithm. See comments on each of the layout parameters to better understand how they work.
Future tweaks:
Tell the force calculators to "favor"
xforces so that layouts will tend toward landscape orientation.
Tell the force calculators to "favor" rectilinear placement.
Modifier and Type  Field and Description 

private boolean 
applyUpLeftPressure 
private int 
ATTRACTION_FORCE_SIGN
The arithmetic sign of an attractive force.

private double 
borderMargin
How much extra space to provide on the top and left of the final laid out graph.

private float 
contextInnerPadding
How much padding to provide between the bounding rectangle of the graph/context and its enclosed contents.

private double 
COULOMB_CONSTANT
Coulomb constant (numerator) for the distancesquared calculations.

private double 
COULOMB_EXPONENT
Used to further "dampen" the coulomb force.

private static double 
DAMPER_FOR_COULOMB
Multiplier for the coulomb (repulsion) force

private static double 
DAMPER_FOR_SPRING
Multiplier for the spring force

private static double 
DAMPING_FOR_DISPLACEMENTS
Further damping for displacements; currently set to 1.0

private ArrayList<GEdge> 
edges 
private double 
ENERGY_THRESHHOLD
The minimum energy level that tells the algorithm it can stop.

private double 
ENERGY_THRESHHOLD_PER_NODE
To finetune the threshhold

private static double 
EPSILON
Doubleprecision values are considered equal if they are within this value of each other

private double 
equilibriumEdgeLength
The "best" edge length.

private double 
MAX_DISTANCE
The maximum distance between nodes; if they are farther apart than this,
bring them in to this distance.

private Rectangle2D.Double 
maxBoundsAvailable
How much space this graph is allowed to occupy

static int 
maxIterations
When to call it quits on iterating through the algorithm.

private double 
MIN_DISTANCE
The minimum distance between nodes; if they are actually closer than this,
then assume they are at this distance.

private static DecimalFormat 
nformat 
private HashMap<GNode,Point2D.Double> 
nodeDisplacements
Displacement is represented as a "point" where the x value is dx and the
y value is dy.

private HashMap<GNode,Point2D.Double> 
nodeForces 
private HashMap<GNode,Point2D.Double> 
nodePositions
Keeps track of each node's displacement (movement) at each iteration.

private ArrayList<GNode> 
nodes 
private double 
pressureScale 
private int 
REPULSION_FORCE_SIGN
Set to 1 * the attraction force.

private static double 
SPRING_CONSTANT
Used in determining the spring force using Hooke's law.

private static Point2D.Double 
zeroPoint 
graph, verbose
Constructor and Description 

SpringGraphLayout(Graph g) 
Modifier and Type  Method and Description 

void 
addEdgesFromUnconnectedComponents()
Add custom edges between unconnected graph components.

void 
addForceToNodeForces(Point2D.Double force,
GraphObject node)
For the given node, add the force to the current forces on it.

void 
addNewCoulombForces()
For each node in the graph, calculate the new coulomb force vectors (as
"points") and add them to the nodeForces list.

void 
addNewSpringForces() 
void 
copyToGraph()
Update the actual graph to reflect the positions calculated by the
layout.

Point2D.Double 
coulomb_force(GNode thisnode,
GNode other)
Given two nodes, calculates the coulomb force that repels them.

double 
getBorderMargin() 
protected Rectangle2D.Double 
getBounds(boolean displayRects)
Find the bounds of all the node positions (not the original graph).

double 
getClippedLength(GNode node1,
GNode node2)
Considers the shape (from the original graph) returns the distance
between the clipping points of a centertocenter line between the
objects.

protected Rectangle2D.Double 
getDisplayRectBounds()
Find the bounds of all the node display rectangles (using the original
graph).

double 
getEquilibriumEdgeLength()
The preferred length of an edge to be sought by the algorithm.

Rectangle2D.Double 
getMaxBoundsAvailable()
Find out the maximum size of the area in which nodes can be placed.

protected Rectangle2D.Double 
getPositionBounds()
Find the bounds of all the node positions (not the original graph).

static Point2D.Double 
getXYForce(double force,
Point2D.Double source,
Point2D.Double dest)
Calculates both the x and y components of a force between two points.

private Rectangle2D.Double 
inferCurrentDisplayRect(GNode node)
Uses the height and width of the node's display rectangle, but infers
(from its new proposed center point) the rectangle it would form in its
nodePositions location.

void 
loadEdges()
Initializes the edges list.

void 
loadNodePositions()
Using the nodes list, get the actual positions from the original objects
and load up nodePositions list.

double 
makeNewPositions(boolean upLeftPressure)
From the existing forces vectors, calculate a displacement for each node,
assume a unit time interval and calculate a new position for each node.

double 
mass(GNode gn)
Allows the algorithm to adjust for varying "sizes" of nodes.

void 
moveToUpperLeft(boolean force)
Makes sure there are no negativecoordinate positions.

protected boolean 
nodesInLine()
Using the original graph nodes, determines whether, within EPSILON, the
nodes are in line, either along an xvalue or a yvalue.

boolean 
performLayout()
Perform the layout operation on the graph.

boolean 
performLayoutOnContext(Graph g)
Invokes the spring algorithm recursively on any nested graph.

double 
performOneRelaxation()
One iteration of the algorithm, starting with zero forces all around.

protected void 
randomizePositions()
Not really random; moves each node one pixel right and down from the
previous node.

static Point2D.Double 
reverseForce(Point2D.Double force) 
protected void 
scanAndLoadGraph()
Initialize the node and edges lists.

void 
setBorderMargin(double borderMargin) 
void 
setEquilibriumEdgeLength(double equilibriumEdgeLength) 
void 
setMaxBoundsAvailable(Rectangle rect)
Set the available rectangle to be the current extent of the graph; i.e., it will not take up any
more room in display.

void 
setMaxBoundsAvailable(Rectangle2D.Double maxBoundsAvailable)
Set the maximum space allowed in laying out the graph.

private void 
showAllForces(String s) 
private void 
showDisplacements(String s) 
static String 
showForce(Point2D.Double p) 
private String 
showPoint(Point2D.Double point) 
private void 
showPositions(String s) 
Point2D.Double 
spring_force(GEdge edge,
boolean fromTo)
Models the Hooke's law spring force along edges.

private void 
zeroOutVectors(HashMap<GNode,Point2D.Double> points)
convenience method for resetting the hashmaps after each relaxation.

isVerbose, setVerbose
private double equilibriumEdgeLength
private double borderMargin
private float contextInnerPadding
private Rectangle2D.Double maxBoundsAvailable
public static int maxIterations
Global.springLayoutMaxIterations
private double MIN_DISTANCE
private double MAX_DISTANCE
private static final double DAMPER_FOR_SPRING
private static final double DAMPER_FOR_COULOMB
private double COULOMB_EXPONENT
private double ENERGY_THRESHHOLD
private double ENERGY_THRESHHOLD_PER_NODE
private static double EPSILON
private static double DAMPING_FOR_DISPLACEMENTS
private static double SPRING_CONSTANT
DAMPER_FOR_SPRING
private double COULOMB_CONSTANT
COULOMB_EXPONENT
private static final Point2D.Double zeroPoint
private int ATTRACTION_FORCE_SIGN
private int REPULSION_FORCE_SIGN
private static DecimalFormat nformat
private boolean applyUpLeftPressure
private double pressureScale
private HashMap<GNode,Point2D.Double> nodeDisplacements
private HashMap<GNode,Point2D.Double> nodePositions
private HashMap<GNode,Point2D.Double> nodeForces
private ArrayList<GNode> nodes
private ArrayList<GEdge> edges
public SpringGraphLayout(Graph g)
protected void scanAndLoadGraph()
protected boolean nodesInLine()
protected void randomizePositions()
private void zeroOutVectors(HashMap<GNode,Point2D.Double> points)
points
 public boolean performLayout()
performLayout
in class GraphLayout
copyToGraph()
public double performOneRelaxation()
public boolean performLayoutOnContext(Graph g)
g
 the context to be laid outpublic double makeNewPositions(boolean upLeftPressure)
upLeftPressure
 if true, then an additional "pressure" is applied to
force nodes upward and to the left. This should help layouts from getting too spread out.public void addNewCoulombForces()
public void addNewSpringForces()
public Point2D.Double coulomb_force(GNode thisnode, GNode other)
thisnode
 The node from which the other is being repelledother
 public Point2D.Double spring_force(GEdge edge, boolean fromTo)
edge
 The edge whose forces are to be determinedfromTo
 Whether to calculate force from the from object to the to
object or vice versapublic double mass(GNode gn)
gn
 public void addForceToNodeForces(Point2D.Double force, GraphObject node)
force
 x and y values to be added to the force, multiplied by the "mass" of the node.node
 The node whose force is to be alteredpublic void moveToUpperLeft(boolean force)
force
 Whether to force the graph into the upper left corner
whether it already fits or not.public static Point2D.Double getXYForce(double force, Point2D.Double source, Point2D.Double dest)
force
 source
 dest
 public void loadNodePositions()
public void loadEdges()
public void addEdgesFromUnconnectedComponents()
public void copyToGraph()
copyToGraph
in class GraphLayout
private void showAllForces(String s)
private void showDisplacements(String s)
private void showPositions(String s)
private String showPoint(Point2D.Double point)
public static String showForce(Point2D.Double p)
public static Point2D.Double reverseForce(Point2D.Double force)
protected Rectangle2D.Double getBounds(boolean displayRects)
displayRects
 whether to consider the displayrects (an
approximation for the shapes)protected Rectangle2D.Double getPositionBounds()
protected Rectangle2D.Double getDisplayRectBounds()
private Rectangle2D.Double inferCurrentDisplayRect(GNode node)
node
 public double getClippedLength(GNode node1, GNode node2)
public Rectangle2D.Double getMaxBoundsAvailable()
public void setMaxBoundsAvailable(Rectangle rect)
rect
 public void setMaxBoundsAvailable(Rectangle2D.Double maxBoundsAvailable)
maxBoundsAvailable
 public double getEquilibriumEdgeLength()
public void setEquilibriumEdgeLength(double equilibriumEdgeLength)
public double getBorderMargin()
public void setBorderMargin(double borderMargin)