Package ca.nengo.ui.lib.world.elastic

Source Code of ca.nengo.ui.lib.world.elastic.ElasticLayoutRunner

package ca.nengo.ui.lib.world.elastic;

import java.awt.geom.Point2D;
import java.lang.reflect.InvocationTargetException;

import javax.swing.SwingUtilities;

import ca.nengo.ui.lib.util.ElasticLayout;
import ca.nengo.ui.lib.util.Util;
import ca.nengo.ui.lib.util.ElasticLayout.LengthFunction;
import edu.uci.ics.jung.graph.ArchetypeVertex;
import edu.uci.ics.jung.graph.Edge;
import edu.uci.ics.jung.graph.Vertex;
import edu.uci.ics.jung.graph.impl.SparseGraph;

public class ElasticLayoutRunner {
  /**
   * Used to determine when to pause the algorithm
   */
  public static final double RELAX_DELTA = 2;
  public static final float SPRING_LAYOUT_FORCE_MULTIPLIER = 1f / 3f;
  public static final int SPRING_LAYOUT_DEFAULT_LENGTH = 300;
  public static final int SPRING_LAYOUT_DEFAULT_REPULSION_DISTANCE = 200;
  private int relaxCount;
  private boolean continueLayout = true;

  private ElasticLayout layout;

  private SparseGraph myGraph;

  private final ElasticGround myParent;

  public ElasticLayoutRunner(ElasticGround world) {
    super();
    this.myParent = world;
    init();
  }

  class ElasticLengthFunction implements LengthFunction {

    public double getLength(Edge e) {
      if (e.containsUserDatumKey(ElasticGround.ELASTIC_LENGTH_KEY)) {
        return (Double) e.getUserDatum(ElasticGround.ELASTIC_LENGTH_KEY);
      } else {
        return SPRING_LAYOUT_DEFAULT_LENGTH;
      }
    }

    public double getMass(Vertex v) {
      if (v instanceof ElasticVertex) {
        return ((ElasticVertex) v).getRepulsionRange();
      }

      return SPRING_LAYOUT_DEFAULT_REPULSION_DISTANCE;
    }

  }

  private void init() {

    myParent.updateGraph();
    myGraph = myParent.getGraph();
    this.layout = new ElasticLayout(myGraph, new ElasticLengthFunction());
    layout.setForceMultiplier(SPRING_LAYOUT_FORCE_MULTIPLIER);
    layout.initialize();

    for (Object obj : myGraph.getVertices()) {
      ElasticVertex vertex = (ElasticVertex) obj;
      Point2D vertexLocation = vertex.getLocation();
      layout.forceMove(vertex, vertexLocation.getX(), vertexLocation.getY());
    }

  }

  private void runLayout() {

    while (!layout.incrementsAreDone() && !myParent.isDestroyed() && continueLayout) {

      /**
       * Layout nodes needs to be done in the Swing dispatcher thread
       */
      try {
        SwingUtilities.invokeAndWait(new Runnable() {
          public void run() {
            updateLayout();
          }
        });
      } catch (InvocationTargetException e) {
        e.getTargetException().printStackTrace();
      } catch (Exception e) {
        e.printStackTrace();
      }

      try {
        Thread.sleep(1000 / 25);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }

    if (layout.incrementsAreDone()) {
      Util.Assert(false, "Iterable layout is done, this shouldn't be possible");
    }
  }

  public void updateLayout() {
    if (checkLayout()) {
      myParent.updateChildrenFromLayout(layout, false, false);
    }
  }

  private boolean checkLayout() {

    ElasticGround.UpdateGraphResult result = myParent.updateGraph();

    if (result.isGraphUpdated()) {
      layout.update();

      // update new vertex positions
      for (ElasticVertex vertex : result.getAddedVertices()) {
        layout.forceMove(vertex, vertex.getLocation().getX(), vertex.getLocation().getY());
      }

      relaxCount = 0;
    }

    boolean isResting = false;

    if (relaxCount >= 50) {
      relaxCount = 50;
      isResting = true;
    }
    if (!isResting) {
      layout.advancePositions();

      // Check to see if the elastic graph has settled in a certain
      // position
      double maxDelta = 0;
      for (Object obj : myGraph.getVertices()) {
        ElasticVertex vertex = (ElasticVertex) obj;
        Point2D vertexLocation = vertex.getLocation();
        Point2D layoutLocation = layout.getLocation(vertex);

        double delta = Math.abs(vertexLocation.distance(layoutLocation));

        if (delta > maxDelta) {
          maxDelta = delta;
        }
      }

      if (maxDelta < RELAX_DELTA) {
        relaxCount++;
      }
    }
    return !isResting;
  }

  public void start() {
    Thread myLayoutThread = new Thread(new Runnable() {
      public void run() {
        runLayout();
      }
    }, "Elastic layout runner");

    // myLayoutThread.setPriority(Thread.NORM_PRIORITY);
    myLayoutThread.start();
  }

  public void stopLayout() {
    continueLayout = false;
  }

  public void forceMove(Vertex picked, double x, double y) {
    relaxCount = 0;
    layout.forceMove(picked, x, y);
  }

  public boolean isLocked(Vertex v) {
    return layout.isLocked(v);
  }

  public Point2D getLocation(ArchetypeVertex v) {
    return layout.getLocation(v);
  }

  public boolean isLockedVertex(Vertex v) {
    return layout.isLocked(v);
  }

  public void lockVertex(Vertex v) {
    layout.lockVertex(v);
  }

  public void unlockVertex(Vertex v) {
    layout.unlockVertex(v);
  }
}
TOP

Related Classes of ca.nengo.ui.lib.world.elastic.ElasticLayoutRunner

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.