Package net.wigis.graph.dnv.layout.implementations

Source Code of net.wigis.graph.dnv.layout.implementations.FruchtermanReingold

/******************************************************************************************************
* Copyright (c) 2010, University of California, Santa Barbara
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
*    * Redistributions of source code must retain the above copyright notice, this list of
*      conditions and the following disclaimer.
*    * Redistributions in binary form must reproduce the above copyright notice, this list of
*      conditions and the following disclaimer in the documentation and/or other materials
*      provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************************************/

package net.wigis.graph.dnv.layout.implementations;

import java.io.BufferedWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.List;

import net.wigis.graph.dnv.DNVEdge;
import net.wigis.graph.dnv.DNVGraph;
import net.wigis.graph.dnv.DNVNode;
import net.wigis.graph.dnv.layout.helpers.Grid;
import net.wigis.graph.dnv.layout.interfaces.SpaceRestrictedLayoutInterface;
import net.wigis.graph.dnv.utilities.GraphFunctions;
import net.wigis.graph.dnv.utilities.Timer;
import net.wigis.graph.dnv.utilities.Vector2D;

// TODO: Auto-generated Javadoc
/**
* The Class FruchtermanReingold.
*
* @author Brynjar Gretarsson
*/
public class FruchtermanReingold implements SpaceRestrictedLayoutInterface
{

  /**
   * Logger.
   *
   * @param width
   *            the width
   * @param height
   *            the height
   * @param graph
   *            the graph
   * @param level
   *            the level
   * @param temperature
   *            the temperature
   * @param useNumberOfSubnodes
   *            the use number of subnodes
   * @param useRestingDistance
   *            the use resting distance
   * @param useNodeSize
   *            the use node size
   */
  private static boolean enableWrite = true;
  // // private static Log logger = LogFactory.getLog(
  // FruchtermanReingold.class );
  public FruchtermanReingold(){
   
  }
  public FruchtermanReingold(boolean enableWrite){
    this.enableWrite = enableWrite;
  }
  public static void runIteration( float width, float height, DNVGraph graph, int level, float temperature, boolean useNumberOfSubnodes,
      boolean useRestingDistance, boolean useNodeSize )
  {
    runIteration( width, height, graph.getNodes( level ), graph.getEdges( level ), temperature, useNumberOfSubnodes, useRestingDistance,
        useNodeSize );
  }

  /**
   * Run iteration.
   *
   * @param width
   *            the width
   * @param height
   *            the height
   * @param nodes
   *            the nodes
   * @param edges
   *            the edges
   * @param temperature
   *            the temperature
   * @param useNumberOfSubnodes
   *            the use number of subnodes
   * @param useRestingDistance
   *            the use resting distance
   * @param useNodeSize
   *            the use node size
   */
  public static void runIteration( float width, float height, Collection<DNVNode> nodes, Collection<DNVEdge> edges, float temperature,
      boolean useNumberOfSubnodes, boolean useRestingDistance, boolean useNodeSize )
  {
   
   
    float area = width * height;
    float k = (float)Math.sqrt( area / nodes.size() );
    float kPower2 = k * k;

    // System.out.println( "Temperature : " + temperature + " Level : " +
    // level + " Number of Nodes: " + graph.getGraphSize( level ) );

    Vector2D difference = new Vector2D();
    float length;

    Grid grid = new Grid( k * 2, nodes );
    List<DNVNode> potentialNodes;

    // repulsive forces
    for( DNVNode v : nodes )
    {
      v.setForce( 0, 0 );
      potentialNodes = grid.getPotentialNodes( v );
      for( DNVNode u : potentialNodes )
      {
        if( u != v )
        {
          difference.set( v.getPosition() );
          difference.subtract( u.getPosition() );
          length = difference.length();
          // If two nodes are in exact same position
          // then we need to do something to move them apart.
          // Give them a small repelling force in random direction.
          if( length == 0 )
          {
            difference.set( (float)Math.random(), (float)Math.random() );
            length = difference.length();
          }
          if( length < k * 2 )
          {
            difference.normalize();
            if( useNodeSize )
            {
              difference.dotProduct( repel( length, kPower2 * u.getRadius() ) );
            }
            else
            {
              difference.dotProduct( repel( length, kPower2 ) );
            }
            if( useNumberOfSubnodes )
            {
              difference.dotProduct( Math.max( u.getSubNodes().size(), 1 ) );
              difference.dotProduct( Math.max( v.getSubNodes().size(), 1 ) );
            }
            v.getForce().add( difference );
          }
        }
      }
    }

    // attractive forces
    for( DNVEdge e : edges )
    {
      difference.set( e.getFrom().getPosition() );
      difference.subtract( e.getTo().getPosition() );
      length = difference.length();
      if( useRestingDistance )
      {
        length = length - e.getRestingDistance();
        length = length * e.getK();
        difference.normalize();
        difference.dotProduct( attract( length, k ) );
      }
      else
      {
        difference.dotProduct( attract( length, k ) );
      }
      if( e.getTo().getType().equals( "topic" ) || !e.getFrom().getType().equals( "topic" ) )
        e.getFrom().getForce().subtract( difference );
      if( !e.getTo().getType().equals( "topic" ) || e.getFrom().getType().equals( "topic" ) )
        e.getTo().getForce().add( difference );
    }
    /*
     * Vector2D center = GraphFunctions.getCenterOfGravity( nodes.iterator()
     * ); for( DNVNode v : nodes ) { difference.set( center );
     * difference.subtract( v.getPosition() ); v.getForce().add( difference
     * ); }
     */
    // apply the forces
    for( DNVNode v : nodes )
    {
      if( v.getProperty( "pinned" ) == null ||  v.getProperty( "pinned" ).equals("false"))
      {
        difference.set( v.getForce() );
        length = difference.length();
        difference.normalize();
        difference.dotProduct( Math.min( length, temperature ) );
        v.move( difference, true, false );
        // v.getPosition().setX( Math.min( width / 2.0f, Math.max(
        // -width / 2.0f, v.getPosition().getX() ) ) );
        // v.getPosition().setY( Math.min( height / 2.0f, Math.max(
        // -height / 2.0f, v.getPosition().getY() ) ) );
      }
    }
   
  }

  /**
   * Attract.
   *
   * @param x
   *            the x
   * @param k
   *            the k
   * @return the float
   */
  private static float attract( float x, float k )
  {
    return ( x * x ) / k;
  }

  /**
   * Repel.
   *
   * @param x
   *            the x
   * @param kPower2TimesRadiusU
   *            the k power2 times radius u
   * @return the float
   */
  public static float repel( float x, float kPower2TimesRadiusU )
  {
    return kPower2TimesRadiusU / x;
  }

  /**
   * Cool.
   *
   * @param temperature
   *            the temperature
   * @param coolingFactor
   *            the cooling factor
   * @return the float
   */
  public static float cool( float temperature, float coolingFactor )
  {
    if( temperature > 0.01 )
      return Math.max( 0, temperature * ( 1 - coolingFactor ) );

    return 0;
  }

  /**
   * Run layout.
   *
   * @param width
   *            the width
   * @param height
   *            the height
   * @param graph
   *            the graph
   * @param coolingFactor
   *            the cooling factor
   * @param level
   *            the level
   * @param layoutAllLevels
   *            the layout all levels
   * @param useNumberOfSubnodes
   *            the use number of subnodes
   */
  @Override
  public void runLayout( float width, float height, DNVGraph graph, float coolingFactor, int level, boolean layoutAllLevels,
      boolean useNumberOfSubnodes )
  {
    runLayout( width, height, graph, coolingFactor, level, layoutAllLevels, useNumberOfSubnodes, false, false );
  }

  /**
   * Run layout.
   *
   * @param width
   *            the width
   * @param height
   *            the height
   * @param graph
   *            the graph
   * @param coolingFactor
   *            the cooling factor
   * @param level
   *            the level
   * @param layoutAllLevels
   *            the layout all levels
   * @param useNumberOfSubnodes
   *            the use number of subnodes
   * @param useEdgeRestingDistance
   *            the use edge resting distance
   */
  @Override
  public void runLayout( float width, float height, DNVGraph graph, float coolingFactor, int level, boolean layoutAllLevels,
      boolean useNumberOfSubnodes, boolean useEdgeRestingDistance )
  {
    runLayout( width, height, graph, coolingFactor, level, layoutAllLevels, useNumberOfSubnodes, useEdgeRestingDistance, false );
  }

  /**
   * Run layout.
   *
   * @param width
   *            the width
   * @param height
   *            the height
   * @param graph
   *            the graph
   * @param coolingFactor
   *            the cooling factor
   * @param level
   *            the level
   * @param layoutAllLevels
   *            the layout all levels
   * @param useNumberOfSubnodes
   *            the use number of subnodes
   * @param useEdgeRestingDistance
   *            the use edge resting distance
   * @param useNodeSize
   *            the use node size
   */
  @Override
  public void runLayout( float width, float height, DNVGraph graph, float coolingFactor, int level, boolean layoutAllLevels,
      boolean useNumberOfSubnodes, boolean useEdgeRestingDistance, boolean useNodeSize )
  {
    if( layoutAllLevels )
    {
      for( level = graph.getMaxLevel(); level >= 0; level-- )
      {
        System.out.println( "Running Fruchterman-Reingold on level " + level );
        layoutLevel( width, height, graph.getNodes( level ), graph.getEdges( level ), coolingFactor, useNumberOfSubnodes,
            useEdgeRestingDistance, useNodeSize );
      }

      System.out.println( "Layout complete" );
    }
    else
    {
      runLayout( width, height, graph.getNodes( level ), graph.getEdges( level ), coolingFactor, useNumberOfSubnodes, useEdgeRestingDistance,
          useNodeSize );
    }

  }

  /**
   * Run layout.
   *
   * @param width
   *            the width
   * @param height
   *            the height
   * @param nodes
   *            the nodes
   * @param edges
   *            the edges
   * @param coolingFactor
   *            the cooling factor
   * @param useNumberOfSubnodes
   *            the use number of subnodes
   */
  @Override
  public void runLayout( float width, float height, Collection<DNVNode> nodes, Collection<DNVEdge> edges, float coolingFactor,
      boolean useNumberOfSubnodes )
  {
    runLayout( width, height, nodes, edges, coolingFactor, useNumberOfSubnodes, false, false );
  }

  /**
   * Run layout.
   *
   * @param width
   *            the width
   * @param height
   *            the height
   * @param nodes
   *            the nodes
   * @param edges
   *            the edges
   * @param coolingFactor
   *            the cooling factor
   * @param useNumberOfSubnodes
   *            the use number of subnodes
   * @param useEdgeRestingDistance
   *            the use edge resting distance
   * @param useNodeSize
   *            the use node size
   */
  @Override
  public void runLayout( float width, float height, Collection<DNVNode> nodes, Collection<DNVEdge> edges, float coolingFactor,
      boolean useNumberOfSubnodes, boolean useEdgeRestingDistance, boolean useNodeSize )
  {
    layoutLevel( width, height, nodes, edges, coolingFactor, useNumberOfSubnodes, useEdgeRestingDistance, useNodeSize );
  }

  /**
   * Layout level.
   *
   * @param width
   *            the width
   * @param height
   *            the height
   * @param nodes
   *            the nodes
   * @param edges
   *            the edges
   * @param coolingFactor
   *            the cooling factor
   * @param useNumberOfSubnodes
   *            the use number of subnodes
   * @param useEdgeRestingDistance
   *            the use edge resting distance
   * @param useNodeSize
   *            the use node size
   */
  public void setEnableWrite(boolean enableWrite){
    this.enableWrite = enableWrite;
  }
  private static void layoutLevel( float width, float height, Collection<DNVNode> nodes, Collection<DNVEdge> edges, float coolingFactor,
      boolean useNumberOfSubnodes, boolean useEdgeRestingDistance, boolean useNodeSize )
  {
    Timer timer = new Timer( Timer.MILLISECONDS );
    timer.setStart();
    float size = Math.max( GraphFunctions.getGraphWidth( nodes, false ), width );
    size = Math.max( size, Math.max( GraphFunctions.getGraphHeight( nodes, false ), height ) );
    float temperature = size / 10.0f;
    if( nodes.size() > 0 )
    {
      DNVGraph graph = nodes.iterator().next().getGraph();

      while( temperature > 0 )
      {
        synchronized( graph )
        {
          runIteration( width, height, nodes, edges, temperature, useNumberOfSubnodes, useEdgeRestingDistance, useNodeSize );
        }
        temperature = cool( temperature, coolingFactor );
        // System.out.println( "Temperature : " + temperature );
      }
    }
    timer.setEnd();
    if(writer != null && enableWrite){
      try{
        //writer.write(timer.getLastSegment( Timer.SECONDS ) + "\n");
        int n = nodes.size();
        int e = edges.size();
        double time = timer.getTimeSinceStart(Timer.SECONDS);;
        writer.write(time + "\t" + time/n + "\t" + time/e + "\t" + time/(n+e) + "\t" + time/(e/n) + "\n");
        //writer.write(LABEL + " finished in " + timer.getLastSegment( Timer.SECONDS ) + " seconds.\n");
      }catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }

  /** The Constant FRUCHTERMAN_REINGOLD_LAYOUT. */
  public static final String LABEL = "Fruchterman-Reingold";

  @Override
  public String getLabel()
  {
    return LABEL;
  }
  private static BufferedWriter writer;
  @Override
  public void setOutputWriter(BufferedWriter writer) {
    // TODO Auto-generated method stub
    this.writer = writer;
  }
}
TOP

Related Classes of net.wigis.graph.dnv.layout.implementations.FruchtermanReingold

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.