/* (non-Javadoc)
* @see com.mxgraph.layout.mxIGraphLayout#execute(java.lang.Object)
*/
public void execute(Object parent)
{
mxIGraphModel model = graph.getModel();
// Finds the relevant vertices for the layout
Object[] vertices = graph.getChildVertices(parent);
List<Object> tmp = new ArrayList<Object>(vertices.length);
for (int i = 0; i < vertices.length; i++)
{
if (!isVertexIgnored(vertices[i]))
{
tmp.add(vertices[i]);
}
}
vertexArray = tmp.toArray();
mxRectangle initialBounds = (useInputOrigin) ? graph.getBoundsForCells(
vertexArray, false, false, true) : null;
int n = vertexArray.length;
dispX = new double[n];
dispY = new double[n];
cellLocation = new double[n][];
isMoveable = new boolean[n];
neighbours = new int[n][];
radius = new double[n];
radiusSquared = new double[n];
minDistanceLimitSquared = minDistanceLimit * minDistanceLimit;
if (forceConstant < 0.001)
{
forceConstant = 0.001;
}
forceConstantSquared = forceConstant * forceConstant;
// 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++)
{
Object vertex = vertexArray[i];
cellLocation[i] = new double[2];
// Set up the mapping from array indices to cells
indices.put(vertex, new Integer(i));
mxRectangle bounds = getVertexBounds(vertex);
// Set the X,Y value of the internal version of the cell to
// the center point of the vertex for better positioning
double width = bounds.getWidth();
double height = bounds.getHeight();
// Randomize (0, 0) locations
double x = bounds.getX();
double y = bounds.getY();
cellLocation[i][0] = x + width / 2.0;
cellLocation[i][1] = y + height / 2.0;
radius[i] = Math.min(width, height);
radiusSquared[i] = radius[i] * radius[i];
}
// Moves cell location back to top-left from center locations used in
// algorithm, resetting the edge points is part of the transaction
model.beginUpdate();
try
{
for (int i = 0; i < n; i++)
{
dispX[i] = 0;
dispY[i] = 0;
isMoveable[i] = isVertexMovable(vertexArray[i]);
// Get lists of neighbours to all vertices, translate the cells
// obtained in indices into vertexArray and store as an array
// against the original cell index
Object[] edges = graph.getConnections(vertexArray[i], parent);
for (int k = 0; k < edges.length; k++)
{
if (isResetEdges())
{
graph.resetEdge(edges[k]);
}
if (isDisableEdgeStyle())
{
setEdgeStyleEnabled(edges[k], false);
}
}
Object[] cells = graph.getOpposites(edges, vertexArray[i]);
neighbours[i] = new int[cells.length];
for (int j = 0; j < cells.length; j++)
{
Integer index = indices.get(cells[j]);
// Check the connected cell in part of the vertex list to be
// acted on by this layout
if (index != null)
{
neighbours[i][j] = index.intValue();
}
// Else if index of the other cell doesn't correspond to
// any cell listed to be acted upon in this layout. Set
// the index to the value of this vertex (a dummy self-loop)
// so the attraction force of the edge is not calculated
else
{
neighbours[i][j] = i;
}
}
}
temperature = initialTemp;
// If max number of iterations has not been set, guess it
if (maxIterations == 0)
{
maxIterations = (int) (20 * Math.sqrt(n));
}
// Main iteration loop
for (iteration = 0; iteration < maxIterations; iteration++)
{
if (!allowedToRun)
{
return;
}
// Calculate repulsive forces on all vertices
calcRepulsion();
// Calculate attractive forces through edges
calcAttraction();
calcPositions();
reduceTemperature();
}
Double minx = null;
Double miny = null;
for (int i = 0; i < vertexArray.length; i++)
{
Object vertex = vertexArray[i];
mxGeometry geo = model.getGeometry(vertex);
if (geo != null)
{
cellLocation[i][0] -= geo.getWidth() / 2.0;
cellLocation[i][1] -= geo.getHeight() / 2.0;
double x = graph.snap(cellLocation[i][0]);
double y = graph.snap(cellLocation[i][1]);
setVertexLocation(vertex, x, y);
if (minx == null)
{
minx = new Double(x);
}
else
{
minx = new Double(Math.min(minx.doubleValue(), x));
}
if (miny == null)
{
miny = new Double(y);
}
else
{
miny = new Double(Math.min(miny.doubleValue(), y));
}
}
}
// Modifies the cloned geometries in-place. Not needed
// to clone the geometries again as we're in the same
// undoable change.
double dx = (minx != null) ? -minx.doubleValue() - 1 : 0;
double dy = (miny != null) ? -miny.doubleValue() - 1 : 0;
if (initialBounds != null)
{
dx += initialBounds.getX();
dy += initialBounds.getY();
}
graph.moveCells(vertexArray, dx, dy);
}
finally
{
model.endUpdate();
}
}