Package org.rascalmpl.library.vis.figure.graph.spring

Source Code of org.rascalmpl.library.vis.figure.graph.spring.SpringGraph$AnimateForces

/*******************************************************************************
* Copyright (c) 2009-2013 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:

*   * Paul Klint - Paul.Klint@cwi.nl - CWI
*******************************************************************************/
package org.rascalmpl.library.vis.figure.graph.spring;

import static org.rascalmpl.library.vis.properties.Properties.ID;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import org.eclipse.imp.pdb.facts.IConstructor;
import org.eclipse.imp.pdb.facts.IList;
import org.eclipse.imp.pdb.facts.IValue;
import org.rascalmpl.interpreter.utils.RuntimeExceptionFactory;
import org.rascalmpl.library.vis.figure.Figure;
import org.rascalmpl.library.vis.figure.FigureFactory;
import org.rascalmpl.library.vis.graphics.GraphicsContext;
import org.rascalmpl.library.vis.properties.Properties;
import org.rascalmpl.library.vis.properties.PropertyManager;
import org.rascalmpl.library.vis.swt.Animation;
import org.rascalmpl.library.vis.swt.ICallbackEnv;
import org.rascalmpl.library.vis.swt.IFigureConstructionEnv;
import org.rascalmpl.library.vis.swt.applet.IHasSWTElement;
import org.rascalmpl.library.vis.util.vector.Rectangle;
import org.rascalmpl.library.vis.util.vector.Vector2D;

/**

* Force-directed (spring) Graph layout. Given a list of nodes and edges a graph layout is computed with given size.
*
* We use a spring layout approach as described in
*
*     Fruchterman, T. M. J., & Reingold, E. M. (1991).
*     Graph Drawing by Force-Directed Placement.
*     Software: Practice and Experience, 21(11).
*
* with the extensions described here:
*
*     Arne Frick, Andreas Ludwig, Heiko Mehldau
*     A Fast Adaptive Layout Algorithm for Undirected Graphs
*     Proceedings of Graph Drawing '94,
*     Volume 894 of Lecture Notes in Computer Science,
*     edited by Roberto Tamassia and Ioannis Tollis,
*     Springer-Verlag, 1995.
*
*  Spring layout is activated by the property: hint("spring")
*
* @author paulk
*
*/
public class SpringGraph extends Figure {
  protected ArrayList<SpringGraphNode> nodes;
  protected ArrayList<SpringGraphEdge> edges;
  private HashMap<String, SpringGraphNode> registered;
 
  // Fields for force layout
  protected int temperature;
  private static boolean debug = false;
  private final ICallbackEnv env;
  private Animation currentAnimation;

  public SpringGraph(IFigureConstructionEnv fpa, PropertyManager properties, IList nodes,  IList edges) {
    super(properties);
    this.nodes = new ArrayList<SpringGraphNode>();
    this.env = fpa.getCallBackEnv();
    registered = new HashMap<String,SpringGraphNode>();
    for(IValue v : nodes){
      IConstructor c = (IConstructor) v;
      Figure fig = FigureFactory.make(fpa, c, properties, null);
      String name = fig.prop.getStr(ID);

      if(name.length() == 0)
        throw RuntimeExceptionFactory.figureException("Id property should be defined", v, fpa.getRascalContext().getCurrentAST(), fpa.getRascalContext().getStackTrace());

      SpringGraphNode node = new SpringGraphNode(this, name, fig);
      this.nodes.add(node);
      register(name, node);
    }

    this.edges = new ArrayList<SpringGraphEdge>();
    for (IValue v : edges) {
      IConstructor c = (IConstructor) v;
      PropertyManager pm = c.arity() > 2 ? new PropertyManager(fpa, properties, (IList) c.get(2)) : properties;
      SpringGraphEdge e = FigureFactory.makeSpringGraphEdge(this, fpa, c, pm);
      this.edges.add(e);
      e.getFrom().addOut(e.getTo());
      e.getTo().addIn(e.getFrom());
    }

    // Create the children of the SpringGraph figure
   
    int nChildren = this.nodes.size() + this.edges.size();
    int nedges = this.edges.size();
    this.children = new Figure[nChildren];
   
    for(int i = 0; i < nedges; i++)
      this.children[i] = this.edges.get(i);
   
    for(int i = 0; i < this.nodes.size(); i++)
      this.children[nedges + i] = this.nodes.get(i);   
  }
 
  public void register(String name, SpringGraphNode nd){
    registered.put(name, nd);
  }

  public SpringGraphNode getRegistered(String name) {
    return registered.get(name);
  }
 
  public double EDGE_LENGTH;            // Set in computeMinSize.
  public double EDGE_LENGTH_2;             // Set in computeMinSize.
  public double RAND_DISTURB;              // Set in computeMinSize.
  public double MIN_GLOBAL_TEMPERATURE;    // Set in computeMinSize.
 
  public double MAX_LOCAL_TEMPERATURE = 256.0;
  public double ATTRACT = 6.0;
  public double REPEL = 6.0;
  public double UPDATE_STEP = 1;
  public double OSCILLATION = 1.0;
  public double SKEW = 1.0;
  public double ROTATION = 1.0;
  public double GRAVITY = 0.20;        // Set in computeMinSize.
  public static int MAX_ROUNDS = 400;

  public void printValues() {
    System.err.println("-----------------------------------------");
    System.err.println("#NODES                 = " + nodes.size());
    System.err.println("#EDGES                 = " + edges.size());
    System.err.println("ATTRACT                = " + ATTRACT);
    System.err.println("EDGE_LENGTH            = " + EDGE_LENGTH);
    System.err.println("EDGE_LENGTH_2          = " + EDGE_LENGTH_2);
    System.err.println("UPDATE_STEP            = " + UPDATE_STEP);
    System.err.println("OSCILLATION            = " + OSCILLATION);
    System.err.println("SKEW                   = " + SKEW);
    System.err.println("ROTATION               = " + ROTATION);
    System.err.println("GRAVITY                = " + GRAVITY);
    System.err.println("RAND_DISTURB           = " + RAND_DISTURB);
    System.err.println("MAX_LOCAL_TEMPERATURE  = " + MAX_LOCAL_TEMPERATURE);
    System.err.println("MIN_GLOBAL_TEMPERATURE = " + MIN_GLOBAL_TEMPERATURE);
  }
  public Vector2D getBaryCenter(){
   
//    return new Vector2D(minSize.getX()/2, minSize.getY()/2);
    double cx = 0;
    double cy = 0;
    for (SpringGraphNode n : nodes){
      cx += n.getCenterX();
      cy += n.getCenterY();
    }
    return new Vector2D(cx / nodes.size(), cy / nodes.size());
  }
 
   @Override
   public void computeMinSize(){
     double hsize = prop.getReal(Properties.HSIZE);
     double vsize = prop.getReal(Properties.VSIZE);
     if(hsize == 0)
       hsize = 100;
     if(vsize == 0)
       vsize = 100;
     minSize.set(hsize,vsize);
     resizable.set(false, false);
     size.set(minSize);

     double hgap = prop.getReal(Properties.HGAP);
     double vgap = prop.getReal(Properties.VGAP);

     double mass = 0;
     double radius = 0;
     for (SpringGraphNode nd : nodes){
       nd.init();
       mass += nd.getMass();
       radius += nd.radius();
     }
     GRAVITY = 10 * nodes.size()/mass;
    
     EDGE_LENGTH = Math.max(Math.max(2 * radius / nodes.size(),
                                 Math.sqrt(size.getX() * size.getY()) / nodes.size()),
                                     Math.sqrt(hgap * hgap + vgap * vgap));
     EDGE_LENGTH_2 = EDGE_LENGTH * EDGE_LENGTH;
     RAND_DISTURB = EDGE_LENGTH/4;
     MIN_GLOBAL_TEMPERATURE = 0.005 * MAX_LOCAL_TEMPERATURE/ (1 +nodes.size());
    
     currentAnimation = new AnimateForces();
   }

  @Override
  public void drawElement(GraphicsContext gc, List<IHasSWTElement> visibleSWTElements){
    applyProperties(gc);
    if(currentAnimation != null){
      env.registerAnimation(currentAnimation);
    }
  }
 
  @Override
  public void resizeElement(Rectangle view) {
    localLocation.set(0,0);
  }
 
   @Override
  public void destroyElement(IFigureConstructionEnv env) {
     env.getCallBackEnv().unregisterAnimation(currentAnimation);
   }

  class AnimateForces implements Animation {
    int iteration;

    public AnimateForces() {
      iteration = 0;
      printValues();
    }

    @Override
    public boolean moreFrames() {
      return iteration < MAX_ROUNDS && globalTemperature() > MIN_GLOBAL_TEMPERATURE;
    }

    @Override
    public void animate() {
      if(debug)System.err.println("\nITERATION: " + iteration + ", total temp: "+ globalTemperature());
      Collections.shuffle(nodes);
     
      for (SpringGraphNode nd : nodes){
        nd.step();   
      }
     
      for(SpringGraphNode nd : nodes){
        nd.placeCenter(nd.getCenterX(), nd.getCenterY());
     
     
      iteration++;
    }
   
    // The global temperature is the sum of all node temperatures.
    public double globalTemperature(){
      double result = 0;
      for (SpringGraphNode n : nodes){
        result += n.temperature;
      }
      return result;
    }
  }

 
}
TOP

Related Classes of org.rascalmpl.library.vis.figure.graph.spring.SpringGraph$AnimateForces

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.