com.jgraph.layout.graph.JGraphSpringLayout Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ingeniasjgraphmod Show documentation
Show all versions of ingeniasjgraphmod Show documentation
A modified version of some JGraph files
The newest version!
/*
* $Id: JGraphSpringLayout.java,v 1.1 2009/09/25 15:14:15 david Exp $
* Copyright (c) 2001-2005, Gaudenz Alder
* Copyright (c) 2005, David Benson
*
* All rights reserved.
*
* This file is licensed under the JGraph software license, a copy of which
* will have been provided to you in the file LICENSE at the root of your
* installation directory. If you are unable to locate this file please
* contact JGraph sales for another copy.
*/
package com.jgraph.layout.graph;
import java.awt.geom.Point2D;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Map;
import com.jgraph.layout.JGraphFacade;
import com.jgraph.layout.JGraphLayout;
import com.jgraph.layout.JGraphLayoutProgress;
/**
* A basic Spring Embedded Layout Algorithm. Edges on the graph represent
* spring. All the springs have a natural length, measured in the same units
* as the screen co-ordination system, which they attempt to achieve constantly.
* If the spring is shorter than its natural length it extends, pushing the
* nodes are either end of the edge apart. If the spring is longer than its
* natural length it contracts, pulling the nodes at either end of the edge
* together. The force exerted by the spring is proportional to different
* between its current length and its natural length. A force multiple is
* also applied indicating the "strength" of the spring.
*
* In addition, all nodes repel each other with a force inversely
* proportional to the distance between each other. The repelling
* force is mutliplied by a replusive force factor.
*
* The whole affect is to cause nodes to space out fairly evenly but
* for nodes linked by edges ( springs ) to cluster together
*
* @deprecated use JGraphFastOrganicLayout instead
*/
public class JGraphSpringLayout implements JGraphLayout, JGraphLayout.Stoppable {
/**
* Stores the temporary positions of each cell during the layout
*/
protected transient Map displacement = new Hashtable();
/**
* The multiple by which the force replusive each pair of nodes scaled by
* Increase to make nodes force further apart
*/
protected double replusiveForce = 10000.0;
/**
* The multiple of force applied to the attraction of springs
*/
protected double springForce = 0.2;
/**
* The natural length of the spring (edge) whereby it imparts no force
* on either connected node
*/
protected double springLength = 50.0;
/**
* current iteration number
*/
protected int iteration;
/**
* total number of iterations to step through when running
*/
protected int maxIterations = 0;
/**
* An array of all vertices to be laid out
*/
protected Object vertexArray[];
/**
* An array of locally stored X co-ordinate displacements for the vertices
*/
protected double dispX[];
/**
* An array of locally stored Y co-ordinate displacements for the vertices
*/
protected double dispY[];
/**
* An array of locally stored X co-ordinate positions for the vertices
*/
protected double cellLocationX[];
/**
* An array of locally stored Y co-ordinate positions for the vertices
*/
protected double cellLocationY[];
/**
* Local copy of isMoveable
*/
protected boolean isMoveable[];
/**
* Local copy of cell neighbours
*/
protected int[] neighbours[];
/**
* An object to monitor and control progress.
*/
protected JGraphLayoutProgress progress = new JGraphLayoutProgress();
/**
* Creates a new layout of 50 iterations
*
*/
public JGraphSpringLayout() {
this(50);
}
/**
* Creates a new spring layout to be executed over the specified number
* of iterations
* @param
* iterations the number of layout iterations to execute
*/
public JGraphSpringLayout(int iterations) {
setMaxIterations(iterations);
}
/**
* @return Returns the progress.
*/
public JGraphLayoutProgress getProgress() {
return progress;
}
/**
* Executes the spring layout of the specified facade data
*
* @param graph
* the description of the graph to be acted upon
*/
public void run(JGraphFacade graph) {
// Set the facade to be non-directed, directed graphs produce incorrect
// results. Store the directed state to reset it after this method
boolean directed = graph.isDirected();
graph.setDirected(true);
Collection vertices = graph.getVertices();
if (vertices.isEmpty()) return;
// Allocate memory for local cached arrays
vertexArray = vertices.toArray();
dispX = new double[vertexArray.length];
dispY = new double[vertexArray.length];
cellLocationX = new double[vertexArray.length];
cellLocationY = new double[vertexArray.length];
isMoveable = new boolean[vertexArray.length];
neighbours = new int[vertexArray.length][];
// If max number of iterations has not been set, guess it
if (maxIterations == 0) {
maxIterations = 20 * (int)Math.sqrt(vertexArray.length);
}
progress.reset(maxIterations);
// Temporary map used to setup neighbour array of arrays
Map vertexMap = new Hashtable(vertexArray.length);
// Create a map of vertices first. This is required for the array of
// arrays called neighbours which holds, for each vertex, a list of
// ints which represents the neighbours cells to that vertex as
// the indices into vertexArray
for (int i=0; i < vertexArray.length; i++) {
// Set up the mapping from array indices to cells
vertexMap.put(vertexArray[i],new Integer(i));
}
for (int i=0; i < vertexArray.length; i++) {
dispX[i] = 0;
dispY[i] = 0;
// Makes a local copy of all cell locations for performance
Point2D pos = graph.getLocation(vertexArray[i]);
cellLocationX[i] = pos.getX();
cellLocationY[i] = pos.getY();
isMoveable[i] = graph.isMoveable(vertexArray[i]);
// Get lists of neighbours to all vertices, translate the cells
// obtained in indices into vertexArray and store as an array
// against the orginial cell index
Object cellNeighbours[] = graph.getNeighbours(vertexArray[i], null, false).toArray();
neighbours[i] = new int[cellNeighbours.length];
for (int j=0; j springLength) {
fr = springLength;
} else if (fr < -springLength) {
fr = -springLength;
}
double deltaNormX = deltaX / nodeDistance;
double displacementX = deltaNormX * fr;
double deltaNormY = deltaY / nodeDistance;
double displacementY = deltaNormY * fr;
if (isMoveable[i]) {
dispX[i] += displacementX;
dispY[i] += displacementY;
}
if (isMoveable[j]) {
dispX[j] -= displacementX;
dispY[j] -= displacementY;
}
}
}
}
}
/**
* Calculates an attractive force between the cells connected by the
* specified edge
*/
protected void attract() {
// Check the neighbours of each vertex and calculate the attractive
// force of the edge connecting them
for (int i=0; i < vertexArray.length; i++) {
for (int k=0; k < neighbours[i].length; k++) {
if (progress.isStopped())
return;
// Get the index of the othe cell in the vertex array
int j = neighbours[i][k];
// Do not process self-loops
if (i != j) {
double xDelta = cellLocationX[i] - cellLocationX[j];
double yDelta = cellLocationY[i] - cellLocationY[j];
// The distance between the nodes
double edgeLength = Math.sqrt((xDelta * xDelta)
+ (yDelta * yDelta));
// Calculate the length by which the spring is extended
double extensionLength = edgeLength - springLength;
// Avoid divide by zero
if (edgeLength < 1.0)
edgeLength = 1.0;
// calculate the attractive forces
double fa = extensionLength * springForce;
double deltaNormX = xDelta / edgeLength;
double deltaNormY = yDelta / edgeLength;
double displacementX = deltaNormX * fa;
double displacementY = deltaNormY * fa;
if (isMoveable[i]) {
dispX[i] -= displacementX;
dispY[i] -= displacementY;
}
if (isMoveable[j]) {
dispX[j] += displacementX;
dispY[j] += displacementY;
}
}
}
}
}
/**
* repositions the specified cells using the positioning
* data obtained through repulse and attract phases
* @param graph
* the description of the graph to be laid out
*/
protected void reposition(JGraphFacade graph) {
for (int index=0; index < vertexArray.length; index++) {
if (isMoveable[index]) {
// Update the cached cell locations
cellLocationX[index] += dispX[index];
cellLocationY[index] += dispY[index];
// reset displacements
dispX[index] = 0;
dispY[index] = 0;
// If this is the last iteration, write the node locations
// back to the facade
if (iteration == maxIterations-1) {
graph.setLocation(vertexArray[index],
cellLocationX[index],
cellLocationY[index]);
}
}
}
}
/**
* @param iterations the value to set maxIterations
to
*/
public void setMaxIterations(int iterations) {
if (iterations < 0) {
throw new IllegalArgumentException(
"iterations must be a positive integer");
}
this.maxIterations = iterations;
}
/**
* @return Returns the total number of iterations.
*/
public int getMaxIterations() {
return maxIterations;
}
/**
* @return Returns the springLength.
*/
public double getSpringLength() {
return springLength;
}
/**
* @param springLength The springLength to set.
*/
public void setSpringLength(double springLength) {
// Must be finite and positive
if (springLength < 0.001) {
throw new IllegalArgumentException(
"spring length must be postive and non-zero");
}
this.springLength = springLength;
}
/**
* @return Returns the springForce.
*/
public double getSpringForce() {
return springForce;
}
/**
* @param springForce The springForce to set.
*/
public void setSpringForce(double springForce) {
this.springForce = springForce;
}
/**
* @return Returns the replusiveForce.
*/
public double getReplusiveForce() {
return replusiveForce;
}
/**
* @param replusiveForce The replusiveForce to set.
*/
public void setReplusiveForce(double replusiveForce) {
this.replusiveForce = replusiveForce;
}
/**
* Returns Spring
, the name of this algorithm.
*/
public String toString() {
return "Spring";
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy