Author: paperwing
Date: 2012-03-28 17:08:29 -0700 (Wed, 28 Mar 2012)
New Revision: 28687

Added:
   
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutAlgorithm.java
   
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutAlgorithmTask.java
   
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutContext.java
   
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/tools/LayoutToolkit.java
Modified:
   
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/CyActivator.java
   
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/cytoscape/view/WindNetworkView.java
   
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/geometric/Vector3.java
   
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/SphericalLayoutAlgorithmTask.java
Log:
#refs 812 Added new layout algorithm to arrange nodes as a hollow, cubic box, 
added to menu under "Layouts > 3D Layouts". Spherical layout also available.

Modified: 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/CyActivator.java
===================================================================
--- 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/CyActivator.java
      2012-03-28 22:45:59 UTC (rev 28686)
+++ 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/CyActivator.java
      2012-03-29 00:08:29 UTC (rev 28687)
@@ -3,6 +3,7 @@
 import java.util.Properties;
 
 import org.cytoscape.paperwing.internal.cytoscape.view.WindNetworkViewFactory;
+import org.cytoscape.paperwing.internal.layouts.GridLayoutAlgorithm;
 import org.cytoscape.paperwing.internal.layouts.SphericalLayoutAlgorithm;
 import org.cytoscape.paperwing.internal.task.TaskFactoryListener;
 import org.cytoscape.service.util.AbstractCyActivator;
@@ -107,7 +108,14 @@
                
sphericalLayoutAlgorithmProps.setProperty("preferredTaskManager","menu");
                
sphericalLayoutAlgorithmProps.setProperty("title",sphericalLayoutAlgorithm.toString());
                sphericalLayoutAlgorithmProps.setProperty("menuGravity","10.5");
+               registerService(bc, sphericalLayoutAlgorithm, 
CyLayoutAlgorithm.class, sphericalLayoutAlgorithmProps);
                
-               registerService(bc,sphericalLayoutAlgorithm, 
CyLayoutAlgorithm.class, sphericalLayoutAlgorithmProps);
+               GridLayoutAlgorithm gridLayoutAlgorithm = new 
GridLayoutAlgorithm();
+               Properties gridLayoutAlgorithmProps = new Properties();
+               gridLayoutAlgorithmProps.setProperty("preferredMenu","Layout.3D 
Layouts");
+               
gridLayoutAlgorithmProps.setProperty("preferredTaskManager","menu");
+               gridLayoutAlgorithmProps.setProperty("title", 
gridLayoutAlgorithm.toString());
+               gridLayoutAlgorithmProps.setProperty("menuGravity","10.49");
+               registerService(bc, gridLayoutAlgorithm, 
CyLayoutAlgorithm.class, gridLayoutAlgorithmProps);
        }
 }

Modified: 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/cytoscape/view/WindNetworkView.java
===================================================================
--- 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/cytoscape/view/WindNetworkView.java
   2012-03-28 22:45:59 UTC (rev 28686)
+++ 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/cytoscape/view/WindNetworkView.java
   2012-03-29 00:08:29 UTC (rev 28687)
@@ -165,6 +165,10 @@
                        }
                }
                
+               if (selectedNodeViews.isEmpty()) {
+                       return;
+               }
+               
                if (networkCamera != null) {
                        NetworkToolkit.fitInView(networkCamera, 
selectedNodeViews, 180.0, 2.3, 1.8);
                }

Modified: 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/geometric/Vector3.java
===================================================================
--- 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/geometric/Vector3.java
        2012-03-28 22:45:59 UTC (rev 28686)
+++ 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/geometric/Vector3.java
        2012-03-29 00:08:29 UTC (rev 28687)
@@ -107,6 +107,19 @@
                return new Vector3(x + other.x, y + other.y, z + other.z);
        }
        
+       /** Return a new vector equal to the result of this plus a vector
+        * with the given coordinates
+        * 
+        * @param x The x-coordinate of the vector to add
+        * @param y The y-coordinate of the vector to add
+        * @param z The z-coordinate of the vector to add
+        * @return A new vector representing the result of this plus a vector
+        * with the given coordinates
+        */
+       public Vector3 plus(double x, double y, double z) {
+               return new Vector3(this.x + x, this.y + y, this.z + z);
+       }
+       
        /** Add another vector to this vector, such that this vector becomes
         * the sum
         * 
@@ -140,6 +153,18 @@
                return new Vector3(x - other.x, y - other.y, z - other.z);
        }
        
+       /** Subtract a 3-vector with the specified coordinates from this vector
+        * 
+        * @param x The x-coordinate of the vector to subtract
+        * @param y The y-coordinate of the vector to subtract
+        * @param z The z-coordinate of the vector to subtract
+        * @return A new vector representing the result of this minus a vector
+        * with the given coordinates
+        */
+       public Vector3 subtract(double x, double y, double z) {
+               return new Vector3(this.x - x, this.y - y, this.z - z);
+       }
+       
        /** Subtract the specified values from the coordinates of this vector
         * 
         * @param x X-coordinate

Added: 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutAlgorithm.java
===================================================================
--- 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutAlgorithm.java
                              (rev 0)
+++ 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutAlgorithm.java
      2012-03-29 00:08:29 UTC (rev 28687)
@@ -0,0 +1,25 @@
+package org.cytoscape.paperwing.internal.layouts;
+
+import org.cytoscape.view.layout.AbstractLayoutAlgorithm;
+import org.cytoscape.view.layout.CyLayoutContext;
+import org.cytoscape.view.model.CyNetworkView;
+import org.cytoscape.work.TaskIterator;
+import org.cytoscape.work.undo.UndoSupport;
+
+public class GridLayoutAlgorithm extends 
AbstractLayoutAlgorithm<GridLayoutContext> {
+
+       public GridLayoutAlgorithm() {
+               super("grid3D", "3D Grid Layout", false);
+       }
+
+       @Override
+       public TaskIterator createTaskIterator(GridLayoutContext context) {
+               return new TaskIterator(
+                               new GridLayoutAlgorithmTask(getName(), 
context));
+       }
+       
+       @Override
+       public GridLayoutContext createLayoutContext() {
+               return new GridLayoutContext(supportsSelectedOnly(), 
supportsNodeAttributes(), supportsEdgeAttributes());
+       }
+}


Property changes on: 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutAlgorithm.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutAlgorithmTask.java
===================================================================
--- 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutAlgorithmTask.java
                          (rev 0)
+++ 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutAlgorithmTask.java
  2012-03-29 00:08:29 UTC (rev 28687)
@@ -0,0 +1,156 @@
+package org.cytoscape.paperwing.internal.layouts;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.cytoscape.model.CyEdge.Type;
+import org.cytoscape.model.CyNetwork;
+import org.cytoscape.model.CyNode;
+import org.cytoscape.paperwing.internal.cytoscape.view.WindNetworkView;
+import org.cytoscape.paperwing.internal.geometric.Vector3;
+import org.cytoscape.paperwing.internal.tools.LayoutToolkit;
+import org.cytoscape.paperwing.internal.tools.NetworkToolkit;
+import org.cytoscape.view.layout.AbstractBasicLayoutTask;
+import org.cytoscape.view.layout.AbstractLayoutAlgorithmContext;
+import org.cytoscape.view.layout.LayoutNode;
+import org.cytoscape.view.layout.LayoutPartition;
+import org.cytoscape.view.layout.PartitionUtil;
+import org.cytoscape.view.model.CyNetworkView;
+import org.cytoscape.view.model.View;
+import org.cytoscape.view.presentation.property.BasicVisualLexicon;
+import org.cytoscape.work.TaskMonitor;
+
+public class GridLayoutAlgorithmTask extends AbstractBasicLayoutTask {
+
+       private GridLayoutContext context;
+       
+       public GridLayoutAlgorithmTask(String name,
+                       GridLayoutContext context) {
+               super(name, context);
+               this.context = context;
+       }
+
+       @Override
+       protected void doLayout(TaskMonitor taskMonitor) {
+               
+               // Break graph into partitions
+               List<LayoutPartition> layoutPartitions = 
PartitionUtil.partition(networkView, false, null);
+               int numPartitions = layoutPartitions.size();
+               
+               Collection<Collection<View<CyNode>>> partitions = new 
HashSet<Collection<View<CyNode>>>(layoutPartitions.size());
+               
+               Collection<View<CyNode>> partitionNodeViews;
+               
+               for (LayoutPartition partition : layoutPartitions) {
+                       partitionNodeViews = new HashSet<View<CyNode>>();
+                       
+                       for (LayoutNode layoutNode : partition.getNodeList()) {
+                               View<CyNode> nodeView = 
layoutNode.getNodeView();
+                               partitionNodeViews.add(nodeView);
+                       }
+                       
+                       partitions.add(partitionNodeViews);
+               }
+               
+               for (Collection<View<CyNode>> partition : partitions) {
+                       arrangeAsBox(partition, 270);
+               }
+               
+               LayoutToolkit.arrangePartitions(partitions);
+       }
+       
+       private void arrangeAsBox(Collection<View<CyNode>> nodeViews, double 
nodeSpacing) {             
+               int nodeCount = nodeViews.size();
+               int nodesPerFace = (int) Math.ceil(nodeCount / 6.0);
+               
+               int sideLength = (int) Math.ceil(Math.sqrt(nodesPerFace));
+               double halfSideLength = sideLength / 2.0;
+               
+               Vector3 center = LayoutToolkit.findCenter(nodeViews);
+               
+               // The position of the top-left corner of a face
+               Vector3 faceCorner;
+               // A unit vector pointing rightwards from the current corner
+               Vector3 faceRight = new Vector3();
+               // A unit vector pointing downwards from the current corner
+               Vector3 faceDown = new Vector3();
+               
+               int count = 0;
+               for (View<CyNode> nodeView : nodeViews) {
+                       int face = count / nodesPerFace;
+               
+                       switch (face) {
+                               // Front face (positive z direction)
+                               case 0:
+                                       faceCorner = 
center.plus(-halfSideLength * nodeSpacing, 
+                                                       halfSideLength * 
nodeSpacing,
+                                                       halfSideLength * 
nodeSpacing);
+                                       faceRight.set(1, 0, 0);
+                                       faceDown.set(0, -1, 0);
+                                       break;
+                               // Back face (negative z direction)
+                               case 1:
+                                       faceCorner = center.plus(halfSideLength 
* nodeSpacing, 
+                                                       halfSideLength * 
nodeSpacing,
+                                                       -halfSideLength * 
nodeSpacing);
+                                       faceRight.set(-1, 0, 0);
+                                       faceDown.set(0, -1, 0);
+                                       break;
+                               // Left face (negative x direction)
+                               case 2:
+                                       faceCorner = 
center.plus(-halfSideLength * nodeSpacing, 
+                                                       halfSideLength * 
nodeSpacing,
+                                                       -halfSideLength * 
nodeSpacing);
+                                       faceRight.set(0, 0, 1);
+                                       faceDown.set(0, -1, 0);
+                                       break;
+                               // Right face (positive x direction)
+                               case 3:
+                                       faceCorner = center.plus(halfSideLength 
* nodeSpacing, 
+                                                       halfSideLength * 
nodeSpacing,
+                                                       halfSideLength * 
nodeSpacing);
+                                       faceRight.set(0, 0, -1);
+                                       faceDown.set(0, -1, 0);
+                                       break;
+                               // Top face (positive y direction)
+                               case 4:
+                                       faceCorner = 
center.plus(-halfSideLength * nodeSpacing, 
+                                                       halfSideLength * 
nodeSpacing,
+                                                       -halfSideLength * 
nodeSpacing);
+                                       faceRight.set(1, 0, 0);
+                                       faceDown.set(0, 0, 1);
+                                       break;
+                               // Bottom face (negative y direction)
+                               case 5:
+                                       faceCorner = 
center.plus(-halfSideLength * nodeSpacing, 
+                                                       -halfSideLength * 
nodeSpacing,
+                                                       halfSideLength * 
nodeSpacing);
+                                       faceRight.set(1, 0, 0);
+                                       faceDown.set(0, 0, -1);
+                                       break;
+                               default:
+                                       throw new 
IllegalStateException("Current node cannot be allocated to a face of the 
arrangement cube.");
+                       }
+                       
+                       // The row that this node belongs to on the current face
+                       int row = (count % nodesPerFace) % sideLength + 1;
+                       
+                       // The column that this node belongs to on the current 
face
+                       int column = (count % nodesPerFace) / sideLength + 1;
+                       
+                       
nodeView.setVisualProperty(BasicVisualLexicon.NODE_X_LOCATION, 
+                                       faceCorner.x() + faceRight.x() * 
nodeSpacing * column + faceDown.x() * nodeSpacing * row);
+                       
nodeView.setVisualProperty(BasicVisualLexicon.NODE_Y_LOCATION, 
+                                       faceCorner.y() + faceRight.y() * 
nodeSpacing * column + faceDown.y() * nodeSpacing * row);
+                       
nodeView.setVisualProperty(BasicVisualLexicon.NODE_Z_LOCATION, 
+                                       faceCorner.z() + faceRight.z() * 
nodeSpacing * column + faceDown.z() * nodeSpacing * row);
+                       
+                       count++;
+               }
+       }
+}


Property changes on: 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutAlgorithmTask.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutContext.java
===================================================================
--- 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutContext.java
                                (rev 0)
+++ 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutContext.java
        2012-03-29 00:08:29 UTC (rev 28687)
@@ -0,0 +1,19 @@
+package org.cytoscape.paperwing.internal.layouts;
+
+import java.util.Set;
+
+import org.cytoscape.view.layout.AbstractLayoutAlgorithmContext;
+import org.cytoscape.work.Tunable;
+import org.cytoscape.work.TunableValidator;
+
+public class GridLayoutContext extends AbstractLayoutAlgorithmContext 
implements TunableValidator {
+       
+       public GridLayoutContext(boolean supportsSelectedOnly, Set<Class<?>> 
supportedNodeAttributes, Set<Class<?>> supportedEdgeAttributes) {
+               super(supportsSelectedOnly, supportedNodeAttributes, 
supportedEdgeAttributes);
+       }
+
+       @Override //TODO how to validate these values?
+       public ValidationState getValidationState(final Appendable errMsg) {
+               return ValidationState.OK;
+       }
+}


Property changes on: 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/GridLayoutContext.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/SphericalLayoutAlgorithmTask.java
===================================================================
--- 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/SphericalLayoutAlgorithmTask.java
     2012-03-28 22:45:59 UTC (rev 28686)
+++ 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/layouts/SphericalLayoutAlgorithmTask.java
     2012-03-29 00:08:29 UTC (rev 28687)
@@ -13,6 +13,7 @@
 import org.cytoscape.model.CyNode;
 import org.cytoscape.paperwing.internal.cytoscape.view.WindNetworkView;
 import org.cytoscape.paperwing.internal.geometric.Vector3;
+import org.cytoscape.paperwing.internal.tools.LayoutToolkit;
 import org.cytoscape.paperwing.internal.tools.NetworkToolkit;
 import org.cytoscape.view.layout.AbstractBasicLayoutTask;
 import org.cytoscape.view.layout.AbstractLayoutAlgorithmContext;
@@ -60,81 +61,9 @@
                        arrangeAsSphere(partition);
                }
                
-               arrangePartitions(partitions);
+               LayoutToolkit.arrangePartitions(partitions);
        }
        
-       private void arrangePartitions(Collection<Collection<View<CyNode>>> 
partitions) {
-               // Consider sorting partitions in order of decreasing radius?
-               
-               Map<Collection<View<CyNode>>, Double> partitionRadii = new 
HashMap<Collection<View<CyNode>>, Double>(partitions.size());
-               
-               // Basic approach: 1 partition per cube
-               int cubeLength = (int) Math.ceil(Math.pow(partitions.size(), 
1.0/3));
-               
-               // System.out.println("cubeLength: " + cubeLength);
-               
-               // Average position of all nodes
-               Vector3 averageTotalNodePosition = new Vector3();
-               int totalNodeCount = 0;
-               
-               double largestRadius = -1;
-               
-               for (Collection<View<CyNode>> partition : partitions) {
-                       
averageTotalNodePosition.addLocal(findCenter(partition).multiply(partition.size()));
-                       totalNodeCount += partition.size();
-                       
-                       double partitionRadius = findSubgraphRadius(partition);
-                       partitionRadii.put(partition, partitionRadius);
-                       
-                       if (partitionRadius > largestRadius) {
-                               largestRadius = partitionRadius;
-                       }
-               }
-               
-               largestRadius = Math.max(largestRadius, 50);
-               largestRadius *= 2;
-               
-               // Calculate the average position of all nodes by using the 
average position of partitions weighted by their node count
-               averageTotalNodePosition.divideLocal(totalNodeCount);
-               
-               int count = 0;
-               for (Collection<View<CyNode>> partition : partitions) {
-                       int x = count % cubeLength;
-                       int y = count / cubeLength % cubeLength;
-                       int z = count / cubeLength / cubeLength;
-                       
-                       // TODO: Need to set offset so that total average node 
position is preserved
-                       Vector3 offset = new Vector3(x * largestRadius, y * 
largestRadius, z * largestRadius);
-                       double halfCubeActualLength = (double) (cubeLength - 1) 
/ 2 * largestRadius;
-                       offset.subtractLocal(halfCubeActualLength, 
halfCubeActualLength, halfCubeActualLength);
-                       
-                       displaceNodes(partition, 
offset.plus(averageTotalNodePosition));
-                       
-                       // System.out.println(new Vector3(x, y, z));
-                       count++;
-               }
-       }
-       
-       // Displace a set of nodes such that their average of position is moved 
to the given point.
-       // Each node's position relative to the average position should remain 
unchanged.
-       private void displaceNodes(Collection<View<CyNode>> nodeViews, Vector3 
target) {
-               Vector3 currentCenter = findCenter(nodeViews);
-               Vector3 displacement = target.subtract(currentCenter);
-               
-               for (View<CyNode> nodeView : nodeViews) {
-                       
nodeView.setVisualProperty(BasicVisualLexicon.NODE_X_LOCATION,
-                                       
nodeView.getVisualProperty(BasicVisualLexicon.NODE_X_LOCATION) + 
displacement.x());
-                       
nodeView.setVisualProperty(BasicVisualLexicon.NODE_Y_LOCATION,
-                                       
nodeView.getVisualProperty(BasicVisualLexicon.NODE_Y_LOCATION) + 
displacement.y());
-                       
nodeView.setVisualProperty(BasicVisualLexicon.NODE_Z_LOCATION,
-                                       
nodeView.getVisualProperty(BasicVisualLexicon.NODE_Z_LOCATION) + 
displacement.z());
-               }
-       }
-       
-       private void arrangeAsBox(Collection<View<CyNode>> nodeViews) {
-               
-       }
-       
        private void arrangeAsSphere(Collection<View<CyNode>> nodeViews) {
                int nodeCount = nodeViews.size();
                int current = 0;
@@ -142,7 +71,7 @@
                double sphereRadius = findSphereRadius(nodeCount);
                double x, y, z;
                
-               Vector3 sphereCenter = findCenter(nodeViews);
+               Vector3 sphereCenter = LayoutToolkit.findCenter(nodeViews);
                
                for (View<CyNode> nodeView : nodeViews) {
                        
@@ -176,27 +105,6 @@
                }
        }
        
-       /**
-        * Find the average position of a given set of nodes
-        * @param nodeViews A set of nodes whose average position is to be found
-        * @return The average position, in coordinates directly obtained from 
node visual properties
-        */
-       private Vector3 findCenter(Collection<View<CyNode>> nodeViews) {
-               double x = 0;
-               double y = 0;
-               double z = 0;
-               
-               for (View<CyNode> nodeView : nodeViews) {
-                       x += 
nodeView.getVisualProperty(BasicVisualLexicon.NODE_X_LOCATION);
-                       y += 
nodeView.getVisualProperty(BasicVisualLexicon.NODE_Y_LOCATION);
-                       z += 
nodeView.getVisualProperty(BasicVisualLexicon.NODE_Z_LOCATION);
-               }
-               
-               Vector3 center = new Vector3(x, y, z);
-               center.divideLocal(nodeViews.size());
-               
-               return center;
-       }
        
        /**
         * Find an appropriate sphere size given the number of nodes to arrange
@@ -204,149 +112,4 @@
        private double findSphereRadius(int nodeCount) {
                return 100 + nodeCount;
        }
-
-       private Map<CyNode, Collection<CyNode>> findCliques(CyNetwork network) {
-               // TODO: Implement optimization by partitioning the graph 
before finding cliques
-               
-               Collection<CyNode> nodesList = new 
HashSet<CyNode>(network.getNodeList());
-               
-               // A map that maps every node to the biggest clique containing 
that node
-               Map<CyNode, Collection<CyNode>> cliques = new HashMap<CyNode, 
Collection<CyNode>>();
-               
-               // Find the largest clique containing each node
-               for (CyNode currentNode : nodesList) {
-
-                       Collection<CyNode> clique = new HashSet<CyNode>();
-                       clique.add(currentNode);
-
-                       // Loop through every neighbor of the current node
-                       for (CyNode neighbor : 
network.getNeighborList(currentNode, Type.ANY)) {
-
-                               boolean addToCurrentClique = true;
-                               
-                               for (CyNode cliqueNode : clique) {
-                                       if 
(network.getConnectingEdgeList(cliqueNode, neighbor, Type.ANY).isEmpty()) {
-                                               addToCurrentClique = false;
-                                       }
-                               }
-                               
-                               if (addToCurrentClique) {
-                                       clique.add(neighbor);
-                               }
-                       }
-                       
-                       cliques.put(currentNode, clique);
-               }
-               
-               return cliques;
-       }
-       
-       // Find the largest clique containing a given node from a given network
-       private Collection<CyNode> findLargestClique(CyNode node, CyNetwork 
network) {
-               Collection<CyNode> clique = new HashSet<CyNode>();
-               clique.add(node);
-               
-               List<CyNode> neighbors = network.getNeighborList(node, 
Type.ANY);
-               
-               // Loop through every neighbor of the current node
-               for (CyNode neighbor : neighbors) {
-
-                       boolean addToCurrentClique = true;
-                       
-                       for (CyNode cliqueNode : clique) {
-                               if (network.getConnectingEdgeList(cliqueNode, 
neighbor, Type.ANY).isEmpty()) {
-                                       addToCurrentClique = false;
-                               }
-                       }
-                       
-                       if (addToCurrentClique) {
-                               clique.add(neighbor);
-                       }
-               }
-               
-               return clique;
-       }
-       
-       /**
-        * Return a list of all cliques in the given set of nodes, sorted in 
order of decreasing size.
-        * A clique is a subgraph where there is an edge between any 2 nodes.
-        * 
-        * @param nodeViews The set of node view objects that should be used to 
find cliques.
-        * @return A list of cliques found, sorted in order of decreasing size.
-        */
-       private List<Collection<CyNode>> findCliquesOld(CyNetwork network) {
-               List<Collection<CyNode>> cliques = new 
LinkedList<Collection<CyNode>>();
-               
-               // TODO: Implement optimization by partitioning the graph 
before finding cliques
-               
-               Collection<CyNode> nodesToBeVisited = new 
HashSet<CyNode>(network.getNodeList());
-               Collection<CyNode> nodesPlacedInClique;
-               
-               Collection<CyNode> clique;
-               CyNode currentNode;
-               
-               // Find the largest clique containing each node
-               while(!nodesToBeVisited.isEmpty()) {
-                       currentNode = nodesToBeVisited.iterator().next();
-                       
-                       clique = new HashSet<CyNode>();
-                       clique.add(currentNode);
-
-                       nodesPlacedInClique = new HashSet<CyNode>();
-                       nodesPlacedInClique.add(currentNode);
-                       
-                       // Loop through every potential neighbor for the 
current node
-                       for (CyNode potentialNeighbor : nodesToBeVisited) {
-                               if (potentialNeighbor != currentNode) {
-                                       boolean addToCurrentClique = true;
-                                       
-                                       for (CyNode cliqueNode : clique) {
-                                               if 
(!network.containsEdge(potentialNeighbor, cliqueNode)
-                                                               && 
!network.containsEdge(cliqueNode, potentialNeighbor)) {
-                                                       
-                                                       addToCurrentClique = 
false;
-                                               }
-                                       }
-                                       
-                                       if (addToCurrentClique) {
-                                               clique.add(potentialNeighbor);
-                                               
nodesPlacedInClique.add(potentialNeighbor);
-                                       }
-                               }
-                       }
-                       
-                       cliques.add(clique);
-                       nodesToBeVisited.removeAll(nodesPlacedInClique);
-               }
-               
-               return null;
-       }
-       
-       /**
-        * Find the radius of the subgraph formed by the given set of nodes. 
This radius can be useful
-        * for determining the spacing between graph partitions.
-        * @return
-        */
-       private double findSubgraphRadius(Collection<View<CyNode>> nodeViews) {
-               
-               // Obtain the average node position
-               Vector3 averagePosition = findCenter(nodeViews);
-               
-               double maxDistanceSquared = -1;
-               View<CyNode> farthestNode = null;
-               double distanceSquared;
-               
-               for (View<CyNode> nodeView : nodeViews) {
-                       distanceSquared = 
Math.pow(nodeView.getVisualProperty(BasicVisualLexicon.NODE_X_LOCATION) - 
averagePosition.x(), 2)
-                               + 
Math.pow(nodeView.getVisualProperty(BasicVisualLexicon.NODE_Y_LOCATION) - 
averagePosition.y(), 2)
-                               + 
Math.pow(nodeView.getVisualProperty(BasicVisualLexicon.NODE_Z_LOCATION) - 
averagePosition.z(), 2);
-                       
-                       if (distanceSquared > maxDistanceSquared) {
-                               maxDistanceSquared = distanceSquared;
-                               farthestNode = nodeView;
-                       }
-               }
-               
-               return Math.sqrt(maxDistanceSquared);
-       }
 }

Added: 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/tools/LayoutToolkit.java
===================================================================
--- 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/tools/LayoutToolkit.java
                              (rev 0)
+++ 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/tools/LayoutToolkit.java
      2012-03-29 00:08:29 UTC (rev 28687)
@@ -0,0 +1,146 @@
+package org.cytoscape.paperwing.internal.tools;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.cytoscape.model.CyNode;
+import org.cytoscape.paperwing.internal.geometric.Vector3;
+import org.cytoscape.view.model.View;
+import org.cytoscape.view.presentation.property.BasicVisualLexicon;
+
+public class LayoutToolkit {
+       
+       /**
+        * Arranges the given partitions in a 3D cube-like grid with equal 
spacing. The spacing between partitions is proportional
+        * to the radius of the largest partition.
+        * 
+        * The average position of all given nodes should remain the same after 
the arrangement.
+        * 
+        * @param partitions The graph partitions to arrange.
+        */
+       public static void 
arrangePartitions(Collection<Collection<View<CyNode>>> partitions) {
+               // Consider sorting partitions in order of decreasing radius?
+               
+               Map<Collection<View<CyNode>>, Double> partitionRadii = new 
HashMap<Collection<View<CyNode>>, Double>(partitions.size());
+               
+               // Basic approach: 1 partition per cube
+               int cubeLength = (int) Math.ceil(Math.pow(partitions.size(), 
1.0/3));
+               
+               // System.out.println("cubeLength: " + cubeLength);
+               
+               // Average position of all nodes
+               Vector3 averageTotalNodePosition = new Vector3();
+               int totalNodeCount = 0;
+               
+               double largestRadius = -1;
+               
+               for (Collection<View<CyNode>> partition : partitions) {
+                       
averageTotalNodePosition.addLocal(findCenter(partition).multiply(partition.size()));
+                       totalNodeCount += partition.size();
+                       
+                       double partitionRadius = findSubgraphRadius(partition);
+                       partitionRadii.put(partition, partitionRadius);
+                       
+                       if (partitionRadius > largestRadius) {
+                               largestRadius = partitionRadius;
+                       }
+               }
+               
+               largestRadius = Math.max(largestRadius, 50);
+               largestRadius *= 2;
+               
+               // Calculate the average position of all nodes by using the 
average position of partitions weighted by their node count
+               averageTotalNodePosition.divideLocal(totalNodeCount);
+               
+               int count = 0;
+               for (Collection<View<CyNode>> partition : partitions) {
+                       int x = count % cubeLength;
+                       int y = count / cubeLength % cubeLength;
+                       int z = count / cubeLength / cubeLength;
+                       
+                       // TODO: Need to set offset so that total average node 
position is preserved
+                       Vector3 offset = new Vector3(x * largestRadius, y * 
largestRadius, z * largestRadius);
+                       double halfCubeActualLength = (double) (cubeLength - 1) 
/ 2 * largestRadius;
+                       offset.subtractLocal(halfCubeActualLength, 
halfCubeActualLength, halfCubeActualLength);
+                       
+                       displaceNodes(partition, 
offset.plus(averageTotalNodePosition));
+                       
+                       // System.out.println(new Vector3(x, y, z));
+                       count++;
+               }
+       }
+       
+       /**
+        * Displace a set of nodes such that their average of position is moved 
to the given point. Each node's 
+        * position relative to the average position should remain unchanged.
+        * 
+        * @param nodeViews The node views to displace
+        * @param target The target position to move the nodes towards
+        */
+       public static void displaceNodes(Collection<View<CyNode>> nodeViews, 
Vector3 target) {
+               Vector3 currentCenter = findCenter(nodeViews);
+               Vector3 displacement = target.subtract(currentCenter);
+               
+               for (View<CyNode> nodeView : nodeViews) {
+                       
nodeView.setVisualProperty(BasicVisualLexicon.NODE_X_LOCATION,
+                                       
nodeView.getVisualProperty(BasicVisualLexicon.NODE_X_LOCATION) + 
displacement.x());
+                       
nodeView.setVisualProperty(BasicVisualLexicon.NODE_Y_LOCATION,
+                                       
nodeView.getVisualProperty(BasicVisualLexicon.NODE_Y_LOCATION) + 
displacement.y());
+                       
nodeView.setVisualProperty(BasicVisualLexicon.NODE_Z_LOCATION,
+                                       
nodeView.getVisualProperty(BasicVisualLexicon.NODE_Z_LOCATION) + 
displacement.z());
+               }
+       }
+       
+
+       /**
+        * Find the average position of a given set of nodes
+        * @param nodeViews A set of nodes whose average position is to be found
+        * @return The average position, in coordinates directly obtained from 
node visual properties
+        */
+       public static Vector3 findCenter(Collection<View<CyNode>> nodeViews) {
+               double x = 0;
+               double y = 0;
+               double z = 0;
+               
+               for (View<CyNode> nodeView : nodeViews) {
+                       x += 
nodeView.getVisualProperty(BasicVisualLexicon.NODE_X_LOCATION);
+                       y += 
nodeView.getVisualProperty(BasicVisualLexicon.NODE_Y_LOCATION);
+                       z += 
nodeView.getVisualProperty(BasicVisualLexicon.NODE_Z_LOCATION);
+               }
+               
+               Vector3 center = new Vector3(x, y, z);
+               center.divideLocal(nodeViews.size());
+               
+               return center;
+       }
+       
+       /**
+        * Find the radius of the subgraph formed by the given set of nodes. 
This radius can be useful
+        * for determining the spacing between graph partitions.
+        * @return The radius of the subgraph, which is the distance from the 
average position of the nodes to
+        * the node that is farthest from the average position.
+        */
+       public static double findSubgraphRadius(Collection<View<CyNode>> 
nodeViews) {
+               
+               // Obtain the average node position
+               Vector3 averagePosition = findCenter(nodeViews);
+               
+               double maxDistanceSquared = -1;
+               View<CyNode> farthestNode = null;
+               double distanceSquared;
+               
+               for (View<CyNode> nodeView : nodeViews) {
+                       distanceSquared = 
Math.pow(nodeView.getVisualProperty(BasicVisualLexicon.NODE_X_LOCATION) - 
averagePosition.x(), 2)
+                               + 
Math.pow(nodeView.getVisualProperty(BasicVisualLexicon.NODE_Y_LOCATION) - 
averagePosition.y(), 2)
+                               + 
Math.pow(nodeView.getVisualProperty(BasicVisualLexicon.NODE_Z_LOCATION) - 
averagePosition.z(), 2);
+                       
+                       if (distanceSquared > maxDistanceSquared) {
+                               maxDistanceSquared = distanceSquared;
+                               farthestNode = nodeView;
+                       }
+               }
+               
+               return Math.sqrt(maxDistanceSquared);
+       }
+}


Property changes on: 
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/tools/LayoutToolkit.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

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