Package org.gvt.layout

Source Code of org.gvt.layout.AbstractLayout

package org.gvt.layout;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PrecisionPoint;
import org.eclipse.draw2d.IFigure;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.ui.parts.ScrollingGraphicalViewer;
import org.eclipse.jface.util.Assert;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.gvt.ChisioMain;
import org.gvt.GraphAnimation;
import org.gvt.editpart.ChsScalableRootEditPart;
import org.gvt.figure.HighlightLayer;
import org.gvt.model.*;
import org.gvt.util.ChsTransform;

import java.util.*;

/**
* This class lays out the graph model rooted at the Chisio model passed into
* the constructor by first constructing an l-level model (LGraphManager,
* LGraph, LNode and LEdge) and copying the results back to the input Chisio
* model when finished.
*
* @author Cihan Kucukkececi
*
* Copyright: i-Vis Research Group, Bilkent University, 2007 - present
*/
public abstract class AbstractLayout
{
// -----------------------------------------------------------------------------
// Section: Instance Variables
// -----------------------------------------------------------------------------

  ChisioMain main;
  protected ScrollingGraphicalViewer viewer;

  /**
   * Geometric abstraction of the compound graph
   */
  protected LGraphManager lGraphManager;

  /**
   * Nesting levels of the compound structure
   */
  protected Vector inclusionLevels;

  /**
   * Hash maps to store the mapping of layout objects (l-level) and their
   * model level objects
   */
  protected HashMap viewMapVtoL;
  protected HashMap viewMapLtoV;

  /**
   * Indicates whether the topology will be created from Chisio model or not
   */
  protected boolean fromChisioModel;
  /**
   * Whether layout should create bendpoints as needed or not
   */
  protected boolean createBendsAsNeeded;

  /**
   * Whether layout should be incremental or not
   */
  protected boolean incremental;

  /**
   * Do we animate the layout process?
   */
  protected boolean animationDuringLayout;

  /**
   * Number iterations that should be done between two successive animations
   */
  protected int animationPeriod;

  /**
   * This is used for creation of bendpoints by using dummy nodes and edges.
   * Maps an LEdge to its dummy bendpoint path.
   */
  protected HashMap edgeToDummyNodes = new HashMap();

  /**
   * Layout Quality: 0:proof, 1:default, 2:draft
   */
  protected int layoutQuality;

  /**
   * Holds given root chisio model in constructor in order to use it in
   * createTopology method, later.
   */
  CompoundModel rootModel;

  /**
   * Holds given list of edges and nodes in constructor in order to use it in
   * createTopology method, later.
   */
  private List<LNode> V;
  private List<LEdge> E;

// -----------------------------------------------------------------------------
// Section: Constructors and Initializations
// -----------------------------------------------------------------------------
  /**
   *  Initializes fields and creates topology according to given chisio root
   *  model.
   */
  public AbstractLayout(CompoundModel rootModel)
  {
    assert (rootModel != null): "Root chisio model cannot be null";

    this.init();
    this.fromChisioModel = true;
    this.rootModel = rootModel;
  }

  /**
   *  Initialize field and creates topoly according to given LNodes and LEdges
   */
  public AbstractLayout(List<LNode> V, List<LEdge> E)
  {
    assert (V != null): "Node list cannot be null";
    assert (E != null): "Edge list cannot be null";

    this.init();
    this.fromChisioModel = false;
    this.V = V;
    this.E = E;
  }

  private void init()
  {
    this.lGraphManager = this.createNewLGraphManager();
    this.inclusionLevels = new Vector();
    this.viewMapVtoL = new HashMap();
    this.viewMapLtoV = new HashMap();
  }

  /**
   * This method creates light-weight abstractions (layout level objects) of
   * the given Chisio compound graph model. It returns false if the provided
   * topology is unexpected (e.g. compound structures, where they are not
   * supported).
   */
  protected boolean createTopology(CompoundModel rootModel)
  {
    LNode rootNode = this.createLGraphs(rootModel, 0);
    this.createLEdges(rootModel);
    this.lGraphManager.setRootGraph(rootNode.getChild());
    this.initialize();

    return true;
  }

  /**
   * This method sets required fields of this class according to already
   * created l-level topology. These fields are:
   *  - Owner graph of given nodes.
   *  - LGraphManager of given nodes.
   *  - Inclusion levels for the given graph structure (currently flat)
   * It returns false if the provided topology is unexpected (e.g. compound
   * structures, where they are not supported).
   */
  protected boolean createTopology(List<LNode> lNodes,List<LEdge> lEdges)
  {
    // Create root lNode and root lGraph
    LNode rootNode = this.createNewLNode(this.lGraphManager, null);
    LGraph rootGraph = this.createNewLGraph(rootNode, this.lGraphManager);
    rootNode.setChild(rootGraph);
    this.lGraphManager.getGraphs().add(rootGraph);

    // Adjust levels
    Vector currentLevel = new Vector(1);
    this.inclusionLevels.add(0,currentLevel);

    // Process all nodes and make necessary settings.
    for (LNode currentNode : lNodes)
    {
      currentNode.setOwner(rootGraph);
      currentNode.setChild(null);
      currentNode.graphManager = this.lGraphManager;
      rootGraph.getNodes().add(currentNode);
      currentLevel.add(currentNode);
    }

    // Process all edges and make necessary settings.
    for (LEdge currentEdge : lEdges)
    {
      assert currentEdge.source != null;
      assert currentEdge.target != null;

      assert rootGraph.getNodes().contains(currentEdge.source);
      assert rootGraph.getNodes().contains(currentEdge.target);

      this.lGraphManager.getEdgeList().add(currentEdge);
      rootGraph.getEdges().add(currentEdge);
    }

    this.lGraphManager.setRootGraph(rootNode.getChild());
    this.initialize();

    return true;
  }

  /**
   * This method initializes layout parameters.
   */
  public void initialize()
  {
    this.initParameters();
  }

  public LGraphManager createNewLGraphManager()
  {
    return new LGraphManager(this);
  }

  public LNode createNewLNode(LGraphManager gm, NodeModel model)
  {
    return new LNode(gm);
  }

  public LNode createNewLNode(LGraphManager gm,
    NodeModel model,
    Point loc,
    Dimension size)
  {
    return new LNode(gm, loc, size);
  }

  public LEdge createNewLEdge(LNode source, LNode target)
  {
    return new LEdge(source, target);
  }

  public LGraph createNewLGraph(LNode rootNode, LGraphManager lGraphManager)
  {
    return new LGraph(rootNode, lGraphManager);
  }

  protected LNode createLGraphs(CompoundModel model, int level)
  {
    LNode rootNode;
    LNode lNode;
    Vector currentLevel;

    if (this.inclusionLevels.size() < level + 1)
    {
      currentLevel = new Vector();
      this.inclusionLevels.add(level, currentLevel);
    }
    else
    {
      currentLevel = (Vector) this.inclusionLevels.elementAt(level);
    }

    LGraph lGraph;

    if (model.getParentModel() == null)
    // root of Chisio compound structure
    {
      rootNode = this.createNewLNode(this.lGraphManager, null);
    }
    else
    {
      rootNode =
        this.createNewLNode(this.lGraphManager,
          model,
          model.getLocationAbs(),
          model.getSize());
    }

    // instantiate an owner graph
    ArrayList lNodes = new ArrayList();
    lGraph = this.createNewLGraph(rootNode, this.lGraphManager);

    // get the nodes of the graph
    Iterator iter = model.getChildren().iterator();
    Object currentObject;
    boolean isCompound;

    while (iter.hasNext())
    {
      currentObject = iter.next();
      isCompound = currentObject instanceof CompoundModel;

      if (!isCompound)
//        // needed when compounds are in collapsed form!
//        || !currentNode.getChildGraph().isViewable())
      {
        NodeModel mdl = (NodeModel) currentObject;
        lNode =
          this.createNewLNode(this.lGraphManager,
            mdl,
            mdl.getLocationAbs(),
            mdl.getSize());
        lNode.setChild(null);
      }
      else
      {
        // recurse on this node
        // also set Chisio model node appropriately
        lNode =
          this.createLGraphs((CompoundModel) currentObject,
            level + 1);
        lNode.setRect(((NodeModel) currentObject).getLocationAbs(),
          ((NodeModel) currentObject).getSize());
      }

      lNode.setOwner(lGraph);
      lNodes.add(lNode);

      // Since (in the createTopology method) the edges are traversed
      // after all the l-level nodes are created, they must be kept in a
      // hash map in which they are bound to v-level nodes
      currentLevel.add(lNode);
      this.viewMapVtoL.put((GraphObject) currentObject, lNode);
      this.viewMapLtoV.put(lNode, (GraphObject) currentObject);
    }

    // set the nodes of the LGraph and return the node that owns this graph;
    // also make sure that this graph is added to the graphs list of
    // LGraphManager
    lGraph.setNodes(lNodes);
    this.lGraphManager.getGraphs().add(lGraph);
    rootNode.setChild(lGraph);

    return rootNode;
  }

  /**
   * This method creates l-level edges for all Chisio edges.
   */
  protected void createLEdges(CompoundModel root)
  {
    // iterate through the list of all edges in this graph and create
    // LEdge's reading the information from the hash map created before
    // according to the source and target nodes
    Iterator iter = root.getEdgeIterator(CompoundModel.ALL_EDGES, true, false);
    EdgeModel vEdge;

    while (iter.hasNext())
    {
      vEdge = (EdgeModel) iter.next();

      NodeModel vSource = vEdge.getSource();
      NodeModel vTarget = vEdge.getTarget();

      // get corresponding l-level nodes from the map
      LNode lSource = (LNode) this.viewMapVtoL.get(vSource);
      LNode lTarget = (LNode) this.viewMapVtoL.get(vTarget);

      // create the LEdge
      LEdge lEdge = this.createNewLEdge(lSource, lTarget);

      Assert.isTrue((vSource.getParentModel() != vTarget.getParentModel())
        == lEdge.isInterGraph);

      // add the newly created edge to the owner of the source (or target)
      // node, also add it to the LGraphManager
      LGraph lGraph = lSource.getOwner();
      lGraph.getEdges().add(lEdge);
      this.lGraphManager.getEdgeList().add(lEdge);

      this.viewMapVtoL.put(vEdge, lEdge);
      this.viewMapLtoV.put(lEdge, vEdge);
    }
  }

// -----------------------------------------------------------------------------
// Section: Accessor Methods
// -----------------------------------------------------------------------------
  /**
   * This method returns the associated layout graph manager.
   */
  public LGraphManager getLGraphManager()
  {
    return this.lGraphManager;
  }

  /**
   * This method returns the array of all nodes.
   */
  public Object[] getNodes()
  {
    return this.lGraphManager.getNodes();
  }

  /**
   * This method returns the array of all edges.
   */
  public Object[] getEdges()
  {
    return this.lGraphManager.getEdges();
  }

  public Dimension getCurrentSize()
  {
    return new Dimension(viewer.getControl().getShell().getSize());
  }

  public void setViewer(ScrollingGraphicalViewer viewer)
  {
    this.viewer = viewer;
  }

// -----------------------------------------------------------------------------
// Section: Remaining Methods
// -----------------------------------------------------------------------------
  /**
   *  This method shows busy cursor while layout is runnning.
   */
  public final void runLayout()
  {
    viewer.getControl().getShell().setEnabled(false);
    viewer.getControl().getShell().setCursor(new Cursor(null, SWT.CURSOR_WAIT));
    //disable higlight and handles
    IFigure highlightLayer = ((ChsScalableRootEditPart) viewer.getRootEditPart()).getLayer(
      HighlightLayer.HIGHLIGHT_LAYER);

    IFigure handleLayer = ((ChsScalableRootEditPart) viewer.getRootEditPart()).getLayer(
      LayerConstants.HANDLE_LAYER);

    highlightLayer.setVisible(false);
    handleLayer.setVisible(false);

    boolean isSuccessful;

    if (fromChisioModel)
    {
      isSuccessful = createTopology(rootModel);
    }
    else
    {
      isSuccessful = createTopology(V, E);
    }

    if (isSuccessful)
    {
      this.layout();

      this.transform();

      // Propagate geometric changes to v-level objects if we have created
      // l-graph objects from chisio model.
      if (fromChisioModel)
      {
        this.update();
      }
    }
    else
    {
      MessageBox mb = new MessageBox(new Shell(), SWT.OK);
      mb.setMessage("Compound structures are not supported by this"
        + " layout style!");
      mb.setText(ChisioMain.TOOL_NAME);
      mb.open();
    }

    //enable highlight and handles
    highlightLayer.setVisible(true);
    handleLayer.setVisible(true);

    viewer.getControl().getShell().setCursor(new Cursor(null, SWT.CURSOR_ARROW));
    viewer.getControl().getShell().setEnabled(true);
  }

  /**
   * This method is the main method of the layout algorithm; each new layout
   * algoritm must implement this method.
   */
  public abstract void layout();

  /**
   * This method is used to set all layout parameters to default values
   * determined at compile time.
   */
  public void initParameters()
  {
    LayoutOptionsPack.General layoutOptionsPack =
      LayoutOptionsPack.getInstance().getGeneral();

    this.animationDuringLayout =
      layoutOptionsPack.isAnimationDuringLayout();
    this.animationPeriod = (int) transform(
      layoutOptionsPack.getAnimationPeriod(), DEFAULT_ANIMATION_PERIOD);
    animationOnLayout = layoutOptionsPack.isAnimationOnLayout();

    this.layoutQuality = layoutOptionsPack.getLayoutQuality();
    this.incremental = layoutOptionsPack.isIncremental();
    this.createBendsAsNeeded = layoutOptionsPack.isCreateBendsAsNeeded();

    LGraph.setGraphMargin(CompoundModel.MARGIN_SIZE);
  }

  /**
   * This method transforms the LNodes in the associated LGraphManager so that
   * upper-left corner of the drawing is (0, 0). The goal is to avoid negative
   * coordinates that are not allowed when displaying by shifting the drawing
   * as necessary.
   */
  public void transform()
  {
    this.transform(new PrecisionPoint(0, 0));
  }

  /**
   * This method transforms the LNodes in the associated LGraphManager so that
   * upper-left corner of the drawing starts at the input coordinate.
   */
  public void transform(PrecisionPoint newLeftTop)
  {
    // create a transformation object (from Eclipse to layout). When an
    // inverse transform is applied, we get upper-left coordinate of the
    // drawing or the root graph at given input coordinate (some margins
    // already included in calculation of left-top).

    ChsTransform trans = new ChsTransform();
    Point leftTop = this.lGraphManager.getRoot().updateLeftTop();

    if (leftTop != null)
    {
      trans.setWorldOrgX(newLeftTop.preciseX);
      trans.setWorldOrgY(newLeftTop.preciseY);

      trans.setDeviceOrgX(leftTop.x);
      trans.setDeviceOrgY(leftTop.y);

      List nodes = this.lGraphManager.getNodeList();
      Iterator iter = nodes.iterator();

      while (iter.hasNext())
      {
        LNode lNode = (LNode) iter.next();
        lNode.transform(trans);
      }
    }
  }


  /**
   * This method updates the geometry of the target graph according to
   * calculated layout.
   */
  public void update()
  {
    createBendpointsFromDummyNodes();

    List nodes = lGraphManager.getNodeList();
    Iterator iter = nodes.iterator();

    while (iter.hasNext())
    {
      LNode lNode = (LNode) iter.next();

      NodeModel vNode = (NodeModel) viewMapLtoV.get(lNode);

      if (vNode == null)
      {
        continue;
      }

      if (lNode.getChild() == null ||
        lNode.getChild().getNodes().size() == 0)
      {
        vNode.setLocationAbs(new Point(lNode.getLocation().preciseX,
          lNode.getLocation().preciseY));
      }
      else
      {
        ((CompoundModel)vNode).calculateSize();
      }
    }

    if (animationOnLayout || animationDuringLayout)
    {
      GraphAnimation.run(viewer);
    }
  }

  /**
   * This method creates dummy nodes (an l-level node with minimal dimensions)
   * for the given edge (one per bendpoint). The existing l-level structure
   * is updated accordingly.
   */
  public List createDummyNodesForBendpoints(LEdge edge)
  {
    List dummyNodes = new ArrayList();
    LNode prev = edge.source;
    int level = prev.getInclusionTreeDepth()-1;
    LGraph graph =
      this.lGraphManager.findLowestCommonAncestor(edge.source, edge.target);

    for (int i = 0; i < edge.bendpoints.size(); i++)
    {
      // create new dummy node
      LNode dummyNode =
        this.createNewLNode(this.lGraphManager,
          null,
          new Point(0,0),
          new Dimension(1,1));
      dummyNode.setOwner(graph);
      dummyNode.setChild(null);
      graph.getNodes().add(dummyNode);
      ((Vector)this.inclusionLevels.get(level)).add(dummyNode);

      // create new dummy edge between prev and dummy node
      LEdge dummyEdge = this.createNewLEdge(prev, dummyNode);
      graph.getEdges().add(dummyEdge);
      this.lGraphManager.getEdgeList().add(dummyEdge);

      dummyNodes.add(dummyNode);
      prev = dummyNode;
    }

    LEdge dummyEdge = this.createNewLEdge(prev, edge.target);
    graph.getEdges().add(dummyEdge);
    this.lGraphManager.getEdgeList().add(dummyEdge);

    // remove real edge from graph
    this.edgeToDummyNodes.put(edge, dummyNodes);
    graph.getEdges().remove(edge);
    this.lGraphManager.getEdgeList().remove(edge);

    return dummyNodes;
  }

  /**
   * This method creates bendpoints for edges in Chisio from the dummy nodes
   * at l-level.
   */
  public void createBendpointsFromDummyNodes()
  {
    List edges = this.lGraphManager.getEdgeList();
    edges.addAll(0, this.edgeToDummyNodes.keySet());

    for (int k = 0 ; k < edges.size(); k++)
    {
      LEdge lEdge = (LEdge) edges.get(k);

      if (lEdge.bendpoints.size() > 0)
      {
        List path = (List) this.edgeToDummyNodes.get(lEdge);

        Point sourceLoc =
          new Point(lEdge.source.getCenterX(),
            lEdge.source.getCenterY());
        Point targetLoc =
          new Point(lEdge.target.getCenterX(),
            lEdge.target.getCenterY());
        int level = lEdge.source.getInclusionTreeDepth()-1;
        LGraph graph = this.lGraphManager.findLowestCommonAncestor(
          lEdge.source, lEdge.target);

        for (int i = 0; i < path.size(); i++)
        {
          LNode dummyNode = ((LNode)path.get(i));
          Point p =
            new PrecisionPoint(dummyNode.getCenterX(),
              dummyNode.getCenterY());

          // update bendpoint's location according to dummy node
          EdgeBendpoint ebp =
            (EdgeBendpoint) lEdge.bendpoints.get(i);
          ebp.setRelativeDimensions(
            p.getDifference(sourceLoc),
            p.getDifference(targetLoc));

          // remove created dummy node and dummy edges
          graph.getNodes().remove(dummyNode);
          ((Vector)this.inclusionLevels.get(level)).remove(dummyNode);

          graph.getEdges().removeAll(dummyNode.edges);
          this.lGraphManager.getEdgeList().removeAll(dummyNode.edges);

          this.lGraphManager.getNodeList().remove(dummyNode);
        }

        // add the real edge to graph list
        graph.getEdges().add(lEdge);
      }

      // transfer bendpoints information to v-level
      EdgeModel edge = (EdgeModel) this.viewMapLtoV.get(lEdge);
      edge.setBendpoints(lEdge.bendpoints);
    }
  }

  /**
   * This method determines the initial positions of leaf nodes in the
   * associated l-level compound graph structure randomly. Non-empty compound
   * nodes get their initial positions (and dimensions) from their contents,
   * thus no calculations should be done for them!
   */
  protected void positionNodesRandomly()
  {
    assert !this.incremental;

    Object[] lNodes = this.lGraphManager.getNodes();
    LNode lNode;

    for (int i = 0; i < lNodes.length; i++)
    {
      lNode = (LNode) lNodes[i];

      if (lNode.getChild() == null)
      {
        lNode.scatter();
      }
      else if (lNode.getChild().getNodes().size() == 0)
      {
        lNode.scatter();
      }
      else
      {
        lNode.updateBounds();
      }
    }
  }

  /**
   * This method returns a list of trees where each tree is represented as a
   * list of l-nodes. The method returns a list of size 0 when:
   * - The graph is not flat or
   * - One of the component(s) of the graph is not a tree.
   */
  protected ArrayList<ArrayList<LNode>> getFlatForest()
  {
    ArrayList<ArrayList<LNode>> flatForest =
      new ArrayList<ArrayList<LNode>>();
    boolean isForest = true;

    // Quick reference for all nodes in the graph manager associated with
    // this layout. The list should not be changed.
    final List<LNode> allNodes = this.lGraphManager.getRoot().getNodes();

    // First be sure that the graph is flat
    boolean isFlat = true;

    for (int i = 0; i < allNodes.size(); i++)
    {
      if (allNodes.get(i).getChild() != null)
      {
        isFlat = false;
      }
    }

    // Return empty forest if the graph is not flat.
    if (!isFlat)
    {
      return flatForest;
    }

    // Run BFS for each component of the graph.

    Set<LNode> visited = new HashSet<LNode>();
    LinkedList<LNode> toBeVisited = new LinkedList<LNode>();
    HashMap<LNode, LNode> parents = new HashMap<LNode, LNode>();
    LinkedList<LNode> unProcessedNodes = new LinkedList<LNode>();

    unProcessedNodes.addAll(allNodes);

    // Each iteration of this loop finds a component of the graph and
    // decides whether it is a tree or not. If it is a tree, adds it to the
    // forest and continued with the next component.

    while (unProcessedNodes.size() > 0 && isForest)
    {
      toBeVisited.add(unProcessedNodes.getFirst());

      // Start the BFS. Each iteration of this loop visits a node in a
      // BFS manner.
      while (!toBeVisited.isEmpty() && isForest)
      {
        LNode currentNode = toBeVisited.poll();
        visited.add(currentNode);

        // Traverse all neighbors of this node.
        List<LEdge> neighborEdges = currentNode.getEdges();

        for (int i = 0; i < neighborEdges.size(); i++)
        {
          LNode currentNeighbor =
            neighborEdges.get(i).getOtherEnd(currentNode);

          // If BFS is not growing from this neighbor.
          if (parents.get(currentNode) != currentNeighbor)
          {
            // We haven't previously visited this neighbor.
            if (!visited.contains(currentNeighbor))
            {
              toBeVisited.addLast(currentNeighbor);
              parents.put(currentNeighbor, currentNode);
            }
            // Since we have previously visited this neighbor and
            // this neighbor is not parent of currentNode, given
            // graph contains a component that is not tree, hence
            // it is not a forest.
            else
            {
              isForest = false;
              break;
            }
          }
        }
      }

      if (!isForest)
      // The graph contains a component that is not a tree. Empty
      // previously found trees. The method will end.
      {
        flatForest.clear();
      }
      else
      // Save currently visited nodes as a tree in our forest. Reset
      // visited and parents lists. Continue with the next component of
      // the graph, if any.
      {
        flatForest.add(new ArrayList<LNode>(visited));
        unProcessedNodes.removeAll(visited);
        visited.clear();
        parents.clear();
      }
    }

    return flatForest;
  }

  /**
   * This method moves the l-nodes towards the middle of the screen for better
   * visibility during animation.
   */
  protected void moveTowardsScreenCenter()
  {
    Object[] lNodes = this.getNodes();

    for (int i = 0; i < lNodes.length; i++)
    {
      LNode node = (LNode) lNodes[i];

      node.moveBy(500, 500);
    }
  }

// -----------------------------------------------------------------------------
// Section: Class Methods
// -----------------------------------------------------------------------------
  /**
   * This method returns the sign of the input value.
   */
  static public int sign(double value)
  {
    if (value > 0)
    {
      return 1;
    }
    else if (value < 0)
    {
      return -1;
    }
    else
    {
      return 0;
    }
  }

  /**
   * This method transforms the input slider value into an actual parameter
   * value using two separate linear functions (one from 0 to 50, other from
   * 50 to 100), where default slider value (50) maps to the default value of
   * the associated actual parameter. Minimum and maximum slider values map to
   * 1/10 and 10 fold of this default value, respectively.
   */
  public static double transform(int sliderValue, double defaultValue)
  {
    double a, b;

    if (sliderValue <= 50)
    {
      a = 9.0 * defaultValue / 500.0;
      b = defaultValue / 10.0;
    }
    else
    {
      a = 9.0 * defaultValue / 50.0;
      b = -8 * defaultValue;
    }

    return (a * sliderValue + b);
  }

  /**
   * This method takes a list of lists, where each list contains l-nodes of a
   * tree. Center of each tree is return as a list of.
   */
  public static List<LNode> findCenterOfEachTree(List<List> listofLists)
  {
    ArrayList<LNode> centers = new ArrayList<LNode>();

    for (int i = 0; i < listofLists.size(); i++)
    {
      List<LNode> list = listofLists.get(i);
      LNode center = findCenterOfTree(list);
      centers.add(i, center);
    }

    return centers;
  }

  /**
   * This method finds and returns the center of the given nodes, assuming
   * that the given nodes form a tree in themselves.
   */
  public static LNode findCenterOfTree(List<LNode> nodes)
  {
    ArrayList<LNode> list = new ArrayList<LNode>();
    list.addAll(nodes);

    ArrayList<LNode> removedNodes = new ArrayList<LNode>();
    HashMap<LNode, Integer> remainingDegrees =
      new HashMap<LNode, Integer>();
    boolean foundCenter = false;
    LNode centerNode = null;

    if (list.size() == 1 || list.size() == 2)
    {
      foundCenter = true;
      centerNode = list.get(0);
    }

    Iterator<LNode> iter = list.iterator();

    while (iter.hasNext())
    {
      LNode node = iter.next();
      Integer degree = new Integer(node.getNeighborsList().size());
      remainingDegrees.put(node , degree);

      if (degree.intValue() == 1)
      {
        removedNodes.add(node);
      }
    }

    ArrayList<LNode> tempList = new ArrayList<LNode>();
    tempList.addAll(removedNodes);

    while (!foundCenter)
    {
      ArrayList<LNode> tempList2 = new ArrayList<LNode>();
      tempList2.addAll(tempList);
      tempList.removeAll(tempList);
      iter = tempList2.iterator();

      while (iter.hasNext())
      {
        LNode node = iter.next();
        list.remove(node);

        Set<LNode> neighbours = node.getNeighborsList();

        for (LNode neighbor: neighbours)
        {
          if (!removedNodes.contains(neighbor))
          {
            Integer otherDegree = remainingDegrees.get(neighbor);
            Integer newDegree =
              new Integer(otherDegree.intValue() - 1);

            if (newDegree.intValue() == 1)
            {
              tempList.add(neighbor);
            }

            remainingDegrees.put(neighbor, newDegree);
          }
        }
      }

      removedNodes.addAll(tempList);

      if (list.size() == 1 || list.size() == 2)
      {
        foundCenter = true;
        centerNode = list.get(0);
      }
    }

    return centerNode;
  }

// -----------------------------------------------------------------------------
// Section: Class Variables
// -----------------------------------------------------------------------------
  /**
   * Do we animate the before and after layout node replacements?
   */
  public static boolean animationOnLayout;

  /**
   * This variable stores the world boundaries that this manager operates on.
   */
  public static final int WORLD_BOUNDARY = 1000000;

  /**
   * This variable stores the coordinates of the gravity center used by some
   * layout algorithms.
   */
  public static final int GRAVITY_CENTER_X = 1200;
  public static final int GRAVITY_CENTER_Y = 900;

  /**
   * Layout Quality
   */
  public static final int PROOF_QUALITY = 0;
  public static final int DEFAULT_QUALITY = 1;
  public static final int DRAFT_QUALITY = 2;

  /**
   * Default parameters
   */
  public static final boolean DEFAULT_CREATE_BENDS_AS_NEEDED = false;
  public static final boolean DEFAULT_INCREMENTAL = false;
  public static final boolean DEFAULT_ANIMATION_ON_LAYOUT = true;
  public static final boolean DEFAULT_ANIMATION_DURING_LAYOUT = false;
  public static final int DEFAULT_ANIMATION_PERIOD = 50;
}
TOP

Related Classes of org.gvt.layout.AbstractLayout

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.