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.