Package com.mxgraph.layout

Source Code of com.mxgraph.layout.mxOrganicLayout$CellWrapper

/**
* Copyright (c) 2007-2013, JGraph Ltd
*/

package com.mxgraph.layout;

import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

import com.mxgraph.model.mxGraphModel;
import com.mxgraph.model.mxIGraphModel;
import com.mxgraph.util.mxRectangle;
import com.mxgraph.view.mxGraph;
import com.mxgraph.view.mxGraphView;

/**
* An implementation of a simulated annealing layout, based on "Drawing Graphs
* Nicely Using Simulated Annealing" by Davidson and Harel (1996). This
* paper describes these criteria as being favourable in a graph layout: (1)
* distributing nodes evenly, (2) making edge-lengths uniform, (3)
* minimizing cross-crossings, and (4) keeping nodes from coming too close
* to edges. These criteria are translated into energy cost functions in the
* layout. Nodes or edges breaking these criteria create a larger cost function
* , the total cost they contribute related to the extent that they break it.
* The idea of the algorithm is to minimise the total system energy. Factors
* are assigned to each of the criteria describing how important that
* criteria is. Higher factors mean that those criteria are deemed to be
* relatively preferable in the final layout. Most of  the criteria conflict
* with the others to some extent and so the setting of the factors determines
* the general look of the resulting graph.
* <p>
* In addition to the four aesthetic criteria the concept of a border line
* which induces an energy cost to nodes in proximity to the graph bounds is
* introduced to attempt to restrain the graph. All of the 5 factors can be
* switched on or off using the <code>isOptimize...</code> variables.
* <p>
* Simulated Annealing is a force-directed layout and is one of the more
* expensive, but generally effective layouts of this type. Layouts like
* the spring layout only really factor in edge length and inter-node
* distance being the lowest CPU intensive for the most aesthetic gain. The
* additional factors are more expensive but can have very attractive results.
* <p>
* The main loop of the algorithm consist of processing the nodes in a
* deterministic order. During the processing of each node a circle of radius
* <code>moveRadius</code> is made around the node and split into
* <code>triesPerCell</code> equal segments. Each point between neighbour
* segments is determined and the new energy of the system if the node were
* moved to that position calculated. Only the necessary nodes and edges are
* processed new energy values resulting in quadratic performance, O(VE),
* whereas calculating the total system energy would be cubic. The default
* implementation only checks 8 points around the radius of the circle, as
* opposed to the suggested 30 in the paper. Doubling the number of points
* double the CPU load and 8 works almost as well as 30.
* <p>
* The <code>moveRadius</code> replaces the temperature as the influencing
* factor in the way the graph settles in later iterations. If the user does
* not set the initial move radius it is set to half the maximum dimension
* of the graph. Thus, in 2 iterations a node may traverse the entire graph,
* and it is more sensible to find minima this way that uphill moves, which
* are little more than an expensive 'tilt' method. The factor by which
* the radius is multiplied by after each iteration is important, lowering
* it improves performance but raising it towards 1.0 can improve the
* resulting graph aesthetics. When the radius hits the minimum move radius
* defined, the layout terminates. The minimum move radius should be set
* a value where the move distance is too minor to be of interest.
* <p>
* Also, the idea of a fine tuning phase is used, as described in the paper.
* This involves only calculating the edge to node distance energy cost
* at the end of the algorithm since it is an expensive calculation and
* it really an 'optimizating' function. <code>fineTuningRadius</code>
* defines the radius value that, when reached, causes the edge to node
* distance to be calculated.
* <p>
* There are other special cases that are processed after each iteration.
* <code>unchangedEnergyRoundTermination</code> defines the number of
* iterations, after which the layout terminates. If nothing is being moved
* it is assumed a good layout has been found. In addition to this if
* no nodes are moved during an iteration the move radius is halved, presuming
* that a finer granularity is required.
*
*/
public class mxOrganicLayout extends mxGraphLayout
{

  /**
   * Whether or not the distance between edge and nodes will be calculated
   * as an energy cost function. This function is CPU intensive and is best
   * only used in the fine tuning phase.
   */
  protected boolean isOptimizeEdgeDistance = true;

  /**
   * Whether or not edges crosses will be calculated as an energy cost
   * function. This function is CPU intensive, though if some iterations
   * without it are required, it is best to have a few cycles at the start
   * of the algorithm using it, then use it intermittantly through the rest
   * of the layout.
   */
  protected boolean isOptimizeEdgeCrossing = true;

  /**
   * Whether or not edge lengths will be calculated as an energy cost
   * function. This function not CPU intensive.
   */
  protected boolean isOptimizeEdgeLength = true;

  /**
   * Whether or not nodes will contribute an energy cost as they approach
   * the bound of the graph. The cost increases to a limit close to the
   * border and stays constant outside the bounds of the graph. This function
   * is not CPU intensive
   */
  protected boolean isOptimizeBorderLine = true;

  /**
   * Whether or not node distribute will contribute an energy cost where
   * nodes are close together. The function is moderately CPU intensive.
   */
  protected boolean isOptimizeNodeDistribution = true;

  /**
   * when {@link #moveRadius}reaches this value, the algorithm is terminated
   */
  protected double minMoveRadius = 2.0;

  /**
   * The current radius around each node where the next position energy
   * values will be calculated for a possible move
   */
  protected double moveRadius;

  /**
   * The initial value of <code>moveRadius</code>. If this is set to zero
   * the layout will automatically determine a suitable value.
   */
  protected double initialMoveRadius = 0.0;

  /**
   * The factor by which the <code>moveRadius</code> is multiplied by after
   * every iteration. A value of 0.75 is a good balance between performance
   * and aesthetics. Increasing the value provides more chances to find
   * minimum energy positions and decreasing it causes the minimum radius
   * termination condition to occur more quickly.
   */
  protected double radiusScaleFactor = 0.75;

  /**
   * The average amount of area allocated per node. If <code> bounds</code>
   * is not set this value mutiplied by the number of nodes to find
   * the total graph area. The graph is assumed square.
   */
  protected double averageNodeArea = 160000;

  /**
   * The radius below which fine tuning of the layout should start
   * This involves allowing the distance between nodes and edges to be
   * taken into account in the total energy calculation. If this is set to
   * zero, the layout will automatically determine a suitable value
   */
  protected double fineTuningRadius = 40.0;

  /**
   * Limit to the number of iterations that may take place. This is only
   * reached if one of the termination conditions does not occur first.
   */
  protected int maxIterations = 1000;

  /**
   * Cost factor applied to energy calculations involving the distance
   * nodes and edges. Increasing this value tends to cause nodes to move away
   * from edges, at the partial cost of other graph aesthetics.
   * <code>isOptimizeEdgeDistance</code> must be true for edge to nodes
   * distances to be taken into account.
   */
  protected double edgeDistanceCostFactor = 3000;

  /**
   * Cost factor applied to energy calculations involving edges that cross
   * over one another. Increasing this value tends to result in fewer edge
   * crossings, at the partial cost of other graph aesthetics.
   * <code>isOptimizeEdgeCrossing</code> must be true for edge crossings
   * to be taken into account.
   */
  protected double edgeCrossingCostFactor = 6000;

  /**
   * Cost factor applied to energy calculations involving the general node
   * distribution of the graph. Increasing this value tends to result in
   * a better distribution of nodes across the available space, at the
   * partial cost of other graph aesthetics.
   * <code>isOptimizeNodeDistribution</code> must be true for this general
   * distribution to be applied.
   */
  protected double nodeDistributionCostFactor = 30000;

  /**
   * Cost factor applied to energy calculations for node promixity to the
   * notional border of the graph. Increasing this value results in
   * nodes tending towards the centre of the drawing space, at the
   * partial cost of other graph aesthetics.
   * <code>isOptimizeBorderLine</code> must be true for border
   * repulsion to be applied.
   */
  protected double borderLineCostFactor = 5;

  /**
   * Cost factor applied to energy calculations for the edge lengths.
   * Increasing this value results in the layout attempting to shorten all
   * edges to the minimum edge length, at the partial cost of other graph
   * aesthetics.
   * <code>isOptimizeEdgeLength</code> must be true for edge length
   * shortening to be applied.
   */
  protected double edgeLengthCostFactor = 0.02;

  /**
   * The x coordinate of the final graph
   */
  protected double boundsX = 0.0;

  /**
   * The y coordinate of the final graph
   */
  protected double boundsY = 0.0;

  /**
   * The width coordinate of the final graph
   */
  protected double boundsWidth = 0.0;

  /**
   * The height coordinate of the final graph
   */
  protected double boundsHeight = 0.0;

  /**
   * current iteration number of the layout
   */
  protected int iteration;

  /**
   * determines, in how many segments the circle around cells is divided, to
   * find a new position for the cell. Doubling this value doubles the CPU
   * load. Increasing it beyond 16 might mean a change to the
   * <code>performRound</code> method might further improve accuracy for a
   * small performance hit. The change is described in the method comment.
   */
  protected int triesPerCell = 8;

  /**
   * prevents from dividing with zero and from creating excessive energy
   * values
   */
  protected double minDistanceLimit = 2;

  /**
   * cached version of <code>minDistanceLimit</code> squared
   */
  protected double minDistanceLimitSquared;

  /**
   * distance limit beyond which energy costs due to object repulsive is
   * not calculated as it would be too insignificant
   */
  protected double maxDistanceLimit = 100;

  /**
   * cached version of <code>maxDistanceLimit</code> squared
   */
  protected double maxDistanceLimitSquared;

  /**
   * Keeps track of how many consecutive round have passed without any energy
   * changes
   */
  protected int unchangedEnergyRoundCount;

  /**
   * The number of round of no node moves taking placed that the layout
   * terminates
   */
  protected int unchangedEnergyRoundTermination = 5;

  /**
   * Whether or not to use approximate node dimensions or not. Set to true
   * the radius squared of the smaller dimension is used. Set to false the
   * radiusSquared variable of the CellWrapper contains the width squared
   * and heightSquared is used in the obvious manner.
   */
  protected boolean approxNodeDimensions = true;

  /**
   * Internal models collection of nodes ( vertices ) to be laid out
   */
  protected CellWrapper[] v;

  /**
   * Internal models collection of edges to be laid out
   */
  protected CellWrapper[] e;

  /**
   * Array of the x portion of the normalised test vectors that
   * are tested for a lower energy around each vertex. The vector
   * of the combined x and y normals are multipled by the current
   * radius to obtain test points for each vector in the array.
   */
  protected double[] xNormTry;

  /**
   * Array of the y portion of the normalised test vectors that
   * are tested for a lower energy around each vertex. The vector
   * of the combined x and y normals are multipled by the current
   * radius to obtain test points for each vector in the array.
   */
  protected double[] yNormTry;

  /**
   * Whether or not fine tuning is on. The determines whether or not
   * node to edge distances are calculated in the total system energy.
   * This cost function , besides detecting line intersection, is a
   * performance intensive component of this algorithm and best left
   * to optimization phase. <code>isFineTuning</code> is switched to
   * <code>true</code> if and when the <code>fineTuningRadius</code>
   * radius is reached. Switching this variable to <code>true</code>
   * before the algorithm runs mean the node to edge cost function
   * is always calculated.
   */
  protected boolean isFineTuning = true;

  /**
   *  Specifies if the STYLE_NOEDGESTYLE flag should be set on edges that are
   * modified by the result. Default is true.
   */
  protected boolean disableEdgeStyle = true;

  /**
   * Specifies if all edge points of traversed edges should be removed.
   * Default is true.
   */
  protected boolean resetEdges = false;

  /**
   * Constructor for mxOrganicLayout.
   */
  public mxOrganicLayout(mxGraph graph)
  {
    super(graph);
  }

  /**
   * Constructor for mxOrganicLayout.
   */
  public mxOrganicLayout(mxGraph graph, Rectangle2D bounds)
  {
    super(graph);
    boundsX = bounds.getX();
    boundsY = bounds.getY();
    boundsWidth = bounds.getWidth();
    boundsHeight = bounds.getHeight();
  }

  /**
   * Returns true if the given vertex has no connected edges.
   *
   * @param vertex Object that represents the vertex to be tested.
   * @return Returns true if the vertex should be ignored.
   */
  public boolean isVertexIgnored(Object vertex)
  {
    return false;
  }

  /**
   * Implements <mxGraphLayout.execute>.
   */
  public void execute(Object parent)
  {
    mxIGraphModel model = graph.getModel();
    mxGraphView view = graph.getView();
    Object[] vertices = graph.getChildVertices(parent);
    HashSet<Object> vertexSet = new HashSet<Object>(Arrays.asList(vertices));

    HashSet<Object> validEdges = new HashSet<Object>();

    // Remove edges that do not have both source and target terminals visible
    for (int i = 0; i < vertices.length; i++)
    {
      Object[] edges = mxGraphModel.getEdges(model, vertices[i], false, true, false);

      for (int j = 0; j < edges.length; j++)
      {
        // Only deal with sources. To be valid in the layout, each edge must be attached
        // at both source and target to a vertex in the layout. Doing this avoids processing
        // each edge twice.
        if (view.getVisibleTerminal(edges[j], true) == vertices[i] && vertexSet.contains(view.getVisibleTerminal(edges[j], false)))
        {
          validEdges.add(edges[j]);
        }
      }

    }

    Object[] edges = validEdges.toArray();

    // If the bounds dimensions have not been set see if the average area
    // per node has been
    mxRectangle totalBounds = null;
    mxRectangle bounds = null;
   
    // Form internal model of nodes
    Map<Object, Integer> vertexMap = new Hashtable<Object, Integer>();
    v = new CellWrapper[vertices.length];
    for (int i = 0; i < vertices.length; i++)
    {
      v[i] = new CellWrapper(vertices[i]);
      vertexMap.put(vertices[i], new Integer(i));
      bounds = getVertexBounds(vertices[i]);
     
      if (totalBounds == null)
      {
        totalBounds = (mxRectangle) bounds.clone();
      }
      else
      {
        totalBounds.add(bounds);
      }

      // 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();
      v[i].x = bounds.getX() + width / 2.0;
      v[i].y = bounds.getY() + height / 2.0;
      if (approxNodeDimensions)
      {
        v[i].radiusSquared = Math.min(width, height);
        v[i].radiusSquared *= v[i].radiusSquared;
      }
      else
      {
        v[i].radiusSquared = width * width;
        v[i].heightSquared = height * height;
      }
    }

    if (averageNodeArea == 0.0)
    {
      if (boundsWidth == 0.0 && totalBounds != null)
      {
        // Just use current bounds of graph
        boundsX = totalBounds.getX();
        boundsY = totalBounds.getY();
        boundsWidth = totalBounds.getWidth();
        boundsHeight = totalBounds.getHeight();
      }
    }
    else
    {
      // find the center point of the current graph
      // based the new graph bounds on the average node area set
      double newArea = averageNodeArea * vertices.length;
      double squareLength = Math.sqrt(newArea);
      if (bounds != null)
      {
        double centreX = totalBounds.getX() + totalBounds.getWidth() / 2.0;
        double centreY = totalBounds.getY() + totalBounds.getHeight() / 2.0;
        boundsX = centreX - squareLength / 2.0;
        boundsY = centreY - squareLength / 2.0;
      }
      else
      {
        boundsX = 0;
        boundsY = 0;
      }
      boundsWidth = squareLength;
      boundsHeight = squareLength;
      // Ensure x and y are 0 or positive
      if (boundsX < 0.0 || boundsY < 0.0)
      {
        double maxNegativeAxis = Math.min(boundsX, boundsY);
        double axisOffset = -maxNegativeAxis;
        boundsX += axisOffset;
        boundsY += axisOffset;
      }
    }

    // If the initial move radius has not been set find a suitable value.
    // A good value is half the maximum dimension of the final graph area
    if (initialMoveRadius == 0.0)
    {
      initialMoveRadius = Math.max(boundsWidth, boundsHeight) / 2.0;
    }

    moveRadius = initialMoveRadius;

    minDistanceLimitSquared = minDistanceLimit * minDistanceLimit;
    maxDistanceLimitSquared = maxDistanceLimit * maxDistanceLimit;

    unchangedEnergyRoundCount = 0;


    // Form internal model of edges
    e = new CellWrapper[edges.length];
   
    for (int i = 0; i < e.length; i++)
    {
      e[i] = new CellWrapper(edges[i]);

      Object sourceCell = model.getTerminal(edges[i], true);
      Object targetCell = model.getTerminal(edges[i], false);
      Integer source = null;
      Integer target = null;
      // Check if either end of the edge is not connected
      if (sourceCell != null)
      {
        source = vertexMap.get(sourceCell);
      }
      if (targetCell != null)
      {
        target = vertexMap.get(targetCell);
      }
      if (source != null)
      {
        e[i].source = source.intValue();
      }
      else
      {
        // source end is not connected
        e[i].source = -1;
      }
      if (target != null)
      {
        e[i].target = target.intValue();
      }
      else
      {
        // target end is not connected
        e[i].target = -1;
      }
    }

    // Set up internal nodes with information about whether edges
    // are connected to them or not
    for (int i = 0; i < v.length; i++)
    {
      v[i].relevantEdges = getRelevantEdges(i);
      v[i].connectedEdges = getConnectedEdges(i);
    }

    // Setup the normal vectors for the test points to move each vertex to
    xNormTry = new double[triesPerCell];
    yNormTry = new double[triesPerCell];

    for (int i = 0; i < triesPerCell; i++)
    {
      double angle = i
          * ((2.0 * Math.PI) / triesPerCell);
      xNormTry[i] = Math.cos(angle);
      yNormTry[i] = Math.sin(angle);
    }

   
    int childCount = model.getChildCount(parent);

    for (int i = 0; i < childCount; i++)
    {
      Object cell = model.getChildAt(parent, i);

      if (!isEdgeIgnored(cell))
      {
        if (isResetEdges())
        {
          graph.resetEdge(cell);
        }

        if (isDisableEdgeStyle())
        {
          setEdgeStyleEnabled(cell, false);
        }
      }
    }
   
    // The main layout loop
    for (iteration = 0; iteration < maxIterations; iteration++)
    {
      performRound();
    }

    // Obtain the final positions
    double[][] result = new double[v.length][2];
    for (int i = 0; i < v.length; i++)
    {
      vertices[i] = v[i].cell;
      bounds = getVertexBounds(vertices[i]);

      result[i][0] = v[i].x - bounds.getWidth() / 2;
      result[i][1] = v[i].y - bounds.getHeight() / 2;
    }

    model.beginUpdate();
    try
    {
      for (int i = 0; i < vertices.length; i++)
      {
        setVertexLocation(vertices[i], result[i][0], result[i][1]);
      }
    }
    finally
    {
      model.endUpdate();
    }
  }

  /**
   * The main round of the algorithm. Firstly, a permutation of nodes
   * is created and worked through in that random order. Then, for each node
   * a number of point of a circle of radius <code>moveRadius</code> are
   * selected and the total energy of the system calculated if that node
   * were moved to that new position. If a lower energy position is found
   * this is accepted and the algorithm moves onto the next node. There
   * may be a slightly lower energy value yet to be found, but forcing
   * the loop to check all possible positions adds nearly the current
   * processing time again, and for little benefit. Another possible
   * strategy would be to take account of the fact that the energy values
   * around the circle decrease for half the loop and increase for the
   * other, as a general rule. If part of the decrease were seen, then
   * when the energy of a node increased, the previous node position was
   * almost always the lowest energy position. This adds about two loop
   * iterations to the inner loop and only makes sense with 16 tries or more.
   */
  protected void performRound()
  {
    // sequential order cells are computed (every round the same order)

    // boolean to keep track of whether any moves were made in this round
    boolean energyHasChanged = false;
    for (int i = 0; i < v.length; i++)
    {
      int index = i;

      // Obtain the energies for the node is its current position
      // TODO The energy could be stored from the last iteration
      // and used again, rather than re-calculate
      double oldNodeDistribution = getNodeDistribution(index);
      double oldEdgeDistance = getEdgeDistanceFromNode(index);
      oldEdgeDistance += getEdgeDistanceAffectedNodes(index);
      double oldEdgeCrossing = getEdgeCrossingAffectedEdges(index);
      double oldBorderLine = getBorderline(index);
      double oldEdgeLength = getEdgeLengthAffectedEdges(index);
      double oldAdditionFactors = getAdditionFactorsEnergy(index);

      for (int j = 0; j < triesPerCell; j++)
      {
        double movex = moveRadius * xNormTry[j];
        double movey = moveRadius * yNormTry[j];

        // applying new move
        double oldx = v[index].x;
        double oldy = v[index].y;
        v[index].x = v[index].x + movex;
        v[index].y = v[index].y + movey;

        // calculate the energy delta from this move
        double energyDelta = calcEnergyDelta(index,
            oldNodeDistribution, oldEdgeDistance, oldEdgeCrossing,
            oldBorderLine, oldEdgeLength, oldAdditionFactors);

        if (energyDelta < 0)
        {
          // energy of moved node is lower, finish tries for this
          // node
          energyHasChanged = true;
          break; // exits loop
        }
        else
        {
          // Revert node coordinates
          v[index].x = oldx;
          v[index].y = oldy;
        }
      }
    }
    // Check if we've hit the limit number of unchanged rounds that cause
    // a termination condition
    if (energyHasChanged)
    {
      unchangedEnergyRoundCount = 0;
    }
    else
    {
      unchangedEnergyRoundCount++;
      // Half the move radius in case assuming it's set too high for
      // what might be an optimisation case
      moveRadius /= 2.0;
    }
    if (unchangedEnergyRoundCount >= unchangedEnergyRoundTermination)
    {
      iteration = maxIterations;
    }

    // decrement radius in controlled manner
    double newMoveRadius = moveRadius * radiusScaleFactor;
    // Don't waste time on tiny decrements, if the final pixel resolution
    // is 50 then there's no point doing 55,54.1, 53.2 etc
    if (moveRadius - newMoveRadius < minMoveRadius)
    {
      newMoveRadius = moveRadius - minMoveRadius;
    }
    // If the temperature reaches its minimum temperature then finish
    if (newMoveRadius <= minMoveRadius)
    {
      iteration = maxIterations;
    }
    // Switch on fine tuning below the specified temperature
    if (newMoveRadius < fineTuningRadius)
    {
      isFineTuning = true;
    }

    moveRadius = newMoveRadius;

  }

  /**
   * Calculates the change in energy for the specified node. The new energy is
   * calculated from the cost function methods and the old energy values for
   * each cost function are passed in as parameters
   *
   * @param index
   *            The index of the node in the <code>vertices</code> array
   * @param oldNodeDistribution
   *            The previous node distribution energy cost of this node
   * @param oldEdgeDistance
   *            The previous edge distance energy cost of this node
   * @param oldEdgeCrossing
   *            The previous edge crossing energy cost for edges connected to
   *            this node
   * @param oldBorderLine
   *            The previous border line energy cost for this node
   * @param oldEdgeLength
   *            The previous edge length energy cost for edges connected to
   *            this node
   * @param oldAdditionalFactorsEnergy
   *            The previous energy cost for additional factors from
   *            sub-classes
   *
   * @return the delta of the new energy cost to the old energy cost
   *
   */
  protected double calcEnergyDelta(int index, double oldNodeDistribution,
      double oldEdgeDistance, double oldEdgeCrossing,
      double oldBorderLine, double oldEdgeLength,
      double oldAdditionalFactorsEnergy)
  {
    double energyDelta = 0.0;
    energyDelta += getNodeDistribution(index) * 2.0;
    energyDelta -= oldNodeDistribution * 2.0;

    energyDelta += getBorderline(index);
    energyDelta -= oldBorderLine;

    energyDelta += getEdgeDistanceFromNode(index);
    energyDelta += getEdgeDistanceAffectedNodes(index);
    energyDelta -= oldEdgeDistance;

    energyDelta -= oldEdgeLength;
    energyDelta += getEdgeLengthAffectedEdges(index);

    energyDelta -= oldEdgeCrossing;
    energyDelta += getEdgeCrossingAffectedEdges(index);

    energyDelta -= oldAdditionalFactorsEnergy;
    energyDelta += getAdditionFactorsEnergy(index);

    return energyDelta;
  }

  /**
   * Calculates the energy cost of the specified node relative to all other
   * nodes. Basically produces a higher energy the closer nodes are together.
   *
   * @param i the index of the node in the array <code>v</code>
   * @return the total node distribution energy of the specified node
   */
  protected double getNodeDistribution(int i)
  {
    double energy = 0.0;

    // This check is placed outside of the inner loop for speed, even
    // though the code then has to be duplicated
    if (isOptimizeNodeDistribution == true)
    {
      if (approxNodeDimensions)
      {
        for (int j = 0; j < v.length; j++)
        {
          if (i != j)
          {
            double vx = v[i].x - v[j].x;
            double vy = v[i].y - v[j].y;
            double distanceSquared = vx * vx + vy * vy;
            distanceSquared -= v[i].radiusSquared;
            distanceSquared -= v[j].radiusSquared;

            // prevents from dividing with Zero.
            if (distanceSquared < minDistanceLimitSquared)
            {
              distanceSquared = minDistanceLimitSquared;
            }

            energy += nodeDistributionCostFactor / distanceSquared;
          }
        }
      }
      else
      {
        for (int j = 0; j < v.length; j++)
        {
          if (i != j)
          {
            double vx = v[i].x - v[j].x;
            double vy = v[i].y - v[j].y;
            double distanceSquared = vx * vx + vy * vy;
            distanceSquared -= v[i].radiusSquared;
            distanceSquared -= v[j].radiusSquared;
            // If the height separation indicates overlap, subtract
            // the widths from the distance. Same for width overlap
            // TODO            if ()

            // prevents from dividing with Zero.
            if (distanceSquared < minDistanceLimitSquared)
            {
              distanceSquared = minDistanceLimitSquared;
            }

            energy += nodeDistributionCostFactor / distanceSquared;
          }
        }
      }
    }
    return energy;
  }

  /**
   * This method calculates the energy of the distance of the specified
   * node to the notional border of the graph. The energy increases up to
   * a limited maximum close to the border and stays at that maximum
   * up to and over the border.
   *
   * @param i the index of the node in the array <code>v</code>
   * @return the total border line energy of the specified node
   */
  protected double getBorderline(int i)
  {
    double energy = 0.0;
    if (isOptimizeBorderLine)
    {
      // Avoid very small distances and convert negative distance (i.e
      // outside the border to small positive ones )
      double l = v[i].x - boundsX;
      if (l < minDistanceLimit)
        l = minDistanceLimit;
      double t = v[i].y - boundsY;
      if (t < minDistanceLimit)
        t = minDistanceLimit;
      double r = boundsX + boundsWidth - v[i].x;
      if (r < minDistanceLimit)
        r = minDistanceLimit;
      double b = boundsY + boundsHeight - v[i].y;
      if (b < minDistanceLimit)
        b = minDistanceLimit;
      energy += borderLineCostFactor
          * ((1000000.0 / (t * t)) + (1000000.0 / (l * l))
              + (1000000.0 / (b * b)) + (1000000.0 / (r * r)));
    }
    return energy;
  }

  /**
   * Obtains the energy cost function for the specified node being moved.
   * This involves calling <code>getEdgeLength</code> for all
   * edges connected to the specified node
   * @param node
   *         the node whose connected edges cost functions are to be
   *         calculated
   * @return the total edge length energy of the connected edges
   */
  protected double getEdgeLengthAffectedEdges(int node)
  {
    double energy = 0.0;
    for (int i = 0; i < v[node].connectedEdges.length; i++)
    {
      energy += getEdgeLength(v[node].connectedEdges[i]);
    }
    return energy;
  }

  /**
   * This method calculates the energy due to the length of the specified
   * edge. The energy is proportional to the length of the edge, making
   * shorter edges preferable in the layout.
   *
   * @param i the index of the edge in the array <code>e</code>
   * @return the total edge length energy of the specified edge
   */
  protected double getEdgeLength(int i)
  {
    if (isOptimizeEdgeLength)
    {
      double edgeLength = Point2D.distance(v[e[i].source].x,
          v[e[i].source].y, v[e[i].target].x, v[e[i].target].y);
      return (edgeLengthCostFactor * edgeLength * edgeLength);
    }
    else
    {
      return 0.0;
    }
  }

  /**
   * Obtains the energy cost function for the specified node being moved.
   * This involves calling <code>getEdgeCrossing</code> for all
   * edges connected to the specified node
   * @param node
   *         the node whose connected edges cost functions are to be
   *         calculated
   * @return the total edge crossing energy of the connected edges
   */
  protected double getEdgeCrossingAffectedEdges(int node)
  {
    double energy = 0.0;
    for (int i = 0; i < v[node].connectedEdges.length; i++)
    {
      energy += getEdgeCrossing(v[node].connectedEdges[i]);
    }

    return energy;
  }

  /**
   * This method calculates the energy of the distance from the specified
   * edge crossing any other edges. Each crossing add a constant factor
   * to the total energy
   *
   * @param i the index of the edge in the array <code>e</code>
   * @return the total edge crossing energy of the specified edge
   */
  protected double getEdgeCrossing(int i)
  {
    // TODO Could have a cost function per edge
    int n = 0; // counts energy of edgecrossings through edge i

    // max and min variable for minimum bounding rectangles overlapping
    // checks
    double minjX, minjY, miniX, miniY, maxjX, maxjY, maxiX, maxiY;

    if (isOptimizeEdgeCrossing)
    {
      double iP1X = v[e[i].source].x;
      double iP1Y = v[e[i].source].y;
      double iP2X = v[e[i].target].x;
      double iP2Y = v[e[i].target].y;

      for (int j = 0; j < e.length; j++)
      {
        double jP1X = v[e[j].source].x;
        double jP1Y = v[e[j].source].y;
        double jP2X = v[e[j].target].x;
        double jP2Y = v[e[j].target].y;
        if (j != i)
        {
          // First check is to see if the minimum bounding rectangles
          // of the edges overlap at all. Since the layout tries
          // to separate nodes and shorten edges, the majority do not
          // overlap and this is a cheap way to avoid most of the
          // processing
          // Some long code to avoid a Math.max call...
          if (iP1X < iP2X)
          {
            miniX = iP1X;
            maxiX = iP2X;
          }
          else
          {
            miniX = iP2X;
            maxiX = iP1X;
          }
          if (jP1X < jP2X)
          {
            minjX = jP1X;
            maxjX = jP2X;
          }
          else
          {
            minjX = jP2X;
            maxjX = jP1X;
          }
          if (maxiX < minjX || miniX > maxjX)
          {
            continue;
          }

          if (iP1Y < iP2Y)
          {
            miniY = iP1Y;
            maxiY = iP2Y;
          }
          else
          {
            miniY = iP2Y;
            maxiY = iP1Y;
          }
          if (jP1Y < jP2Y)
          {
            minjY = jP1Y;
            maxjY = jP2Y;
          }
          else
          {
            minjY = jP2Y;
            maxjY = jP1Y;
          }
          if (maxiY < minjY || miniY > maxjY)
          {
            continue;
          }

          // Ignore if any end points are coincident
          if (((iP1X != jP1X) && (iP1Y != jP1Y))
              && ((iP1X != jP2X) && (iP1Y != jP2Y))
              && ((iP2X != jP1X) && (iP2Y != jP1Y))
              && ((iP2X != jP2X) && (iP2Y != jP2Y)))
          {
            // Values of zero returned from Line2D.relativeCCW are
            // ignored because the point being exactly on the line
            // is very rare for double and we've already checked if
            // any end point share the same vertex. Should zero
            // ever be returned, it would be the vertex connected
            // to the edge that's actually on the edge and this is
            // dealt with by the node to edge distance cost
            // function. The worst case is that the vertex is
            // pushed off the edge faster than it would be
            // otherwise. Because of ignoring the zero this code
            // below can behave like only a 1 or -1 will be
            // returned. See Lines2D.linesIntersects().
            boolean intersects = ((Line2D.relativeCCW(iP1X, iP1Y,
                iP2X, iP2Y, jP1X, jP1Y) != Line2D.relativeCCW(
                iP1X, iP1Y, iP2X, iP2Y, jP2X, jP2Y)) && (Line2D
                .relativeCCW(jP1X, jP1Y, jP2X, jP2Y, iP1X, iP1Y) != Line2D
                .relativeCCW(jP1X, jP1Y, jP2X, jP2Y, iP2X, iP2Y)));

            if (intersects)
            {
              n++;
            }
          }
        }
      }
    }
    return edgeCrossingCostFactor * n;
  }

  /**
   * This method calculates the energy of the distance between Cells and
   * Edges. This version of the edge distance cost calculates the energy
   * cost from a specified <strong>node</strong>. The distance cost to all
   * unconnected edges is calculated and the total returned.
   *
   * @param i the index of the node in the array <code>v</code>
   * @return the total edge distance energy of the node
   */
  protected double getEdgeDistanceFromNode(int i)
  {
    double energy = 0.0;
    // This function is only performed during fine tuning for performance
    if (isOptimizeEdgeDistance && isFineTuning)
    {
      int[] edges = v[i].relevantEdges;
      for (int j = 0; j < edges.length; j++)
      {
        // Note that the distance value is squared
        double distSquare = Line2D.ptSegDistSq(v[e[edges[j]].source].x,
            v[e[edges[j]].source].y, v[e[edges[j]].target].x,
            v[e[edges[j]].target].y, v[i].x, v[i].y);

        distSquare -= v[i].radiusSquared;

        // prevents from dividing with Zero. No Math.abs() call
        // for performance
        if (distSquare < minDistanceLimitSquared)
        {
          distSquare = minDistanceLimitSquared;
        }

        // Only bother with the divide if the node and edge are
        // fairly close together
        if (distSquare < maxDistanceLimitSquared)
        {
          energy += edgeDistanceCostFactor / distSquare;
        }
      }
    }
    return energy;
  }

  /**
   * Obtains the energy cost function for the specified node being moved.
   * This involves calling <code>getEdgeDistanceFromEdge</code> for all
   * edges connected to the specified node
   * @param node
   *         the node whose connected edges cost functions are to be
   *         calculated
   * @return the total edge distance energy of the connected edges
   */
  protected double getEdgeDistanceAffectedNodes(int node)
  {
    double energy = 0.0;
    for (int i = 0; i < (v[node].connectedEdges.length); i++)
    {
      energy += getEdgeDistanceFromEdge(v[node].connectedEdges[i]);
    }

    return energy;
  }

  /**
   * This method calculates the energy of the distance between Cells and
   * Edges. This version of the edge distance cost calculates the energy
   * cost from a specified <strong>edge</strong>. The distance cost to all
   * unconnected nodes is calculated and the total returned.
   *
   * @param i the index of the edge in the array <code>e</code>
   * @return the total edge distance energy of the edge
   */
  protected double getEdgeDistanceFromEdge(int i)
  {
    double energy = 0.0;
    // This function is only performed during fine tuning for performance
    if (isOptimizeEdgeDistance && isFineTuning)
    {
      for (int j = 0; j < v.length; j++)
      {
        // Don't calculate for connected nodes
        if (e[i].source != j && e[i].target != j)
        {
          double distSquare = Line2D.ptSegDistSq(v[e[i].source].x,
              v[e[i].source].y, v[e[i].target].x,
              v[e[i].target].y, v[j].x, v[j].y);

          distSquare -= v[j].radiusSquared;

          // prevents from dividing with Zero. No Math.abs() call
          // for performance
          if (distSquare < minDistanceLimitSquared)
            distSquare = minDistanceLimitSquared;

          // Only bother with the divide if the node and edge are
          // fairly close together
          if (distSquare < maxDistanceLimitSquared)
          {
            energy += edgeDistanceCostFactor / distSquare;
          }
        }
      }
    }
    return energy;
  }

  /**
   * Hook method to adding additional energy factors into the layout.
   * Calculates the energy just for the specified node.
   * @param i the nodes whose energy is being calculated
   * @return the energy of this node caused by the additional factors
   */
  protected double getAdditionFactorsEnergy(int i)
  {
    return 0.0;
  }

  /**
   * Returns all Edges that are not connected to the specified cell
   *
   * @param cellIndex
   *            the cell index to which the edges are not connected
   * @return Array of all interesting Edges
   */
  protected int[] getRelevantEdges(int cellIndex)
  {
    ArrayList<Integer> relevantEdgeList = new ArrayList<Integer>(e.length);

    for (int i = 0; i < e.length; i++)
    {
      if (e[i].source != cellIndex && e[i].target != cellIndex)
      {
        // Add non-connected edges
        relevantEdgeList.add(new Integer(i));
      }
    }

    int[] relevantEdgeArray = new int[relevantEdgeList.size()];
    Iterator<Integer> iter = relevantEdgeList.iterator();

    //Reform the list into an array but replace Integer values with ints
    for (int i = 0; i < relevantEdgeArray.length; i++)
    {
      if (iter.hasNext())
      {
        relevantEdgeArray[i] = iter.next().intValue();
      }
    }

    return relevantEdgeArray;
  }

  /**
   * Returns all Edges that are connected with the specified cell
   *
   * @param cellIndex
   *            the cell index to which the edges are connected
   * @return Array of all connected Edges
   */
  protected int[] getConnectedEdges(int cellIndex)
  {
    ArrayList<Integer> connectedEdgeList = new ArrayList<Integer>(e.length);

    for (int i = 0; i < e.length; i++)
    {
      if (e[i].source == cellIndex || e[i].target == cellIndex)
      {
        // Add connected edges to list by their index number
        connectedEdgeList.add(new Integer(i));
      }
    }

    int[] connectedEdgeArray = new int[connectedEdgeList.size()];
    Iterator<Integer> iter = connectedEdgeList.iterator();

    // Reform the list into an array but replace Integer values with ints
    for (int i = 0; i < connectedEdgeArray.length; i++)
    {
      if (iter.hasNext())
      {
        connectedEdgeArray[i] = iter.next().intValue();
        ;
      }
    }

    return connectedEdgeArray;
  }

  /**
   * Returns <code>Organic</code>, the name of this algorithm.
   */
  public String toString()
  {
    return "Organic";
  }

  /**
   * Internal representation of a node or edge that holds cached information
   * to enable the layout to perform more quickly and to simplify the code
   */
  public class CellWrapper
  {

    /**
     * The actual graph cell this wrapper represents
     */
    protected Object cell;

    /**
     * All edge that repel this cell, only used for nodes. This array
     * is equivalent to all edges unconnected to this node
     */
    protected int[] relevantEdges = null;

    /**
     * the index of all connected edges in the <code>e</code> array
     * to this node. This is only used for nodes.
     */
    protected int[] connectedEdges = null;

    /**
     * The x-coordinate position of this cell, nodes only
     */
    protected double x;

    /**
     * The y-coordinate position of this cell, nodes only
     */
    protected double y;

    /**
     * The approximate radius squared of this cell, nodes only. If
     * approxNodeDimensions is true on the layout this value holds the
     * width of the node squared
     */
    protected double radiusSquared;

    /**
     * The height of the node squared, only used if approxNodeDimensions
     * is set to true.
     */
    protected double heightSquared;

    /**
     * The index of the node attached to this edge as source, edges only
     */
    protected int source;

    /**
     * The index of the node attached to this edge as target, edges only
     */
    protected int target;

    /**
     * Constructs a new CellWrapper
     * @param cell the graph cell this wrapper represents
     */
    public CellWrapper(Object cell)
    {
      this.cell = cell;
    }

    /**
     * @return the relevantEdges
     */
    public int[] getRelevantEdges()
    {
      return relevantEdges;
    }

    /**
     * @param relevantEdges the relevantEdges to set
     */
    public void setRelevantEdges(int[] relevantEdges)
    {
      this.relevantEdges = relevantEdges;
    }

    /**
     * @return the connectedEdges
     */
    public int[] getConnectedEdges()
    {
      return connectedEdges;
    }

    /**
     * @param connectedEdges the connectedEdges to set
     */
    public void setConnectedEdges(int[] connectedEdges)
    {
      this.connectedEdges = connectedEdges;
    }

    /**
     * @return the x
     */
    public double getX()
    {
      return x;
    }

    /**
     * @param x the x to set
     */
    public void setX(double x)
    {
      this.x = x;
    }

    /**
     * @return the y
     */
    public double getY()
    {
      return y;
    }

    /**
     * @param y the y to set
     */
    public void setY(double y)
    {
      this.y = y;
    }

    /**
     * @return the radiusSquared
     */
    public double getRadiusSquared()
    {
      return radiusSquared;
    }

    /**
     * @param radiusSquared the radiusSquared to set
     */
    public void setRadiusSquared(double radiusSquared)
    {
      this.radiusSquared = radiusSquared;
    }

    /**
     * @return the heightSquared
     */
    public double getHeightSquared()
    {
      return heightSquared;
    }

    /**
     * @param heightSquared the heightSquared to set
     */
    public void setHeightSquared(double heightSquared)
    {
      this.heightSquared = heightSquared;
    }

    /**
     * @return the source
     */
    public int getSource()
    {
      return source;
    }

    /**
     * @param source the source to set
     */
    public void setSource(int source)
    {
      this.source = source;
    }

    /**
     * @return the target
     */
    public int getTarget()
    {
      return target;
    }

    /**
     * @param target the target to set
     */
    public void setTarget(int target)
    {
      this.target = target;
    }

    /**
     * @return the cell
     */
    public Object getCell()
    {
      return cell;
    }
  }

  /**
   * @return Returns the averageNodeArea.
   */
  public double getAverageNodeArea()
  {
    return averageNodeArea;
  }

  /**
   * @param averageNodeArea The averageNodeArea to set.
   */
  public void setAverageNodeArea(double averageNodeArea)
  {
    this.averageNodeArea = averageNodeArea;
  }

  /**
   * @return Returns the borderLineCostFactor.
   */
  public double getBorderLineCostFactor()
  {
    return borderLineCostFactor;
  }

  /**
   * @param borderLineCostFactor The borderLineCostFactor to set.
   */
  public void setBorderLineCostFactor(double borderLineCostFactor)
  {
    this.borderLineCostFactor = borderLineCostFactor;
  }

  /**
   * @return Returns the edgeCrossingCostFactor.
   */
  public double getEdgeCrossingCostFactor()
  {
    return edgeCrossingCostFactor;
  }

  /**
   * @param edgeCrossingCostFactor The edgeCrossingCostFactor to set.
   */
  public void setEdgeCrossingCostFactor(double edgeCrossingCostFactor)
  {
    this.edgeCrossingCostFactor = edgeCrossingCostFactor;
  }

  /**
   * @return Returns the edgeDistanceCostFactor.
   */
  public double getEdgeDistanceCostFactor()
  {
    return edgeDistanceCostFactor;
  }

  /**
   * @param edgeDistanceCostFactor The edgeDistanceCostFactor to set.
   */
  public void setEdgeDistanceCostFactor(double edgeDistanceCostFactor)
  {
    this.edgeDistanceCostFactor = edgeDistanceCostFactor;
  }

  /**
   * @return Returns the edgeLengthCostFactor.
   */
  public double getEdgeLengthCostFactor()
  {
    return edgeLengthCostFactor;
  }

  /**
   * @param edgeLengthCostFactor The edgeLengthCostFactor to set.
   */
  public void setEdgeLengthCostFactor(double edgeLengthCostFactor)
  {
    this.edgeLengthCostFactor = edgeLengthCostFactor;
  }

  /**
   * @return Returns the fineTuningRadius.
   */
  public double getFineTuningRadius()
  {
    return fineTuningRadius;
  }

  /**
   * @param fineTuningRadius The fineTuningRadius to set.
   */
  public void setFineTuningRadius(double fineTuningRadius)
  {
    this.fineTuningRadius = fineTuningRadius;
  }

  /**
   * @return Returns the initialMoveRadius.
   */
  public double getInitialMoveRadius()
  {
    return initialMoveRadius;
  }

  /**
   * @param initialMoveRadius The initialMoveRadius to set.
   */
  public void setInitialMoveRadius(double initialMoveRadius)
  {
    this.initialMoveRadius = initialMoveRadius;
  }

  /**
   * @return Returns the isFineTuning.
   */
  public boolean isFineTuning()
  {
    return isFineTuning;
  }

  /**
   * @param isFineTuning The isFineTuning to set.
   */
  public void setFineTuning(boolean isFineTuning)
  {
    this.isFineTuning = isFineTuning;
  }

  /**
   * @return Returns the isOptimizeBorderLine.
   */
  public boolean isOptimizeBorderLine()
  {
    return isOptimizeBorderLine;
  }

  /**
   * @param isOptimizeBorderLine The isOptimizeBorderLine to set.
   */
  public void setOptimizeBorderLine(boolean isOptimizeBorderLine)
  {
    this.isOptimizeBorderLine = isOptimizeBorderLine;
  }

  /**
   * @return Returns the isOptimizeEdgeCrossing.
   */
  public boolean isOptimizeEdgeCrossing()
  {
    return isOptimizeEdgeCrossing;
  }

  /**
   * @param isOptimizeEdgeCrossing The isOptimizeEdgeCrossing to set.
   */
  public void setOptimizeEdgeCrossing(boolean isOptimizeEdgeCrossing)
  {
    this.isOptimizeEdgeCrossing = isOptimizeEdgeCrossing;
  }

  /**
   * @return Returns the isOptimizeEdgeDistance.
   */
  public boolean isOptimizeEdgeDistance()
  {
    return isOptimizeEdgeDistance;
  }

  /**
   * @param isOptimizeEdgeDistance The isOptimizeEdgeDistance to set.
   */
  public void setOptimizeEdgeDistance(boolean isOptimizeEdgeDistance)
  {
    this.isOptimizeEdgeDistance = isOptimizeEdgeDistance;
  }

  /**
   * @return Returns the isOptimizeEdgeLength.
   */
  public boolean isOptimizeEdgeLength()
  {
    return isOptimizeEdgeLength;
  }

  /**
   * @param isOptimizeEdgeLength The isOptimizeEdgeLength to set.
   */
  public void setOptimizeEdgeLength(boolean isOptimizeEdgeLength)
  {
    this.isOptimizeEdgeLength = isOptimizeEdgeLength;
  }

  /**
   * @return Returns the isOptimizeNodeDistribution.
   */
  public boolean isOptimizeNodeDistribution()
  {
    return isOptimizeNodeDistribution;
  }

  /**
   * @param isOptimizeNodeDistribution The isOptimizeNodeDistribution to set.
   */
  public void setOptimizeNodeDistribution(boolean isOptimizeNodeDistribution)
  {
    this.isOptimizeNodeDistribution = isOptimizeNodeDistribution;
  }

  /**
   * @return Returns the maxIterations.
   */
  public int getMaxIterations()
  {
    return maxIterations;
  }

  /**
   * @param maxIterations The maxIterations to set.
   */
  public void setMaxIterations(int maxIterations)
  {
    this.maxIterations = maxIterations;
  }

  /**
   * @return Returns the minDistanceLimit.
   */
  public double getMinDistanceLimit()
  {
    return minDistanceLimit;
  }

  /**
   * @param minDistanceLimit The minDistanceLimit to set.
   */
  public void setMinDistanceLimit(double minDistanceLimit)
  {
    this.minDistanceLimit = minDistanceLimit;
  }

  /**
   * @return Returns the minMoveRadius.
   */
  public double getMinMoveRadius()
  {
    return minMoveRadius;
  }

  /**
   * @param minMoveRadius The minMoveRadius to set.
   */
  public void setMinMoveRadius(double minMoveRadius)
  {
    this.minMoveRadius = minMoveRadius;
  }

  /**
   * @return Returns the nodeDistributionCostFactor.
   */
  public double getNodeDistributionCostFactor()
  {
    return nodeDistributionCostFactor;
  }

  /**
   * @param nodeDistributionCostFactor The nodeDistributionCostFactor to set.
   */
  public void setNodeDistributionCostFactor(double nodeDistributionCostFactor)
  {
    this.nodeDistributionCostFactor = nodeDistributionCostFactor;
  }

  /**
   * @return Returns the radiusScaleFactor.
   */
  public double getRadiusScaleFactor()
  {
    return radiusScaleFactor;
  }

  /**
   * @param radiusScaleFactor The radiusScaleFactor to set.
   */
  public void setRadiusScaleFactor(double radiusScaleFactor)
  {
    this.radiusScaleFactor = radiusScaleFactor;
  }

  /**
   * @return Returns the triesPerCell.
   */
  public int getTriesPerCell()
  {
    return triesPerCell;
  }

  /**
   * @param triesPerCell The triesPerCell to set.
   */
  public void setTriesPerCell(int triesPerCell)
  {
    this.triesPerCell = triesPerCell;
  }

  /**
   * @return Returns the unchangedEnergyRoundTermination.
   */
  public int getUnchangedEnergyRoundTermination()
  {
    return unchangedEnergyRoundTermination;
  }

  /**
   * @param unchangedEnergyRoundTermination The unchangedEnergyRoundTermination to set.
   */
  public void setUnchangedEnergyRoundTermination(
      int unchangedEnergyRoundTermination)
  {
    this.unchangedEnergyRoundTermination = unchangedEnergyRoundTermination;
  }

  /**
   * @return Returns the maxDistanceLimit.
   */
  public double getMaxDistanceLimit()
  {
    return maxDistanceLimit;
  }

  /**
   * @param maxDistanceLimit The maxDistanceLimit to set.
   */
  public void setMaxDistanceLimit(double maxDistanceLimit)
  {
    this.maxDistanceLimit = maxDistanceLimit;
  }

  /**
   * @return the approxNodeDimensions
   */
  public boolean isApproxNodeDimensions()
  {
    return approxNodeDimensions;
  }

  /**
   * @param approxNodeDimensions the approxNodeDimensions to set
   */
  public void setApproxNodeDimensions(boolean approxNodeDimensions)
  {
    this.approxNodeDimensions = approxNodeDimensions;
  }
 
  /**
   * @return the disableEdgeStyle
   */
  public boolean isDisableEdgeStyle()
  {
    return disableEdgeStyle;
  }

  /**
   * @param disableEdgeStyle the disableEdgeStyle to set
   */
  public void setDisableEdgeStyle(boolean disableEdgeStyle)
  {
    this.disableEdgeStyle = disableEdgeStyle;
  }

  /**
   * @return the resetEdges
   */
  public boolean isResetEdges()
  {
    return resetEdges;
  }

  /**
   * @param resetEdges the resetEdges to set
   */
  public void setResetEdges(boolean resetEdges)
  {
    this.resetEdges = resetEdges;
  }
}
TOP

Related Classes of com.mxgraph.layout.mxOrganicLayout$CellWrapper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.