Author: mes
Date: 2012-04-03 11:48:47 -0700 (Tue, 03 Apr 2012)
New Revision: 28725

Added:
   core3/impl/trunk/edge-bundler-impl/
   core3/impl/trunk/edge-bundler-impl/pom.xml
   core3/impl/trunk/edge-bundler-impl/src/
   core3/impl/trunk/edge-bundler-impl/src/main/
   core3/impl/trunk/edge-bundler-impl/src/main/java/
   core3/impl/trunk/edge-bundler-impl/src/main/java/org/
   core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/
   core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/
   core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/
   
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/
   
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/CyActivator.java
   
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/EdgeBundlerRunner.java
   
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/EdgeBundlerTask.java
   
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/EdgeBundlerTaskFactory.java
Modified:
   core3/impl/trunk/pom.xml
Log:
added edge bundler

Added: core3/impl/trunk/edge-bundler-impl/pom.xml
===================================================================
--- core3/impl/trunk/edge-bundler-impl/pom.xml                          (rev 0)
+++ core3/impl/trunk/edge-bundler-impl/pom.xml  2012-04-03 18:48:47 UTC (rev 
28725)
@@ -0,0 +1,90 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+       <modelVersion>4.0.0</modelVersion>
+
+       <parent>
+               <artifactId>impl-parent</artifactId>
+               <groupId>org.cytoscape</groupId>
+               <version>3.0.0-alpha8-SNAPSHOT</version>
+       </parent>
+
+       <properties>
+               <bundle.symbolicName>edge-bundler</bundle.symbolicName>
+               
<bundle.namespace>org.cytoscape.edge.bundler.internal</bundle.namespace>
+       </properties>
+
+       <artifactId>edge-bundler-impl</artifactId>
+       <name>${bundle.symbolicName}</name>
+       <packaging>bundle</packaging>
+
+  
+       <repositories>
+               <repository>
+                       <id>cytoscape_snapshots</id>
+                       <snapshots>
+                               <enabled>true</enabled>
+                       </snapshots>
+                       <releases>
+                               <enabled>false</enabled>
+                       </releases>
+                       <name>Cytoscape Snapshots</name>
+                       
<url>http://code.cytoscape.org/nexus/content/repositories/snapshots/</url>
+               </repository>
+               <repository>
+                       <id>cytoscape_releases</id>
+                       <snapshots>
+                               <enabled>false</enabled>
+                       </snapshots>
+                       <releases>
+                               <enabled>true</enabled>
+                       </releases>
+                       <name>Cytoscape Releases</name>
+                       
<url>http://code.cytoscape.org/nexus/content/repositories/releases/</url>
+               </repository>
+       </repositories>
+
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.felix</groupId>
+                               <artifactId>maven-bundle-plugin</artifactId>
+                               
<version>${maven-bundle-plugin.version}</version>
+                               <extensions>true</extensions>
+                               <configuration>
+                                       <instructions>
+                                               
<Bundle-SymbolicName>${bundle.symbolicName}</Bundle-SymbolicName>
+                                               
<Bundle-Version>${project.version}</Bundle-Version>
+                                               
<Export-Package>!${bundle.namespace}.*</Export-Package>
+                                               
<Private-Package>${bundle.namespace}.*</Private-Package>
+                                               
<Bundle-Activator>${bundle.namespace}.CyActivator</Bundle-Activator>
+                                       </instructions>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
+  
+  
+       <dependencies>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>presentation-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>application-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>work-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>core-task-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>service-api</artifactId>
+               </dependency>
+    </dependencies>
+  
+       <description>Written by Gregory Hannum, March 2012</description>
+</project>

Added: 
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/CyActivator.java
===================================================================
--- 
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/CyActivator.java
                               (rev 0)
+++ 
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/CyActivator.java
       2012-04-03 18:48:47 UTC (rev 28725)
@@ -0,0 +1,49 @@
+package org.cytoscape.edge.bundler.internal;
+
+import org.cytoscape.task.NetworkViewTaskFactory;
+import org.cytoscape.view.vizmap.VisualMappingFunctionFactory;
+import org.cytoscape.view.vizmap.VisualMappingManager;
+import org.cytoscape.view.presentation.property.values.HandleFactory;
+import org.cytoscape.view.presentation.property.values.BendFactory;
+import org.cytoscape.service.util.AbstractCyActivator;
+import java.util.Properties;
+import org.osgi.framework.BundleContext;
+
+
+public class CyActivator extends AbstractCyActivator {
+       public CyActivator() {
+               super();
+       }
+
+       public void start(BundleContext bc) {
+
+               HandleFactory hf = getService(bc, HandleFactory.class);
+               BendFactory bf = getService(bc, BendFactory.class);
+               VisualMappingManager vmm = getService(bc, 
VisualMappingManager.class);
+               VisualMappingFunctionFactory discreteFactory = 
getService(bc,VisualMappingFunctionFactory.class,"(mapping.type=discrete)");
+               
+               EdgeBundlerTaskFactory edgeBundlerTaskFactory = new 
EdgeBundlerTaskFactory(hf, bf, vmm, discreteFactory, 0);
+               Properties edgeBundlerTaskFactoryProps = new Properties();
+               
edgeBundlerTaskFactoryProps.setProperty("preferredMenu","Layout.Bundle Edges");
+               edgeBundlerTaskFactoryProps.setProperty("menuGravity","11.0");
+               edgeBundlerTaskFactoryProps.setProperty("title","All Nodes and 
Edges");
+               
registerService(bc,edgeBundlerTaskFactory,NetworkViewTaskFactory.class, 
edgeBundlerTaskFactoryProps);
+               
+               
+               edgeBundlerTaskFactory = new EdgeBundlerTaskFactory(hf, bf, 
vmm, discreteFactory, 1);
+               edgeBundlerTaskFactoryProps = new Properties();
+               
edgeBundlerTaskFactoryProps.setProperty("preferredMenu","Layout.Bundle Edges");
+               edgeBundlerTaskFactoryProps.setProperty("menuGravity","12.0");
+               edgeBundlerTaskFactoryProps.setProperty("title","Selected Nodes 
Only");
+               
registerService(bc,edgeBundlerTaskFactory,NetworkViewTaskFactory.class, 
edgeBundlerTaskFactoryProps);
+               
+               
+               edgeBundlerTaskFactory = new EdgeBundlerTaskFactory(hf, bf, 
vmm, discreteFactory, 2);
+               edgeBundlerTaskFactoryProps = new Properties();
+               
edgeBundlerTaskFactoryProps.setProperty("preferredMenu","Layout.Bundle Edges");
+               edgeBundlerTaskFactoryProps.setProperty("menuGravity","13.0");
+               edgeBundlerTaskFactoryProps.setProperty("title","Selected Edges 
Only");
+               
registerService(bc,edgeBundlerTaskFactory,NetworkViewTaskFactory.class, 
edgeBundlerTaskFactoryProps);
+       }
+}
+

Added: 
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/EdgeBundlerRunner.java
===================================================================
--- 
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/EdgeBundlerRunner.java
                         (rev 0)
+++ 
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/EdgeBundlerRunner.java
 2012-04-03 18:48:47 UTC (rev 28725)
@@ -0,0 +1,52 @@
+package org.cytoscape.edge.bundler.internal;
+
+public class EdgeBundlerRunner implements Runnable{
+
+       private final int ni;
+       private final int numNubs;
+       private final boolean[][] edgeAlign;
+       private final double[][][] nubs;
+       private final double[][][] forces;
+       private final double[][] edgeCompatability;
+       private final int[][] edgeMatcher;
+       
+       public EdgeBundlerRunner(int ni, int numNubs, boolean[][] edgeAlign, 
double[][][] nubs, double[][][] forces, double[][] edgeCompatability, int[][] 
edgeMatcher)
+       {
+               this.ni = ni;
+               this.numNubs = numNubs;
+               this.edgeAlign = edgeAlign;
+               this.nubs = nubs;
+               this.forces = forces;
+               this.edgeCompatability = edgeCompatability;
+               this.edgeMatcher = edgeMatcher;
+       }
+       
+       public void run()
+       {
+               for (int ei=0;ei<edgeAlign.length;ei++)
+                       for (int em=0;em<edgeMatcher[ei].length;em++) 
+                       {
+                               int ej = edgeMatcher[ei][em];
+                               
+                               int nj = (edgeAlign[ei][ej]) ? ni : 
numNubs-ni-1;
+                               
+                               double diffx = 
(nubs[ni][0][ei]-nubs[nj][0][ej]);
+                               double diffy = 
(nubs[ni][1][ei]-nubs[nj][1][ej]);
+                               
+                               if (Math.abs(diffx) > 1)
+                               {
+                                       double fx = edgeCompatability[ei][ej] / 
diffx;
+                                       
+                                       forces[ni][0][ei] -= fx;
+                                       forces[nj][0][ej] += fx;
+                               }
+                               
+                               if (Math.abs(diffy) > 1)
+                               {
+                                       double fy = edgeCompatability[ei][ej] / 
diffy;
+                                       forces[ni][1][ei] -= fy;
+                                       forces[nj][1][ej] += fy;
+                               }
+                       }
+       }
+}

Added: 
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/EdgeBundlerTask.java
===================================================================
--- 
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/EdgeBundlerTask.java
                           (rev 0)
+++ 
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/EdgeBundlerTask.java
   2012-04-03 18:48:47 UTC (rev 28725)
@@ -0,0 +1,530 @@
+//Written by Gregory Hannum
+//May 2012
+//Based on Holten and Wijk. Force-directed edge bundling for graph 
visualization. Eurographics/IEEE-VGTC Symposium on Visualization. 2009
+
+package org.cytoscape.edge.bundler.internal;
+
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import org.cytoscape.model.CyEdge;
+import org.cytoscape.model.CyNode;
+import org.cytoscape.model.CyTable;
+import org.cytoscape.task.AbstractNetworkViewTask;
+import org.cytoscape.view.model.CyNetworkView;
+import org.cytoscape.view.model.View;
+import static org.cytoscape.view.presentation.property.BasicVisualLexicon.*;
+import org.cytoscape.view.vizmap.VisualMappingFunctionFactory;
+import org.cytoscape.view.vizmap.VisualMappingManager;
+import org.cytoscape.view.vizmap.mappings.DiscreteMapping;
+import org.cytoscape.work.TaskMonitor;
+import org.cytoscape.work.Tunable;
+import org.cytoscape.view.presentation.property.values.Bend;
+import org.cytoscape.view.presentation.property.values.BendFactory;
+import org.cytoscape.view.presentation.property.values.Handle;
+import org.cytoscape.view.presentation.property.values.HandleFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EdgeBundlerTask extends AbstractNetworkViewTask {
+
+       private static final Logger logger = 
LoggerFactory.getLogger(EdgeBundlerTask.class);
+
+       @Tunable(description="Number of handles")
+       public int numNubs = 3;
+               
+       @Tunable(description="Spring constant")
+       public double K = 3e-3;
+       
+       @Tunable(description="Compatability threshold")
+       public double COMPATABILITY_THRESHOLD = 0.3;
+       
+       @Tunable(description="Maximum iterations")
+       public int maxIterations = 10000;
+       //private double networkScale;
+       
+       private boolean animate = false;
+       
+       private double[][][] edgePos; //source/target, X/Y, edgeIndex
+       private double[][][] nubs;    //nubLocation, X/Y, edgeIndex
+       private double[][] edgeCompatability;
+       private boolean[][] edgeAlign;
+       private double[] edgeLength;
+       private int[][] edgeMatcher;
+               
+       private HandleFactory hf;
+       private BendFactory bf;
+       private VisualMappingManager vmm;
+       private VisualMappingFunctionFactory discreteFactory;
+       
+       private int numEdges;
+       
+       private int selection;
+       
+       EdgeBundlerTask(CyNetworkView v, HandleFactory hf, BendFactory bf, 
VisualMappingManager vmm, VisualMappingFunctionFactory discreteFactory, int 
selection) {
+               super(v);
+               
+               this.hf = hf;
+               this.bf = bf;
+               this.vmm = vmm;
+               this.discreteFactory = discreteFactory;
+               this.selection = selection;
+       }
+
+       public void run(TaskMonitor tm) {
+               
+               
+               //Check tunables
+               if (numNubs<1) numNubs = 1;
+               if (numNubs>50)
+               {
+                       logger.warn("Maximum handles is 50.");
+                       numNubs = 50;
+               }
+               
+               tm.setTitle("Edge Bundle Layout");
+               
+               //Pre-cache data structures
+               tm.setStatusMessage("Caching network data");
+               Collection<View<CyEdge>> edges = null;
+               
+               //Get selection
+               if (selection==0) //Use all edges
+               {
+                       edges = this.view.getEdgeViews();
+               }
+               else if (selection==1) //Use selected nodes only
+               {
+                       Collection<View<CyEdge>> edgeView = 
this.view.getEdgeViews();
+                       
+                       edges = new ArrayList<View<CyEdge>>(edgeView.size());
+                       
+                       for (View<CyEdge> e : edgeView)
+                       {
+                               boolean n1 = 
view.getNodeView(e.getModel().getSource()).getVisualProperty(EDGE_SELECTED);
+                               boolean n2 = 
view.getNodeView(e.getModel().getTarget()).getVisualProperty(EDGE_SELECTED);
+                               if (n1 && n2) edges.add(e);
+                       }
+                       
+               }else if (selection==2) //Use selected edges only
+               {
+                       Collection<View<CyEdge>> edgeView = 
this.view.getEdgeViews();
+                       
+                       edges = new ArrayList<View<CyEdge>>(edgeView.size());
+                       
+                       for (View<CyEdge> e : edgeView)
+                               if (e.getVisualProperty(EDGE_SELECTED)) 
edges.add(e);
+               }
+               
+               int ei = 0;
+               for (View<CyEdge> e : edges)
+               {
+                       View<CyNode> eSource = 
view.getNodeView(e.getModel().getSource());
+                       View<CyNode> eTarget = 
view.getNodeView(e.getModel().getTarget());
+                       
+                       if (eSource.getSUID().equals(eTarget.getSUID())) 
continue;
+                       
+                       ei++;
+               }
+               
+               numEdges = ei;
+               
+               if (numEdges<2)
+               {
+                       logger.warn("Less than two edges found.");
+                       return;
+               }
+               
+               edgePos = new double[2][2][numEdges];
+               nubs = new double[numNubs][2][numEdges];                
+               edgeLength = new double[numEdges];
+               
+               ei = 0;
+               for (View<CyEdge> e : edges)
+               {
+                       //System.out.println("SUID: "+e.getModel().getSUID());
+                       
+                       View<CyNode> eSource = 
view.getNodeView(e.getModel().getSource());
+                       View<CyNode> eTarget = 
view.getNodeView(e.getModel().getTarget());
+                       
+                       if (eSource.getSUID().equals(eTarget.getSUID())) 
continue;
+                       
+                       edgePos[0][0][ei] = 
eSource.getVisualProperty(NODE_X_LOCATION);
+                       edgePos[0][1][ei] = 
eSource.getVisualProperty(NODE_Y_LOCATION);
+                       edgePos[1][0][ei] = 
eTarget.getVisualProperty(NODE_X_LOCATION);
+                       edgePos[1][1][ei] = 
eTarget.getVisualProperty(NODE_Y_LOCATION);
+                       
+                       //if (edgePos[0][0][ei]>edgePos[1][0][ei]) {double temp 
= edgePos[0][0][ei]; edgePos[0][0][ei] = edgePos[1][0][ei]; edgePos[1][0][ei] = 
temp;}
+                       //if (edgePos[0][1][ei]>edgePos[1][1][ei]) {double temp 
= edgePos[0][1][ei]; edgePos[0][1][ei] = edgePos[1][1][ei]; edgePos[1][1][ei] = 
temp;}
+                       
+                       double diffx = edgePos[1][0][ei] - edgePos[0][0][ei];
+                       double diffy = edgePos[1][1][ei] - edgePos[0][1][ei];
+                                               
+                       for (int ni=0;ni<numNubs;ni++)
+                       {
+                               nubs[ni][0][ei] = (diffx) * (ni + 1) / (numNubs 
+ 1) + edgePos[0][0][ei];
+                               nubs[ni][1][ei] = (diffy) * (ni + 1) / (numNubs 
+ 1) + edgePos[0][1][ei];
+                       }
+                       
+                       edgeLength[ei] = Math.sqrt(diffx*diffx + diffy*diffy);
+                       
+                       ei++;
+               }
+               
+                               
+               //networkScale = computeNetworkScale();
+               computeEdgeCompatability();
+               
+               //Simulating physics
+               tm.setStatusMessage("Simulating physics");
+               double time = System.nanoTime();
+               double[][][] forces = new double[numNubs][2][numEdges]; //Nub, 
X/Y, edgeIndex
+               for (int iteri=0;iteri<maxIterations;iteri++)
+               {
+                       if (this.cancelled)
+                       {
+                               //reset();
+                               logger.info("Edge bundling cancelled: 
iter="+iteri);
+                               break;
+                       }
+                       
+                       tm.setProgress(iteri/Double.valueOf(maxIterations));
+                       
+                       updateForces(forces);
+                       updateNubs(forces);
+                       
+                       //Check convergence once in awhile
+                       if (iteri%1000==0 && isConverged(forces,.01))
+                       {
+                               logger.info("Edge bundling converged: 
iter="+iteri);
+                               break;
+                       }
+                       
+                       if (iteri==maxIterations-1)
+                       {
+                               logger.info("Edge bundling did not converge: 
iter="+iteri);
+                               break;
+                       }
+                       
+                       if (animate && System.nanoTime()-time>3)
+                       {
+                               render(edges);
+                               time = System.nanoTime();
+                       }
+               }
+               
+               render(edges);
+               
+               
+//             double minX = 0;
+//             double maxX = 0;
+//             double minY = 0;
+//             double maxY = 0;
+//             
+//             
+//             for (ei=0;ei<edgeLength.length;ei++)
+//                     for (int ni=0;ni<numNubs;ni++)
+//                     {
+//                             double x = nubs[ni][0][ei];
+//                             double y = nubs[ni][1][ei];
+//                             
+//                             if (x<minX) minX = x;
+//                             if (x>maxX) maxX = x;
+//                             if (y<minY) minY = y;
+//                             if (y>maxY) maxY = y;
+//                             
+//                             if (Double.isInfinite(x) || 
Double.isInfinite(y) || Double.isNaN(x) || Double.isNaN(y))
+//                                     System.out.println("Infinite or NaN 
positions detected!");
+//                     }
+//             
+//             System.out.println(minX+":"+maxX+",  "+minY+":"+maxY);
+       }
+       
+       private double computeNetworkScale()
+       {
+               double centerX = 0;
+               double centerY = 0;
+               
+               for (int ei=0;ei<edgeLength.length;ei++)
+               {
+                       centerX += edgePos[0][0][ei] + edgePos[1][0][ei];
+                       centerY += edgePos[0][1][ei] + edgePos[1][1][ei];
+               }
+               
+               centerX /= 2.0*edgeLength.length;
+               centerY /= 2.0*edgeLength.length;
+               
+               double[] dist = new double[2*edgeLength.length];
+                               
+               for (int ei=0;ei<edgeLength.length;ei++)
+               {
+                       double diff0x = edgePos[0][0][ei] - centerX;
+                       double diff0y = edgePos[0][1][ei] - centerY;
+                       double diff1x = edgePos[1][0][ei] - centerX;
+                       double diff1y = edgePos[1][1][ei] - centerY;
+                       
+                       dist[2*ei] = Math.sqrt(diff0x*diff0x + diff0y*diff0y);
+                       dist[2*ei+1] = Math.sqrt(diff1x*diff1x + diff1y*diff1y);
+               }
+               
+               Arrays.sort(dist);
+               double scale = dist[dist.length/2];
+               
+               return scale;
+       }
+       
+       private boolean isConverged(double[][][] forces, double threshold)
+       {
+               for (int ei=0;ei<edgeLength.length;ei++)
+                       for (int ni=0;ni<numNubs;ni++)
+                               if (Math.abs(forces[ni][0][ei])>threshold || 
Math.abs(forces[ni][1][ei])>threshold) 
+                               {
+                                       //System.out.println(forces[ni][0][ei] 
+ ", "+ forces[ni][1][ei]);
+                                       return false;
+                               }
+               
+               return true;
+       }
+
+       private void render(Collection<View<CyEdge>> edges)
+       {
+               DiscreteMapping<Long, Bend> function = 
(DiscreteMapping<Long,Bend>) 
discreteFactory.createVisualMappingFunction(CyTable.SUID, Long.class, null, 
EDGE_BEND);
+               
+               int ei = 0;
+               for (View<CyEdge> e : edges)
+               {
+                       View<CyNode> eSource = 
view.getNodeView(e.getModel().getSource());
+                       View<CyNode> eTarget = 
view.getNodeView(e.getModel().getTarget());
+                       
+                       if (eSource.getSUID().equals(eTarget.getSUID())) 
continue;
+                       
+                       Bend b = bf.createBend();
+                       List<Handle> hlist = b.getAllHandles();
+                       
+                       for (int ni=0;ni<numNubs;ni++)
+                       {
+                               double x = nubs[ni][0][ei];
+                               double y = nubs[ni][1][ei];
+
+                               Handle h = hf.createHandle(0, 0);
+                               h.defineHandle(view,e, x, y);
+                               hlist.add(h);
+                       }
+                       
+                       function.putMapValue(e.getModel().getSUID(), b);
+                       ei++;
+               }
+               
+               vmm.getVisualStyle(view).addVisualMappingFunction(function);
+                                                               
+               vmm.getVisualStyle(view).apply(view);
+               view.updateView();
+       }
+       
+       private void computeEdgeCompatability()
+       {
+               edgeCompatability = new double[edgeLength.length][];
+               edgeAlign = new boolean[edgeLength.length][];
+               edgeMatcher = new int[edgeLength.length][];
+               
+               edgeMatcher[0] = new int[0];
+               
+               for (int ei=1;ei<edgeLength.length;ei++)
+               {
+                       edgeCompatability[ei] = new double[ei];
+                       edgeAlign[ei] = new boolean[ei];
+
+                       List<Integer> compatibleEdges = new 
ArrayList<Integer>(1000);
+                       for (int ej=0;ej<ei;ej++)
+                       {
+                               edgeCompatability[ei][ej] = cangle(ei,ej) * 
cscale(ei, ej) * cpos(ei, ej) * cvis(ei, ej);
+                               edgeAlign[ei][ej] = cangleSign(ei,ej)>0;
+                               
+                               if 
(edgeCompatability[ei][ej]>COMPATABILITY_THRESHOLD) compatibleEdges.add(ej);
+                       }
+                       
+                       edgeMatcher[ei] = new int[compatibleEdges.size()];
+                       for (int i=0;i<compatibleEdges.size();i++)
+                               edgeMatcher[ei][i] = compatibleEdges.get(i);
+               }
+       }
+       
+       private double cangle(int ei, int ej)
+       {
+               double a = edgePos[1][0][ei] - edgePos[0][0][ei];
+               double b = edgePos[1][1][ei] - edgePos[0][1][ei];
+               double c = edgePos[1][0][ej] - edgePos[0][0][ej];
+               double d = edgePos[1][1][ej] - edgePos[0][1][ej];
+               
+               double cosAlpha = ((a*c) + 
(b*d))/(edgeLength[ei]*edgeLength[ej]);
+
+               double out = Math.abs(cosAlpha); 
+               
+               if (Double.isNaN(out) || Double.isInfinite(out)) return 0;
+               return out;
+       }
+       
+       private double cangleSign(int ei, int ej)
+       {
+               double a = edgePos[1][0][ei] - edgePos[0][0][ei];
+               double b = edgePos[1][1][ei] - edgePos[0][1][ei];
+               double c = edgePos[1][0][ej] - edgePos[0][0][ej];
+               double d = edgePos[1][1][ej] - edgePos[0][1][ej];
+               
+               double cosAlpha = ((a*c) + 
(b*d))/(edgeLength[ei]*edgeLength[ej]);
+
+               double out = Math.signum(cosAlpha); 
+               
+               if (Double.isNaN(out) || Double.isInfinite(out)) return 0;
+               return out;
+       }
+       
+       private double cscale(int ei, int ej)
+       {
+               double lavg = (edgeLength[ei] + edgeLength[ej])/2.0;
+               
+               //Note: the formula in the paper is wrong (*min vs. /min)
+               double out = 
2.0/((lavg/Math.min(edgeLength[ei],edgeLength[ej])) + 
(Math.max(edgeLength[ei],edgeLength[ej])/lavg)); 
+               
+               if (Double.isNaN(out) || Double.isInfinite(out)) return 0;
+               return out;
+       }
+       
+       private double cpos(int ei, int ej)
+       {
+               double lavg = (edgeLength[ei] + edgeLength[ej])/2.0;
+
+               double out = lavg / (lavg + distance(mid(ei),mid(ej)) ); 
+               
+               if (Double.isNaN(out) || Double.isInfinite(out)) return 0;
+               
+               return out; 
+       }
+       
+       private double[] mid(int ei) {
+               return new 
double[]{(edgePos[1][0][ei]+edgePos[0][0][ei])/2.0,(edgePos[1][1][ei]+edgePos[0][1][ei])/2.0};
+       }
+
+       private double distance(double[] p, double[] q) {
+               double x = p[0] - q[0];
+               double y = p[1] - q[1];
+               return Math.sqrt(x*x + y*y);
+       }
+       
+       private double cvis(int ei, int ej)
+       {
+               return Math.min(vis(ei,ej), vis(ej,ei));
+       }
+
+       private double vis(int ei, int ej)
+       {
+               double[] I0 = getProjection(ei,ej,new 
double[]{edgePos[0][0][ei],edgePos[0][1][ei]});
+               if (I0==null) return 0;
+               
+               double[] I1 = getProjection(ei,ej,new 
double[]{edgePos[1][0][ei],edgePos[1][1][ei]});
+               if (I1==null) return 0;
+               
+               double[] Im = new double[]{(I1[0]-I0[0])/2 + I0[0], 
(I1[1]-I0[1])/2 + I0[1]};
+               
+               double[] Pm = mid(ej);
+               
+               double a = distance(Pm, Im);
+               double b = distance(I0,I1);
+               return Math.max(1.0 - 2*a/b, 0); 
+       }
+       
+       private double[] getProjection(int ei, int ej, double[] m)
+       {
+               double dx1 = edgePos[1][0][ei] - edgePos[0][0][ei]; 
+               double dy1 = edgePos[1][1][ei] - edgePos[0][1][ei];
+               
+               double dx2 = edgePos[1][0][ej] - edgePos[0][0][ej]; 
+               double dy2 = edgePos[1][1][ej] - edgePos[0][1][ej];
+               
+               double cx = edgePos[0][0][ej];
+               double cy = edgePos[0][1][ej];
+                               
+               //INTERSECTION
+               //double A1 = dy1;
+               //double B1 = -dx1;
+               //double A2 = dy2;
+               //double B2 = -dx2;
+               
+               //PROJECTION
+               double A1 = dx1;
+               double B1 = dy1;
+               double A2 = dy2;
+               double B2 = -dx2;
+               
+               double C1 = A1*m[0]+B1*m[1];
+               double C2 = A2*cx+B2*cy;
+               
+               double det = A1*B2 - A2*B1;
+               if (Math.abs(det)<1e-10) return null;
+               
+               double x = (B2*C1-B1*C2)/det;
+               double y = (A1*C2-A2*C1)/det;
+               
+               return new double[]{x,y};
+       }
+
+       
+       private void updateForces(double[][][] forces)
+       {
+               //Spring forces
+               for (int ei=0;ei<edgeLength.length;ei++)
+                       for (int ni=0;ni<numNubs;ni++)
+                       {
+                               if (ni==0)
+                               {
+                                       forces[ni][0][ei] = nubs[ni][0][ei] - 
edgePos[0][0][ei];
+                                       forces[ni][1][ei] = nubs[ni][1][ei] - 
edgePos[0][1][ei];
+                               }else
+                               {
+                                       forces[ni][0][ei] = nubs[ni][0][ei] - 
nubs[ni-1][0][ei];
+                                       forces[ni][1][ei] = nubs[ni][1][ei] - 
nubs[ni-1][1][ei];
+                               }
+                               
+                               if (ni==numNubs-1)
+                               {
+                                       forces[ni][0][ei] += nubs[ni][0][ei] - 
edgePos[1][0][ei];
+                                       forces[ni][1][ei] += nubs[ni][1][ei] - 
edgePos[1][1][ei];
+                               }else
+                               {
+                                       forces[ni][0][ei] += nubs[ni][0][ei] - 
nubs[ni+1][0][ei];
+                                       forces[ni][1][ei] += nubs[ni][1][ei] - 
nubs[ni+1][1][ei];
+                               }
+                               
+                               forces[ni][0][ei] *= -K;
+                               forces[ni][1][ei] *= -K;
+                               
+                       }
+               
+               //Electrostatic forces
+               ExecutorService exec = 
Executors.newFixedThreadPool(Math.min(numNubs,Runtime.getRuntime().availableProcessors()));
+               
+               for (int ni=0;ni<numNubs;ni++)
+                       exec.execute(new EdgeBundlerRunner(ni, numNubs, 
edgeAlign, nubs, forces, edgeCompatability, edgeMatcher));
+                       
+               exec.shutdown();
+               
+               try {exec.awaitTermination(30, TimeUnit.DAYS);}
+               catch (InterruptedException e) 
{e.printStackTrace();exec.shutdownNow();}
+       }
+       
+       private void updateNubs(double[][][] forces)
+       {
+               for (int ei=0;ei<edgeLength.length;ei++)
+                       for (int ni=0;ni<numNubs;ni++)
+                       {
+                               nubs[ni][0][ei] += forces[ni][0][ei];
+                               nubs[ni][1][ei] += forces[ni][1][ei];
+                               
+                               //nubs[ni][0][ei] += 
Math.signum(forces[ni][0][ei]) * Math.min(Math.abs(forces[ni][0][ei]) * 
stepsize, networkScale * 1e-2);
+                               //nubs[ni][1][ei] += 
Math.signum(forces[ni][1][ei]) * Math.min(Math.abs(forces[ni][1][ei]) * 
stepsize, networkScale * 1e-2);
+                       }
+       }
+}

Added: 
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/EdgeBundlerTaskFactory.java
===================================================================
--- 
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/EdgeBundlerTaskFactory.java
                            (rev 0)
+++ 
core3/impl/trunk/edge-bundler-impl/src/main/java/org/cytoscape/edge/bundler/internal/EdgeBundlerTaskFactory.java
    2012-04-03 18:48:47 UTC (rev 28725)
@@ -0,0 +1,33 @@
+package org.cytoscape.edge.bundler.internal;
+
+import org.cytoscape.view.presentation.property.values.BendFactory;
+import org.cytoscape.view.presentation.property.values.HandleFactory;
+import org.cytoscape.model.CyNetwork;
+import org.cytoscape.task.AbstractNetworkViewTaskFactory;
+import org.cytoscape.view.model.CyNetworkView;
+import org.cytoscape.view.vizmap.VisualMappingFunctionFactory;
+import org.cytoscape.view.vizmap.VisualMappingManager;
+import org.cytoscape.work.TaskIterator;
+
+
+public class EdgeBundlerTaskFactory extends AbstractNetworkViewTaskFactory {
+
+       private HandleFactory hf;
+       private BendFactory bf;
+       private VisualMappingManager vmm;
+       private VisualMappingFunctionFactory discreteFactory;
+       private int selection;
+       
+       public EdgeBundlerTaskFactory(HandleFactory hf, BendFactory bf, 
VisualMappingManager vmm, VisualMappingFunctionFactory discreteFactory, int 
selection) {
+               super();
+               this.hf = hf;
+               this.bf = bf;
+               this.vmm = vmm;
+               this.discreteFactory = discreteFactory;
+               this.selection = selection;
+       }
+       
+       public TaskIterator createTaskIterator(CyNetworkView view) {
+               return new TaskIterator(new EdgeBundlerTask(view, hf, bf, vmm, 
discreteFactory, selection));
+       }
+}

Modified: core3/impl/trunk/pom.xml
===================================================================
--- core3/impl/trunk/pom.xml    2012-04-03 18:40:39 UTC (rev 28724)
+++ core3/impl/trunk/pom.xml    2012-04-03 18:48:47 UTC (rev 28725)
@@ -65,7 +65,8 @@
                <module>datasource-biogrid-impl</module>
                <module>welcome-impl</module>
                <module>gui-cmdline-parser-impl</module>
-    <module>scripting-impl</module>
+               <module>edge-bundler-impl</module>
+               <module>scripting-impl</module>
   </modules>
 
        <properties>

-- 
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.

Reply via email to