Author: pwang
Date: 2010-09-28 16:21:30 -0700 (Tue, 28 Sep 2010)
New Revision: 22096
Added:
core3/layout-cytoscape-impl/trunk/src/main/java/csplugins/layout/algorithms/bioLayout/BioLayoutFRAlgorithmTask.java
Modified:
core3/layout-cytoscape-impl/trunk/src/main/java/csplugins/layout/algorithms/bioLayout/BioLayoutFRAlgorithm.java
Log:
Refactored
Modified:
core3/layout-cytoscape-impl/trunk/src/main/java/csplugins/layout/algorithms/bioLayout/BioLayoutFRAlgorithm.java
===================================================================
---
core3/layout-cytoscape-impl/trunk/src/main/java/csplugins/layout/algorithms/bioLayout/BioLayoutFRAlgorithm.java
2010-09-28 22:19:41 UTC (rev 22095)
+++
core3/layout-cytoscape-impl/trunk/src/main/java/csplugins/layout/algorithms/bioLayout/BioLayoutFRAlgorithm.java
2010-09-28 23:21:30 UTC (rev 22096)
@@ -35,10 +35,13 @@
import java.awt.Dimension;
import java.util.ArrayList;
+import org.cytoscape.view.layout.AbstractLayout;
import org.cytoscape.view.layout.LayoutEdge;
import org.cytoscape.view.layout.LayoutNode;
import org.cytoscape.view.layout.LayoutPartition;
+import org.cytoscape.work.TaskIterator;
import org.cytoscape.work.Tunable;
+import org.cytoscape.work.TunableValidator;
import org.cytoscape.work.undo.UndoSupport;
/**
@@ -56,7 +59,7 @@
* @author <a href="mailto:[email protected]">Scooter Morris</a>
* @version 0.9
*/
-public class BioLayoutFRAlgorithm extends BioLayoutAlgorithm {
+public class BioLayoutFRAlgorithm extends AbstractLayout implements
TunableValidator {
/**
* Sets the number of iterations for each update
*/
@@ -69,13 +72,10 @@
*/
@Tunable(description="Divisor to calculate the attraction force",
groups="Algorithm settings")
public double attraction_multiplier = .03;
- private double attraction_constant;
@Tunable(description="Multiplier to calculate the repulsion force",
groups="Algorithm settings")
public double repulsion_multiplier = 0.04;
- private double repulsion_constant;
@Tunable(description="Multiplier to calculate the gravity force",
groups="Algorithm settings")
public double gravity_multiplier = 1;
- private double gravity_constant;
/**
* conflict_avoidance is a constant force that
@@ -93,22 +93,6 @@
public double max_distance_factor = 20;
/**
- * maxDistance is the actual calculated distance
- * beyond which repulsive forces will not operate.
- * This value takes into account max_distance_factor,
- * but also the size of the nodes in comparison to
- * the size of the graph.
- */
- private double maxDistance;
-
- /**
- * This limits the velocity to no more than 1/maxVelocity_divisor
- * of the width or height per iteration
- */
- private double maxVelocity_divisor = 25;
- private double maxVelocity;
-
- /**
* The spread factor -- used to give extra space to expand
*/
@Tunable(description="Amount of extra room for layout",
groups="Algorithm settings")
@@ -127,49 +111,33 @@
@Tunable(description="Number of iterations", groups="Algorithm
settings")
public int nIterations = 500;
+
+ boolean supportWeights = true;
+
/**
- * This ArrayList is used to calculate the slope of the magnitude
- * of the displacement. When the slope is (approximately) 0, we're
- * done.
- */
- private ArrayList<Double> displacementArray;
-
- /**
- * The partition we're laying out
- */
- private LayoutPartition partition;
-
- /**
- * The width and height of the layout
- */
- private double width = 0;
- private double height = 0;
-
- /**
- * Profile data -- not used, for now
- Profile initProfile;
- Profile iterProfile;
- Profile repulseProfile;
- Profile attractProfile;
- Profile updateProfile;
- */
-
- /**
* This is the constructor for the bioLayout algorithm.
*/
public BioLayoutFRAlgorithm(UndoSupport undoSupport, boolean
supportEdgeWeights) {
+
super(undoSupport);
supportWeights = supportEdgeWeights;
- displacementArray = new ArrayList<Double>(100);
}
+ public TaskIterator getTaskIterator() {
+ return new TaskIterator(new
BioLayoutFRAlgorithmTask(networkView, getName(), selectedOnly, staticNodes,
+
update_iterations,attraction_multiplier,repulsion_multiplier,
+
gravity_multiplier,conflict_avoidance,max_distance_factor,spread_factor,temperature,nIterations,
+ supportWeights));
+ }
+
+ // TODO
+ public boolean tunablesAreValid(final Appendable errMsg) {
+ return true;
+ }
+
/**
- * Required methods (and overrides) for AbstractLayout
- */
-
- /**
* Return the "name" of this algorithm. This is meant
* to be used by programs for deciding which algorithm to
* use. toString() should be used for the human-readable
@@ -195,705 +163,4 @@
return "Force directed (BioLayout)";
}
-
- /**
- * Sets the number of iterations
- *
- * @param value the number of iterations
- */
- public void setNumberOfIterations(int value) {
- this.nIterations = value;
- }
-
- /**
- * Sets the number of iterations
- *
- * @param value the number of iterations
- */
- public void setNumberOfIterations(String value) {
- Integer val = Integer.valueOf(value);
- nIterations = val.intValue();
- }
-
- /**
- * Sets the initial temperature
- *
- * @param value the initial temperature value
- */
- public void setTemperature(double value) {
- this.temperature = value;
- }
-
- /**
- * Sets the initial temperature
- *
- * @param value the initial temperature value
- */
- public void setTemperature(String value) {
- Double val = new Double(value);
- temperature = val.doubleValue();
- }
-
- /**
- * Sets the attraction multiplier used to calculate
- * the attraction force
- *
- * @param value the attraction multiplier
- */
- public void setAttractionMultiplier(double am) {
- attraction_multiplier = am;
- }
-
- /**
- * Sets the attraction multiplier used to calculate
- * the attraction force
- *
- * @param value the attraction multiplier
- */
- public void setAttractionMultiplier(String value) {
- Double val = new Double(value);
- attraction_multiplier = val.doubleValue();
- }
-
- /**
- * Sets the repulsion multiplier used to calculate
- * the repulsion force
- *
- * @param value the repulsion multiplier
- */
- public void setRepulsionMultiplier(double am) {
- repulsion_multiplier = am;
- }
-
- /**
- * Sets the repulsion multiplier used to calculate
- * the repulsion force
- *
- * @param value the repulsion multiplier
- */
- public void setRepulsionMultiplier(String value) {
- Double val = new Double(value);
- repulsion_multiplier = val.doubleValue();
- }
-
- /**
- * Sets the gravity multiplier used to calculate
- * the gravity force
- *
- * @param value the gravity multiplier
- */
- public void setGravityMultiplier(double am) {
- gravity_multiplier = am;
- }
-
- /**
- * Sets the gravity multiplier used to calculate
- * the gravity force
- *
- * @param value the gravity multiplier
- */
- public void setGravityMultiplier(String value) {
- Double val = new Double(value);
- gravity_multiplier = val.doubleValue();
- }
-
- /**
- * Sets the spread factor used to provide space for
- * the graph larger than the area of the nodes themselves.
- * The graph space will be (width*spread_factor, height*spread_factor)
- *
- * @param value the spread factor
- */
- public void setSpreadFactor(double value) {
- spread_factor = value;
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param value DOCUMENT ME!
- */
- public void setSpreadFactor(String value) {
- Double val = new Double(value);
- spread_factor = val.doubleValue();
- }
-
- /**
- * Sets the number of iterations to execute between each
- * screen update. If the value is 0 or -1, no updates
- * will be done until the algorithm completes.
- *
- * @param value the number of iterations between updates
- */
- public void setUpdateIterations(String value) {
- Integer val = Integer.valueOf(value);
- update_iterations = val.intValue();
- }
-
- /**
- * Sets the number of iterations to execute between each
- * screen update. If the value is 0 or -1, no updates
- * will be done until the algorithm completes.
- *
- * @param value the number of iterations between updates
- */
- public void setUpdateIterations(int value) {
- update_iterations = value;
- }
-
- /**
- * Sets an additional repulsive force to nodes
- * when they overlap
- *
- * @param value the additional repulsive force
- */
- public void setConflictAvoidanceForce(String value) {
- Double val = new Double(value);
- conflict_avoidance = val.doubleValue();
- }
-
- /**
- * Sets an additional repulsive force to nodes
- * when they overlap
- *
- * @param value the additional repulsive force
- */
- public void setConflictAvoidanceForce(double value) {
- conflict_avoidance = value;
- }
-
- /**
- * Sets the percentage of the graph beyond which we
- * don't calculate repulsive forces.
- *
- * @param value the maximum distance factor
- */
- public void setMaxDistanceFactor(String value) {
- Double val = new Double(value);
- max_distance_factor = val.doubleValue();
- }
-
- /**
- * Sets the percentage of the graph beyond which we
- * don't calculate repulsive forces.
- *
- * @param value the maximum distance factor
- */
- public void setMaxDistanceFactor(double value) {
- max_distance_factor = value;
- }
-
- /**
- * Perform a layout
- */
- public void layoutPartion(LayoutPartition partition) {
- this.partition = partition;
-
- Dimension initialLocation = null;
-
- /* Get all of our profiles */
- /*
- initProfile = new Profile();
- iterProfile = new Profile();
- repulseProfile = new Profile();
- attractProfile = new Profile();
- updateProfile = new Profile();
-
- initProfile.start();
- */
-
- // Calculate a bounded rectangle for our
- // layout. This is roughly the area of all
- // nodes * 2
- calculateSize();
-
- System.out.println("BioLayoutFR Algorithm. Laying out " +
partition.nodeCount()
- + " nodes and " + partition.edgeCount() + "
edges: ");
-
- // Initialize our temperature
- double temp;
-
- if (temperature == 0) {
- temp = Math.sqrt(this.width*this.height)/2;
- } else {
- temp = Math.sqrt(this.width*this.height) *
this.temperature/100;
- }
-
- // Figure out our starting point
- if (selectedOnly) {
- initialLocation = partition.getAverageLocation();
- }
-
- // Randomize our points, if any points lie
- // outside of our bounds
- if (randomize)
- partition.randomizeLocations();
-
- // Calculate our force constant
- calculateForces();
-
- // Calculate our edge weights
- partition.calculateEdgeWeights();
- // initProfile.done("Initialization completed in ");
- taskMonitor.setStatusMessage("Calculating new node positions");
- taskMonitor.setProgress(0.01);
-
- // Main algorithm
- // iterProfile.start();
- int iteration = 0;
-
- for (iteration = 0; (iteration < nIterations) && !canceled;
iteration++) {
- if ((temp = doOneIteration(iteration, temp)) == 0)
- break;
-
- if (debug || ((update_iterations > 0) && ((iteration %
update_iterations) == 0))) {
- if (iteration > 0) {
- // Actually move the pieces around
- for (LayoutNode v:
partition.getNodeList()) {
- // if this is locked, the move
just resets X and Y
- v.moveToLocation();
-
- }
- // This fires events to presentation
layer.
- networkView.updateView();
- }
-
- if (debug) {
- try {
-
Thread.currentThread().sleep(100);
- } catch (InterruptedException e) {
- }
- }
- }
-
- taskMonitor.setStatusMessage("Calculating new node
positions - " + iteration);
- taskMonitor.setProgress(iteration / nIterations);
- }
-
- // iterProfile.done("Iterations complete in ");
- // System.out.println("Attraction calculation portion of
iterations took "+attractProfile.getTotalTime()+"ms");
- // System.out.println("Repulsion calculation portion of
iterations took "+repulseProfile.getTotalTime()+"ms");
- // System.out.println("Update portion of iterations took
"+updateProfile.getTotalTime()+"ms");
- taskMonitor.setStatusMessage("Updating display");
-
- // Actually move the pieces around
- // Note that we reset our min/max values before we start this
- // so we can get an accurate min/max for paritioning
- partition.resetNodes();
-
- for (LayoutNode v: partition.getNodeList()) {
- partition.moveNodeToLocation(v);
- }
-
- // Not quite done, yet. If we're only laying out selected
nodes, we need
- // to migrate the selected nodes back to their starting position
- if (selectedOnly) {
- double xDelta = 0.0;
- double yDelta = 0.0;
- Dimension finalLocation =
partition.getAverageLocation();
- xDelta = finalLocation.getWidth() -
initialLocation.getWidth();
- yDelta = finalLocation.getHeight() -
initialLocation.getHeight();
-
- for (LayoutNode v: partition.getNodeList()) {
- if (!v.isLocked()) {
- v.decrement(xDelta, yDelta);
- partition.moveNodeToLocation(v);
- }
- }
- }
-
- System.out.println("Layout complete after " + iteration + "
iterations");
- }
-
- /**
- * This executes a single iteration of the FR algorithm.
- *
- * @param iteration The current interation.
- * @param temp The current temperature factor.
- * @return an updated temperature factor.
- */
- public double doOneIteration(int iteration, double temp) {
- double xAverage = 0;
- double yAverage = 0;
-
- // repulseProfile.start();
- // Calculate repulsive forces
- for (LayoutNode v: partition.getNodeList()) {
- if (!v.isLocked()) {
- xAverage += v.getX()/partition.nodeCount();
- yAverage += v.getY()/partition.nodeCount();
- }
- }
-
- for (LayoutNode v: partition.getNodeList()) {
- if (!v.isLocked()) {
- calculateRepulsion(v);
- if (gravity_constant != 0)
- calculateGravity(v,xAverage,yAverage);
- }
- }
-
- // repulseProfile.checkpoint();
-
- // Dump the current displacements
- // print_disp();
-
- // attractProfile.start();
- // Calculate attractive forces
-
-/// for e in E do begin
- for (LayoutEdge e: partition.getEdgeList()) {
- calculateAttraction(e);
- }
-/// end
-
- // attractProfile.checkpoint();
-
- // Dump the current displacements
- // print_disp();
-
- // Dampen & update
- double xDispTotal = 0;
- double yDispTotal = 0;
- // updateProfile.start();
-
-/// for v in V do begin
- for (LayoutNode v: partition.getNodeList()) {
- if (v.isLocked())
- continue;
-
- calculatePosition(v, temp);
-
- xDispTotal += Math.abs(v.getXDisp());
- yDispTotal += Math.abs(v.getYDisp());
- }
-/// end
-
- // Translate back to the middle (or to the starting point,
- // if we're dealing with a selected group
- if (!selectedOnly) {
- for (LayoutNode v: partition.getNodeList()) {
- v.decrement(xAverage - (width / 2), yAverage -
(height / 2));
- }
- }
-
- // updateProfile.checkpoint();
-
- // Test our total x and y displacement to see if we've
- // hit our completion criteria
- if (complete(xDispTotal, yDispTotal))
- return 0;
-
- // cool
-// t := cool(t)
- return cool(temp, iteration);
- }
-
- /**
- * calculate the slope of the total displacement over the last 10
iterations. If its positive or 0
- * we're done.
- *
- */
- private boolean complete(double xDisp, double yDisp) {
- Double disp = new Double(Math.sqrt((xDisp * xDisp) + (yDisp *
yDisp)));
-
- displacementArray.add(disp);
-
- Object[] dispArray = displacementArray.toArray();
-
- if (dispArray.length < 99)
- return false;
-
- double averageSlope = 0;
- double averageValue = ((Double) dispArray[0]).doubleValue() /
dispArray.length;
-
- for (int i = 1; i < dispArray.length; i++) {
- averageSlope += ((((Double) dispArray[i]).doubleValue()
- - ((Double) dispArray[i -
1]).doubleValue()) / dispArray.length);
- averageValue += (((Double) dispArray[i]).doubleValue()
/ dispArray.length);
- }
-
- // System.out.println("Total displacement =
"+disp.doubleValue()+" Average slope = "+averageSlope);
- // 5% a reasonable criteria?
- // if (Math.abs(averageSlope) < Math.abs(averageValue)*.001)
return true;
- if (Math.abs(averageSlope) < .001)
- return true;
-
- if (displacementArray.size() > 99)
- displacementArray.remove(0);
-
- return false;
- }
-
- /**
- * calculate the repulsive forces and offsets for
- * each vertex.
- *
- * @param v LayoutNode we're calculating repulsive forces for
- */
- private void calculateRepulsion(LayoutNode v) {
-/// v.disp := 0;
- v.setDisp(0, 0);
-
- double radius = v.getWidth() / 2;
-
-/// for u in V do
- for (LayoutNode u: partition.getNodeList()) {
- double dx = v.getX() - u.getX();
- double dy = v.getY() - u.getY();
-
-/// if (u # v) then begin
- if (v == u)
- continue;
-
- // Get the
- // double xSign = Math.signum(v.getX() - u.getX());
- // double ySign = Math.signum(v.getY() - u.getY());
-
-/// delta := v.pos - u.pos
- // Get our euclidean distance
- double deltaDistance = v.distance(u);
-
- if (deltaDistance == 0.0)
- deltaDistance = EPSILON;
-
- double fr = forceR(repulsion_constant, deltaDistance);
-
- // If its too close, increase the force by a constant
- if (deltaDistance < (radius + (u.getWidth() / 2))) {
- // System.out.println("Applying
conflict_avoidance force: "+conflict_avoidance);
- fr += conflict_avoidance;
- }
-
- if (Double.isNaN(fr)) {
- fr = 500;
- }
-
- /*
- System.out.println("Repulsive force between
"+v.getIdentifier()
- +" and
"+u.getIdentifier()+" is "+fr);
- System.out.println(" distance =
"+deltaDistance);
- System.out.println(" incrementing
"+v.getIdentifier()+" by ("+
- fr+", "+fr+")");
- */
-
- // Adjust the displacement. In the case of doing
selectedOnly,
- // we increase the force to enhance the discrimination
power.
- // Also note that we only update the displacement of
the movable
- // node since the other node won't move anyways.
-/// v.disp := v.disp + (delta/abs(delta)) * fr(abs(delta))
- double xVector = dx*fr/deltaDistance;
- double yVector = dy*fr/deltaDistance;
- if (v.isLocked()) {
- return; // shouldn't happen
- } else if (u.isLocked()) {
- v.incrementDisp(xVector * 2, yVector * 2);
- } else {
- v.incrementDisp(xVector, yVector);
- }
- }
- }
-
- /**
- * calculate the attractive forces and offsets for
- * each vertex based on their connecting edges and the
- * corresponding edge weights.
- *
- * @param e Edge we're calculating attractive forces for
- */
- private void calculateAttraction(LayoutEdge e) {
- LayoutNode v = e.getSource();
- LayoutNode u = e.getTarget();
- double dx = v.getX() - u.getX();
- double dy = v.getY() - u.getY();
-
-/// delta := e.v.pos - e.u.pos
- double deltaDistance = v.distance(u);
-
- double fa = forceA(attraction_constant, deltaDistance,
e.getWeight());
-
- if (Double.isNaN(fa)) {
- fa = EPSILON;
- }
-
- // Adjust the displacement. In the case of doing selectedOnly,
- // we increase the force to enhance the discrimination power.
- // Also note that we only update the displacement of the movable
- // node since the other node won't move anyways.
-
-/// e.v.disp := e.v.disp - (delta/abs(delta)) * fa(abs(delta))
-/// e.u.disp := e.u.disp + (delta/abs(delta)) * fa(abs(delta))
- double xVector = dx*fa;
- double yVector = dy*fa;
- if (u.isLocked() && v.isLocked()) {
- return; // shouldn't happen
- } else if (u.isLocked()) {
- v.decrementDisp(xVector * 2, yVector * 2);
- } else if (v.isLocked()) {
- u.incrementDisp(xVector * 2, yVector * 2);
- } else {
- v.decrementDisp(xVector, yVector);
- u.incrementDisp(xVector, yVector);
- }
- }
-
- /**
- * Calculate the gravity (pull towards the center) force.
- *
- * @param v the node we're pulling
- * @param xAverage the X portion of the location that's pulling us
- * @param yAverage the Y portion of the location that's pulling us
- */
- private void calculateGravity(LayoutNode v,double xAverage, double
yAverage)
- {
- double dx = v.getX() - xAverage;
- double dy = v.getY() - yAverage;
- double distance = Math.sqrt(Math.pow(dx,2) + Math.pow(dy,2));
- //double theta = Math.atan(dy/dx);
- //double xSign = Math.signum(dx);
- //double ySign = Math.signum(dy);
- if(distance == 0) distance = EPSILON;
- double phi = (1 +v.getDegree())/3;
- double force = gravity_constant*distance*phi;
- double xVector = dx*force;
- double yVector = dy*force;
- if (v.isLocked()) {
- return;
- }// shouldn't happen
-
- else {
- // System.out.println("Gravity adjustment =
"+xVector+", "+yVector);
- v.decrementDisp( xVector, yVector);
- }
- }
-
- /**
- * Calculate and update the position to move a vertex.
- * This routine also handles limiting the velocity and
- * doing the bounds checking to keep the vertices within
- * the graphics area.
- *
- * @param v LayoutNode we're moving
- * @param temp double representing the current temperature
- */
-/// v.pos := v.pos + (v.disp/|v.disp|) * min (v.disp, t);
- private void calculatePosition(LayoutNode v, double temp) {
- double deltaDistance = v.distance(v.getXDisp(), v.getYDisp());
-
- double newXDisp = v.getXDisp() / deltaDistance *
Math.min(deltaDistance, temp);
-
- if (Double.isNaN(newXDisp)) {
- newXDisp = 0;
- }
-
- double newYDisp = v.getYDisp() / deltaDistance *
Math.min(deltaDistance, temp);
-
- if (Double.isNaN(newYDisp)) {
- newYDisp = 0;
- }
- v.increment(newXDisp, newYDisp);
-
-/// v.pos.x := min(W/2, max(-W/2, v.pos.x));
-/// v.pos.y := min(L/2, max(-L/2, v.pos.y));
- }
-
- /**
- * Cools the current temperature
- *
- * @param temp the current temperature
- * @param iteration the iteration number
- * @return the new temperature
- */
- private double cool(double temp, int iteration) {
- temp *= (1.0 - ((double)iteration / (double)nIterations));
-
- return temp;
- }
-
- /**
- * Calculate the width and height of the new graph. If the graph
already has been laid
- * out, then the width and height should be resonable, so use those.
Otherwise, calculate
- * a width and height based on the area covered by the existing graph.
- */
- private void calculateSize() {
- // double spreadFactor = Math.max(spread_factor,
edgeList.length/nodeList.length);
- // LayoutNode v0 = (LayoutNode)nodeList.get(0); // Get the
first vertex to get to the class variables
- double spreadFactor = spread_factor;
- double averageWidth = partition.getWidth() /
partition.nodeCount();
- double averageHeight = partition.getHeight() /
partition.nodeCount();
- double current_area = (partition.getMaxX() -
partition.getMinX()) * (partition.getMaxY()
-
- partition.getMinY());
- double node_area = partition.getWidth() * partition.getHeight();
-
- if (selectedOnly || (current_area > node_area)) {
- this.width = (partition.getMaxX() -
partition.getMinX()) * spreadFactor;
- this.height = (partition.getMaxY() -
partition.getMinY()) * spreadFactor;
- // make it square
- this.width = Math.max(this.width, this.height);
- this.height = this.width;
- } else {
- this.width = Math.sqrt(node_area) * spreadFactor;
- this.height = Math.sqrt(node_area) * spreadFactor;
-
- // System.out.println("spreadFactor = "+spreadFactor);
- }
-
- this.maxVelocity = Math.max(Math.max(averageWidth * 2,
averageHeight * 2),
- Math.max(width, height) /
maxVelocity_divisor);
- this.maxDistance = Math.max(Math.max(averageWidth * 10,
averageHeight * 10),
- Math.min(width, height) *
max_distance_factor / 100);
-
- System.out.println("Size: "+width+" x "+height);
- System.out.println("maxDistance = "+maxDistance);
- System.out.println("maxVelocity = "+maxVelocity);
- /*
- */
- }
-
- /**
- * Calculate the attraction and repulsion constants.
- */
- private void calculateForces() {
- double force = Math.sqrt((this.height * this.width) /
partition.nodeCount());
- attraction_constant = force * attraction_multiplier;
- repulsion_constant = force * repulsion_multiplier;
- gravity_constant = gravity_multiplier;
-
-/*
- System.out.println("attraction_constant =
"+attraction_constant
- +", repulsion_constant =
"+repulsion_constant
- +",
gravity_constant = "+gravity_constant);
-*/
- }
-
- /**
- * Calculate the repulsive force
- *
- * @param k the repulsion constant
- * @param distance the distance between the vertices
- * @return the repulsive force
- */
-/// fr(z) := begin return k*k/z end;
- private double forceR(double k, double distance) {
- // We want to bound the distance over which
- // the repulsive force acts
- // Should we do this??
- if (distance > maxDistance)
- return 0;
-
- return ((k * k) / distance);
- }
-
- /**
- * Calculate the attractive force
- *
- * @param k the attraction constant
- * @param distance the distance between the vertices
- * @param weight the edge weight
- * @return the attractive force
- */
-/// fa(z) := begin return z*z/k end;
- private double forceA(double k, double distance, double weight) {
- return ((distance / k) * weight);
- }
}
Added:
core3/layout-cytoscape-impl/trunk/src/main/java/csplugins/layout/algorithms/bioLayout/BioLayoutFRAlgorithmTask.java
===================================================================
---
core3/layout-cytoscape-impl/trunk/src/main/java/csplugins/layout/algorithms/bioLayout/BioLayoutFRAlgorithmTask.java
(rev 0)
+++
core3/layout-cytoscape-impl/trunk/src/main/java/csplugins/layout/algorithms/bioLayout/BioLayoutFRAlgorithmTask.java
2010-09-28 23:21:30 UTC (rev 22096)
@@ -0,0 +1,872 @@
+package csplugins.layout.algorithms.bioLayout;
+
+import java.awt.Dimension;
+import java.util.ArrayList;
+import java.util.Set;
+
+import org.cytoscape.model.CyNode;
+import org.cytoscape.view.layout.LayoutEdge;
+import org.cytoscape.view.layout.LayoutNode;
+import org.cytoscape.view.layout.LayoutPartition;
+import org.cytoscape.view.model.CyNetworkView;
+import org.cytoscape.view.model.View;
+import org.cytoscape.work.Tunable;
+
+public class BioLayoutFRAlgorithmTask extends BioLayoutAlgorithm {
+
+ /**
+ * Sets the number of iterations for each update
+ */
+ //@Tunable(description="Number of iterations before updating display
(0: update only at end)", groups="Algorithm settings")
+ public int update_iterations;// = 0; // 0 means we only update at the
end
+
+ /**
+ * The multipliers and computed result for the
+ * attraction and repulsion values.
+ */
+ //@Tunable(description="Divisor to calculate the attraction force",
groups="Algorithm settings")
+ public double attraction_multiplier;// = .03;
+ private double attraction_constant;
+ //@Tunable(description="Multiplier to calculate the repulsion force",
groups="Algorithm settings")
+ public double repulsion_multiplier;// = 0.04;
+ private double repulsion_constant;
+ //@Tunable(description="Multiplier to calculate the gravity force",
groups="Algorithm settings")
+ public double gravity_multiplier;// = 1;
+ private double gravity_constant;
+
+ /**
+ * conflict_avoidance is a constant force that
+ * gets applied when two vertices are very close
+ * to each other.
+ */
+ //@Tunable(description="Constant force applied to avoid conflicts",
groups="Algorithm settings")
+ public double conflict_avoidance;// = 20;
+
+ /**
+ * max_distance_factor is the portion of the graph
+ * beyond which repulsive forces will not operate.
+ */
+ //@Tunable(description="Percent of graph used for node repulsion
calculations", groups="Algorithm settings")
+ public double max_distance_factor;// = 20;
+
+ /**
+ * maxDistance is the actual calculated distance
+ * beyond which repulsive forces will not operate.
+ * This value takes into account max_distance_factor,
+ * but also the size of the nodes in comparison to
+ * the size of the graph.
+ */
+ private double maxDistance;
+
+ /**
+ * This limits the velocity to no more than 1/maxVelocity_divisor
+ * of the width or height per iteration
+ */
+ private double maxVelocity_divisor = 25;
+ private double maxVelocity;
+
+ /**
+ * The spread factor -- used to give extra space to expand
+ */
+ //@Tunable(description="Amount of extra room for layout",
groups="Algorithm settings")
+ public double spread_factor;// = 2;
+
+ /**
+ * The initial temperature factor. This will get damped
+ * out through the iterations
+ */
+ //@Tunable(description="Initial temperature", groups="Algorithm
settings")
+ public double temperature;// = 80;
+
+ /**
+ * The number of iterations to run.
+ */
+ //@Tunable(description="Number of iterations", groups="Algorithm
settings")
+ public int nIterations;// = 500;
+
+ /**
+ * This ArrayList is used to calculate the slope of the magnitude
+ * of the displacement. When the slope is (approximately) 0, we're
+ * done.
+ */
+ private ArrayList<Double> displacementArray;
+
+ /**
+ * The partition we're laying out
+ */
+ private LayoutPartition partition;
+
+ /**
+ * The width and height of the layout
+ */
+ private double width = 0;
+ private double height = 0;
+
+ /**
+ * Profile data -- not used, for now
+ Profile initProfile;
+ Profile iterProfile;
+ Profile repulseProfile;
+ Profile attractProfile;
+ Profile updateProfile;
+ */
+
+ public BioLayoutFRAlgorithmTask(final CyNetworkView networkView, final
String name, final boolean selectedOnly,
+ final Set<View<CyNode>> staticNodes,
+ int update_iterations, final double
attraction_multiplier,final double repulsion_multiplier,
+ final double gravity_multiplier,final double
conflict_avoidance, final double max_distance_factor,
+ final double spread_factor,final double
temperature,final int nIterations,
+ final boolean supportWeights)
+ {
+ super(networkView, name, selectedOnly, staticNodes);
+
+ this.update_iterations =update_iterations;
+ this.attraction_multiplier =attraction_multiplier;
+ this.repulsion_multiplier=repulsion_multiplier;
+ this.gravity_multiplier=gravity_multiplier;
+ this.conflict_avoidance=conflict_avoidance;
+ this.max_distance_factor=max_distance_factor;
+ this.spread_factor=spread_factor;
+ this.temperature=temperature;
+ this.nIterations=nIterations;
+ this.supportWeights =supportWeights;
+
+ displacementArray = new ArrayList<Double>(100);
+
+ }
+
+
+
+ /**
+ * Required methods (and overrides) for AbstractLayout
+ */
+
+ /**
+ * Return the "name" of this algorithm. This is meant
+ * to be used by programs for deciding which algorithm to
+ * use. toString() should be used for the human-readable
+ * name.
+ *
+ * @return the algorithm name
+ */
+ public String getName() {
+ return "fruchterman-rheingold";
+ }
+
+ /**
+ * Return the "title" of this algorithm. This is meant
+ * to be used for titles and labels that represent this
+ * algorithm.
+ *
+ * @return the human-readable algorithm name
+ */
+ public String toString() {
+ if (supportWeights)
+ return "Edge-weighted Force directed (BioLayout)";
+ else
+
+ return "Force directed (BioLayout)";
+ }
+
+ /**
+ * Sets the number of iterations
+ *
+ * @param value the number of iterations
+ */
+ public void setNumberOfIterations(int value) {
+ this.nIterations = value;
+ }
+
+ /**
+ * Sets the number of iterations
+ *
+ * @param value the number of iterations
+ */
+ public void setNumberOfIterations(String value) {
+ Integer val = Integer.valueOf(value);
+ nIterations = val.intValue();
+ }
+
+ /**
+ * Sets the initial temperature
+ *
+ * @param value the initial temperature value
+ */
+ public void setTemperature(double value) {
+ this.temperature = value;
+ }
+
+ /**
+ * Sets the initial temperature
+ *
+ * @param value the initial temperature value
+ */
+ public void setTemperature(String value) {
+ Double val = new Double(value);
+ temperature = val.doubleValue();
+ }
+
+ /**
+ * Sets the attraction multiplier used to calculate
+ * the attraction force
+ *
+ * @param value the attraction multiplier
+ */
+ public void setAttractionMultiplier(double am) {
+ attraction_multiplier = am;
+ }
+
+ /**
+ * Sets the attraction multiplier used to calculate
+ * the attraction force
+ *
+ * @param value the attraction multiplier
+ */
+ public void setAttractionMultiplier(String value) {
+ Double val = new Double(value);
+ attraction_multiplier = val.doubleValue();
+ }
+
+ /**
+ * Sets the repulsion multiplier used to calculate
+ * the repulsion force
+ *
+ * @param value the repulsion multiplier
+ */
+ public void setRepulsionMultiplier(double am) {
+ repulsion_multiplier = am;
+ }
+
+ /**
+ * Sets the repulsion multiplier used to calculate
+ * the repulsion force
+ *
+ * @param value the repulsion multiplier
+ */
+ public void setRepulsionMultiplier(String value) {
+ Double val = new Double(value);
+ repulsion_multiplier = val.doubleValue();
+ }
+
+ /**
+ * Sets the gravity multiplier used to calculate
+ * the gravity force
+ *
+ * @param value the gravity multiplier
+ */
+ public void setGravityMultiplier(double am) {
+ gravity_multiplier = am;
+ }
+
+ /**
+ * Sets the gravity multiplier used to calculate
+ * the gravity force
+ *
+ * @param value the gravity multiplier
+ */
+ public void setGravityMultiplier(String value) {
+ Double val = new Double(value);
+ gravity_multiplier = val.doubleValue();
+ }
+
+ /**
+ * Sets the spread factor used to provide space for
+ * the graph larger than the area of the nodes themselves.
+ * The graph space will be (width*spread_factor, height*spread_factor)
+ *
+ * @param value the spread factor
+ */
+ public void setSpreadFactor(double value) {
+ spread_factor = value;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param value DOCUMENT ME!
+ */
+ public void setSpreadFactor(String value) {
+ Double val = new Double(value);
+ spread_factor = val.doubleValue();
+ }
+
+ /**
+ * Sets the number of iterations to execute between each
+ * screen update. If the value is 0 or -1, no updates
+ * will be done until the algorithm completes.
+ *
+ * @param value the number of iterations between updates
+ */
+ public void setUpdateIterations(String value) {
+ Integer val = Integer.valueOf(value);
+ update_iterations = val.intValue();
+ }
+
+ /**
+ * Sets the number of iterations to execute between each
+ * screen update. If the value is 0 or -1, no updates
+ * will be done until the algorithm completes.
+ *
+ * @param value the number of iterations between updates
+ */
+ public void setUpdateIterations(int value) {
+ update_iterations = value;
+ }
+
+ /**
+ * Sets an additional repulsive force to nodes
+ * when they overlap
+ *
+ * @param value the additional repulsive force
+ */
+ public void setConflictAvoidanceForce(String value) {
+ Double val = new Double(value);
+ conflict_avoidance = val.doubleValue();
+ }
+
+ /**
+ * Sets an additional repulsive force to nodes
+ * when they overlap
+ *
+ * @param value the additional repulsive force
+ */
+ public void setConflictAvoidanceForce(double value) {
+ conflict_avoidance = value;
+ }
+
+ /**
+ * Sets the percentage of the graph beyond which we
+ * don't calculate repulsive forces.
+ *
+ * @param value the maximum distance factor
+ */
+ public void setMaxDistanceFactor(String value) {
+ Double val = new Double(value);
+ max_distance_factor = val.doubleValue();
+ }
+
+ /**
+ * Sets the percentage of the graph beyond which we
+ * don't calculate repulsive forces.
+ *
+ * @param value the maximum distance factor
+ */
+ public void setMaxDistanceFactor(double value) {
+ max_distance_factor = value;
+ }
+
+ /**
+ * Perform a layout
+ */
+ public void layoutPartion(LayoutPartition partition) {
+ this.partition = partition;
+
+ Dimension initialLocation = null;
+
+ /* Get all of our profiles */
+ /*
+ initProfile = new Profile();
+ iterProfile = new Profile();
+ repulseProfile = new Profile();
+ attractProfile = new Profile();
+ updateProfile = new Profile();
+
+ initProfile.start();
+ */
+
+ // Calculate a bounded rectangle for our
+ // layout. This is roughly the area of all
+ // nodes * 2
+ calculateSize();
+
+ System.out.println("BioLayoutFR Algorithm. Laying out " +
partition.nodeCount()
+ + " nodes and " + partition.edgeCount() + "
edges: ");
+
+ // Initialize our temperature
+ double temp;
+
+ if (temperature == 0) {
+ temp = Math.sqrt(this.width*this.height)/2;
+ } else {
+ temp = Math.sqrt(this.width*this.height) *
this.temperature/100;
+ }
+
+ // Figure out our starting point
+ if (selectedOnly) {
+ initialLocation = partition.getAverageLocation();
+ }
+
+ // Randomize our points, if any points lie
+ // outside of our bounds
+ if (randomize)
+ partition.randomizeLocations();
+
+ // Calculate our force constant
+ calculateForces();
+
+ // Calculate our edge weights
+ partition.calculateEdgeWeights();
+ // initProfile.done("Initialization completed in ");
+ taskMonitor.setStatusMessage("Calculating new node positions");
+ taskMonitor.setProgress(0.01);
+
+ // Main algorithm
+ // iterProfile.start();
+ int iteration = 0;
+
+ for (iteration = 0; (iteration < nIterations) && !cancelled;
iteration++) {
+ if ((temp = doOneIteration(iteration, temp)) == 0)
+ break;
+
+ if (debug || ((update_iterations > 0) && ((iteration %
update_iterations) == 0))) {
+ if (iteration > 0) {
+ // Actually move the pieces around
+ for (LayoutNode v:
partition.getNodeList()) {
+ // if this is locked, the move
just resets X and Y
+ v.moveToLocation();
+
+ }
+ // This fires events to presentation
layer.
+ networkView.updateView();
+ }
+
+ if (debug) {
+ try {
+
Thread.currentThread().sleep(100);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ taskMonitor.setStatusMessage("Calculating new node
positions - " + iteration);
+ taskMonitor.setProgress(iteration / nIterations);
+ }
+
+ // iterProfile.done("Iterations complete in ");
+ // System.out.println("Attraction calculation portion of
iterations took "+attractProfile.getTotalTime()+"ms");
+ // System.out.println("Repulsion calculation portion of
iterations took "+repulseProfile.getTotalTime()+"ms");
+ // System.out.println("Update portion of iterations took
"+updateProfile.getTotalTime()+"ms");
+ taskMonitor.setStatusMessage("Updating display");
+
+ // Actually move the pieces around
+ // Note that we reset our min/max values before we start this
+ // so we can get an accurate min/max for paritioning
+ partition.resetNodes();
+
+ for (LayoutNode v: partition.getNodeList()) {
+ partition.moveNodeToLocation(v);
+ }
+
+ // Not quite done, yet. If we're only laying out selected
nodes, we need
+ // to migrate the selected nodes back to their starting position
+ if (selectedOnly) {
+ double xDelta = 0.0;
+ double yDelta = 0.0;
+ Dimension finalLocation =
partition.getAverageLocation();
+ xDelta = finalLocation.getWidth() -
initialLocation.getWidth();
+ yDelta = finalLocation.getHeight() -
initialLocation.getHeight();
+
+ for (LayoutNode v: partition.getNodeList()) {
+ if (!v.isLocked()) {
+ v.decrement(xDelta, yDelta);
+ partition.moveNodeToLocation(v);
+ }
+ }
+ }
+
+ System.out.println("Layout complete after " + iteration + "
iterations");
+ }
+
+ /**
+ * This executes a single iteration of the FR algorithm.
+ *
+ * @param iteration The current interation.
+ * @param temp The current temperature factor.
+ * @return an updated temperature factor.
+ */
+ public double doOneIteration(int iteration, double temp) {
+ double xAverage = 0;
+ double yAverage = 0;
+
+ // repulseProfile.start();
+ // Calculate repulsive forces
+ for (LayoutNode v: partition.getNodeList()) {
+ if (!v.isLocked()) {
+ xAverage += v.getX()/partition.nodeCount();
+ yAverage += v.getY()/partition.nodeCount();
+ }
+ }
+
+ for (LayoutNode v: partition.getNodeList()) {
+ if (!v.isLocked()) {
+ calculateRepulsion(v);
+ if (gravity_constant != 0)
+ calculateGravity(v,xAverage,yAverage);
+ }
+ }
+
+ // repulseProfile.checkpoint();
+
+ // Dump the current displacements
+ // print_disp();
+
+ // attractProfile.start();
+ // Calculate attractive forces
+
+/// for e in E do begin
+ for (LayoutEdge e: partition.getEdgeList()) {
+ calculateAttraction(e);
+ }
+/// end
+
+ // attractProfile.checkpoint();
+
+ // Dump the current displacements
+ // print_disp();
+
+ // Dampen & update
+ double xDispTotal = 0;
+ double yDispTotal = 0;
+ // updateProfile.start();
+
+/// for v in V do begin
+ for (LayoutNode v: partition.getNodeList()) {
+ if (v.isLocked())
+ continue;
+
+ calculatePosition(v, temp);
+
+ xDispTotal += Math.abs(v.getXDisp());
+ yDispTotal += Math.abs(v.getYDisp());
+ }
+/// end
+
+ // Translate back to the middle (or to the starting point,
+ // if we're dealing with a selected group
+ if (!selectedOnly) {
+ for (LayoutNode v: partition.getNodeList()) {
+ v.decrement(xAverage - (width / 2), yAverage -
(height / 2));
+ }
+ }
+
+ // updateProfile.checkpoint();
+
+ // Test our total x and y displacement to see if we've
+ // hit our completion criteria
+ if (complete(xDispTotal, yDispTotal))
+ return 0;
+
+ // cool
+// t := cool(t)
+ return cool(temp, iteration);
+ }
+
+ /**
+ * calculate the slope of the total displacement over the last 10
iterations. If its positive or 0
+ * we're done.
+ *
+ */
+ private boolean complete(double xDisp, double yDisp) {
+ Double disp = new Double(Math.sqrt((xDisp * xDisp) + (yDisp *
yDisp)));
+
+ displacementArray.add(disp);
+
+ Object[] dispArray = displacementArray.toArray();
+
+ if (dispArray.length < 99)
+ return false;
+
+ double averageSlope = 0;
+ double averageValue = ((Double) dispArray[0]).doubleValue() /
dispArray.length;
+
+ for (int i = 1; i < dispArray.length; i++) {
+ averageSlope += ((((Double) dispArray[i]).doubleValue()
+ - ((Double) dispArray[i -
1]).doubleValue()) / dispArray.length);
+ averageValue += (((Double) dispArray[i]).doubleValue()
/ dispArray.length);
+ }
+
+ // System.out.println("Total displacement =
"+disp.doubleValue()+" Average slope = "+averageSlope);
+ // 5% a reasonable criteria?
+ // if (Math.abs(averageSlope) < Math.abs(averageValue)*.001)
return true;
+ if (Math.abs(averageSlope) < .001)
+ return true;
+
+ if (displacementArray.size() > 99)
+ displacementArray.remove(0);
+
+ return false;
+ }
+
+ /**
+ * calculate the repulsive forces and offsets for
+ * each vertex.
+ *
+ * @param v LayoutNode we're calculating repulsive forces for
+ */
+ private void calculateRepulsion(LayoutNode v) {
+/// v.disp := 0;
+ v.setDisp(0, 0);
+
+ double radius = v.getWidth() / 2;
+
+/// for u in V do
+ for (LayoutNode u: partition.getNodeList()) {
+ double dx = v.getX() - u.getX();
+ double dy = v.getY() - u.getY();
+
+/// if (u # v) then begin
+ if (v == u)
+ continue;
+
+ // Get the
+ // double xSign = Math.signum(v.getX() - u.getX());
+ // double ySign = Math.signum(v.getY() - u.getY());
+
+/// delta := v.pos - u.pos
+ // Get our euclidean distance
+ double deltaDistance = v.distance(u);
+
+ if (deltaDistance == 0.0)
+ deltaDistance = EPSILON;
+
+ double fr = forceR(repulsion_constant, deltaDistance);
+
+ // If its too close, increase the force by a constant
+ if (deltaDistance < (radius + (u.getWidth() / 2))) {
+ // System.out.println("Applying
conflict_avoidance force: "+conflict_avoidance);
+ fr += conflict_avoidance;
+ }
+
+ if (Double.isNaN(fr)) {
+ fr = 500;
+ }
+
+ /*
+ System.out.println("Repulsive force between
"+v.getIdentifier()
+ +" and
"+u.getIdentifier()+" is "+fr);
+ System.out.println(" distance =
"+deltaDistance);
+ System.out.println(" incrementing
"+v.getIdentifier()+" by ("+
+ fr+", "+fr+")");
+ */
+
+ // Adjust the displacement. In the case of doing
selectedOnly,
+ // we increase the force to enhance the discrimination
power.
+ // Also note that we only update the displacement of
the movable
+ // node since the other node won't move anyways.
+/// v.disp := v.disp + (delta/abs(delta)) * fr(abs(delta))
+ double xVector = dx*fr/deltaDistance;
+ double yVector = dy*fr/deltaDistance;
+ if (v.isLocked()) {
+ return; // shouldn't happen
+ } else if (u.isLocked()) {
+ v.incrementDisp(xVector * 2, yVector * 2);
+ } else {
+ v.incrementDisp(xVector, yVector);
+ }
+ }
+ }
+
+ /**
+ * calculate the attractive forces and offsets for
+ * each vertex based on their connecting edges and the
+ * corresponding edge weights.
+ *
+ * @param e Edge we're calculating attractive forces for
+ */
+ private void calculateAttraction(LayoutEdge e) {
+ LayoutNode v = e.getSource();
+ LayoutNode u = e.getTarget();
+ double dx = v.getX() - u.getX();
+ double dy = v.getY() - u.getY();
+
+/// delta := e.v.pos - e.u.pos
+ double deltaDistance = v.distance(u);
+
+ double fa = forceA(attraction_constant, deltaDistance,
e.getWeight());
+
+ if (Double.isNaN(fa)) {
+ fa = EPSILON;
+ }
+
+ // Adjust the displacement. In the case of doing selectedOnly,
+ // we increase the force to enhance the discrimination power.
+ // Also note that we only update the displacement of the movable
+ // node since the other node won't move anyways.
+
+/// e.v.disp := e.v.disp - (delta/abs(delta)) * fa(abs(delta))
+/// e.u.disp := e.u.disp + (delta/abs(delta)) * fa(abs(delta))
+ double xVector = dx*fa;
+ double yVector = dy*fa;
+ if (u.isLocked() && v.isLocked()) {
+ return; // shouldn't happen
+ } else if (u.isLocked()) {
+ v.decrementDisp(xVector * 2, yVector * 2);
+ } else if (v.isLocked()) {
+ u.incrementDisp(xVector * 2, yVector * 2);
+ } else {
+ v.decrementDisp(xVector, yVector);
+ u.incrementDisp(xVector, yVector);
+ }
+ }
+
+ /**
+ * Calculate the gravity (pull towards the center) force.
+ *
+ * @param v the node we're pulling
+ * @param xAverage the X portion of the location that's pulling us
+ * @param yAverage the Y portion of the location that's pulling us
+ */
+ private void calculateGravity(LayoutNode v,double xAverage, double
yAverage)
+ {
+ double dx = v.getX() - xAverage;
+ double dy = v.getY() - yAverage;
+ double distance = Math.sqrt(Math.pow(dx,2) + Math.pow(dy,2));
+ //double theta = Math.atan(dy/dx);
+ //double xSign = Math.signum(dx);
+ //double ySign = Math.signum(dy);
+ if(distance == 0) distance = EPSILON;
+ double phi = (1 +v.getDegree())/3;
+ double force = gravity_constant*distance*phi;
+ double xVector = dx*force;
+ double yVector = dy*force;
+ if (v.isLocked()) {
+ return;
+ }// shouldn't happen
+
+ else {
+ // System.out.println("Gravity adjustment =
"+xVector+", "+yVector);
+ v.decrementDisp( xVector, yVector);
+ }
+ }
+
+ /**
+ * Calculate and update the position to move a vertex.
+ * This routine also handles limiting the velocity and
+ * doing the bounds checking to keep the vertices within
+ * the graphics area.
+ *
+ * @param v LayoutNode we're moving
+ * @param temp double representing the current temperature
+ */
+/// v.pos := v.pos + (v.disp/|v.disp|) * min (v.disp, t);
+ private void calculatePosition(LayoutNode v, double temp) {
+ double deltaDistance = v.distance(v.getXDisp(), v.getYDisp());
+
+ double newXDisp = v.getXDisp() / deltaDistance *
Math.min(deltaDistance, temp);
+
+ if (Double.isNaN(newXDisp)) {
+ newXDisp = 0;
+ }
+
+ double newYDisp = v.getYDisp() / deltaDistance *
Math.min(deltaDistance, temp);
+
+ if (Double.isNaN(newYDisp)) {
+ newYDisp = 0;
+ }
+ v.increment(newXDisp, newYDisp);
+
+/// v.pos.x := min(W/2, max(-W/2, v.pos.x));
+/// v.pos.y := min(L/2, max(-L/2, v.pos.y));
+ }
+
+ /**
+ * Cools the current temperature
+ *
+ * @param temp the current temperature
+ * @param iteration the iteration number
+ * @return the new temperature
+ */
+ private double cool(double temp, int iteration) {
+ temp *= (1.0 - ((double)iteration / (double)nIterations));
+
+ return temp;
+ }
+
+ /**
+ * Calculate the width and height of the new graph. If the graph
already has been laid
+ * out, then the width and height should be resonable, so use those.
Otherwise, calculate
+ * a width and height based on the area covered by the existing graph.
+ */
+ private void calculateSize() {
+ // double spreadFactor = Math.max(spread_factor,
edgeList.length/nodeList.length);
+ // LayoutNode v0 = (LayoutNode)nodeList.get(0); // Get the
first vertex to get to the class variables
+ double spreadFactor = spread_factor;
+ double averageWidth = partition.getWidth() /
partition.nodeCount();
+ double averageHeight = partition.getHeight() /
partition.nodeCount();
+ double current_area = (partition.getMaxX() -
partition.getMinX()) * (partition.getMaxY()
+
- partition.getMinY());
+ double node_area = partition.getWidth() * partition.getHeight();
+
+ if (selectedOnly || (current_area > node_area)) {
+ this.width = (partition.getMaxX() -
partition.getMinX()) * spreadFactor;
+ this.height = (partition.getMaxY() -
partition.getMinY()) * spreadFactor;
+ // make it square
+ this.width = Math.max(this.width, this.height);
+ this.height = this.width;
+ } else {
+ this.width = Math.sqrt(node_area) * spreadFactor;
+ this.height = Math.sqrt(node_area) * spreadFactor;
+
+ // System.out.println("spreadFactor = "+spreadFactor);
+ }
+
+ this.maxVelocity = Math.max(Math.max(averageWidth * 2,
averageHeight * 2),
+ Math.max(width, height) /
maxVelocity_divisor);
+ this.maxDistance = Math.max(Math.max(averageWidth * 10,
averageHeight * 10),
+ Math.min(width, height) *
max_distance_factor / 100);
+
+ System.out.println("Size: "+width+" x "+height);
+ System.out.println("maxDistance = "+maxDistance);
+ System.out.println("maxVelocity = "+maxVelocity);
+ /*
+ */
+ }
+
+ /**
+ * Calculate the attraction and repulsion constants.
+ */
+ private void calculateForces() {
+ double force = Math.sqrt((this.height * this.width) /
partition.nodeCount());
+ attraction_constant = force * attraction_multiplier;
+ repulsion_constant = force * repulsion_multiplier;
+ gravity_constant = gravity_multiplier;
+
+/*
+ System.out.println("attraction_constant =
"+attraction_constant
+ +", repulsion_constant =
"+repulsion_constant
+ +",
gravity_constant = "+gravity_constant);
+*/
+ }
+
+ /**
+ * Calculate the repulsive force
+ *
+ * @param k the repulsion constant
+ * @param distance the distance between the vertices
+ * @return the repulsive force
+ */
+/// fr(z) := begin return k*k/z end;
+ private double forceR(double k, double distance) {
+ // We want to bound the distance over which
+ // the repulsive force acts
+ // Should we do this??
+ if (distance > maxDistance)
+ return 0;
+
+ return ((k * k) / distance);
+ }
+
+ /**
+ * Calculate the attractive force
+ *
+ * @param k the attraction constant
+ * @param distance the distance between the vertices
+ * @param weight the edge weight
+ * @return the attractive force
+ */
+/// fa(z) := begin return z*z/k end;
+ private double forceA(double k, double distance, double weight) {
+ return ((distance / k) * weight);
+ }
+
+}
--
You received this message because you are subscribed to the Google Groups
"cytoscape-cvs" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/cytoscape-cvs?hl=en.