Author: pwang
Date: 2010-09-22 16:09:51 -0700 (Wed, 22 Sep 2010)
New Revision: 22020
Modified:
core3/layout-prefuse-impl/trunk/src/main/java/org/cytoscape/prefuse/layouts/internal/ForceDirectedLayout.java
Log:
Refactored
Modified:
core3/layout-prefuse-impl/trunk/src/main/java/org/cytoscape/prefuse/layouts/internal/ForceDirectedLayout.java
===================================================================
---
core3/layout-prefuse-impl/trunk/src/main/java/org/cytoscape/prefuse/layouts/internal/ForceDirectedLayout.java
2010-09-22 22:33:00 UTC (rev 22019)
+++
core3/layout-prefuse-impl/trunk/src/main/java/org/cytoscape/prefuse/layouts/internal/ForceDirectedLayout.java
2010-09-22 23:09:51 UTC (rev 22020)
@@ -1,282 +1,106 @@
-
-/*
- Copyright (c) 2007, The Cytoscape Consortium (www.cytoscape.org)
-
- The Cytoscape Consortium is:
- - Institute for Systems Biology
- - University of California San Diego
- - Memorial Sloan-Kettering Cancer Center
- - Institut Pasteur
- - Agilent Technologies
-
- This library is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License, or
- any later version.
-
- This library is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF
- MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. The software and
- documentation provided hereunder is on an "as is" basis, and the
- Institute for Systems Biology and the Whitehead Institute
- have no obligations to provide maintenance, support,
- updates, enhancements or modifications. In no event shall the
- Institute for Systems Biology and the Whitehead Institute
- be liable to any party for direct, indirect, special,
- incidental or consequential damages, including lost profits, arising
- out of the use of this software and its documentation, even if the
- Institute for Systems Biology and the Whitehead Institute
- have been advised of the possibility of such damage. See
- the GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this library; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-*/
-
-package org.cytoscape.prefuse.layouts.internal;
-
-import java.awt.Dimension;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.cytoscape.view.layout.AbstractGraphPartition;
-import org.cytoscape.view.layout.EdgeWeighter;
-import org.cytoscape.view.layout.LayoutEdge;
-import org.cytoscape.view.layout.LayoutNode;
-import org.cytoscape.view.layout.LayoutPartition;
-import org.cytoscape.work.Tunable;
-import org.cytoscape.work.undo.UndoSupport;
-
-import prefuse.util.force.DragForce;
-import prefuse.util.force.EulerIntegrator;
-import prefuse.util.force.ForceItem;
-import prefuse.util.force.ForceSimulator;
-import prefuse.util.force.Integrator;
-import prefuse.util.force.NBodyForce;
-import prefuse.util.force.RungeKuttaIntegrator;
-import prefuse.util.force.SpringForce;
-
-enum Integrators{
- RUNGEKUTTA("RUNGEKUTTA"),
- EULER("EULER");
-
- private String name;
- private Integrators(String str) { name=str; }
- public String toString() { return name; }
- public Integrator getNewIntegrator() {
- // FIXME: could we use a switch on 'this' instead? (can't use
one on
- // name, because that is string, but) 'this' would be an enum,
right?
- // but eclipse complains if I have Integrators.EULER as a switch
- // label...
-
- if (name.equals("EULER")){
- return new EulerIntegrator();
- }
- else if (name.equals("RUNGEKUTTA")){
- return new RungeKuttaIntegrator();
- } else {// use Euler as default
- return new EulerIntegrator();
- }
- }
-}
-
-
-/**
- * This class wraps the Prefuse force-directed layout algorithm.
- * See {...@link http://prefuse.org} for more detail.
- */
-public class ForceDirectedLayout extends AbstractGraphPartition
-{
- private ForceSimulator m_fsim;
-
- @Tunable(description="Number of Iterations", groups="Algorithm
settings")
- public int numIterations = 100;
- @Tunable(description="Default Spring Coefficient", groups="Algorithm
settings")
- public double defaultSpringCoefficient = 1e-4;
- @Tunable(description="Default Spring Length", groups="Algorithm
settings")
- public double defaultSpringLength = 50.0;
- @Tunable(description="Default Node Mass", groups="Algorithm settings")
- public double defaultNodeMass = 3.0;
-
- @Tunable(description="Integration algorithm to use", groups="Algorithm
settings")
- public Integrators integrator = Integrators.RUNGEKUTTA;
-
- /**
- * Value to set for doing unweighted layouts
- */
- public static final String UNWEIGHTEDATTRIBUTE = "(unweighted)";
-
- private boolean supportWeights = true;
- Map<LayoutNode,ForceItem> forceItems;
-
-
- public ForceDirectedLayout(UndoSupport undo) {
- super(undo);
-
- if (edgeWeighter == null)
- edgeWeighter = new EdgeWeighter();
-
- m_fsim = new ForceSimulator();
- m_fsim.addForce(new NBodyForce());
- m_fsim.addForce(new SpringForce());
- m_fsim.addForce(new DragForce());
-
- forceItems = new HashMap<LayoutNode,ForceItem>();
- }
-
- public String getName() {
- return "force-directed";
- }
-
- public String toString() {
- return "Force-Directed Layout";
- }
-
- protected void initialize_local() {
- }
-
-
- public void layoutPartion(LayoutPartition part) {
- Dimension initialLocation = null;
- // System.out.println("layoutPartion:
"+part.getEdgeList().size()+" edges");
- // Calculate our edge weights
- part.calculateEdgeWeights();
- // System.out.println("layoutPartion:
"+part.getEdgeList().size()+" edges after calculateEdgeWeights");
-
- m_fsim.setIntegrator(integrator.getNewIntegrator());
- m_fsim.clear();
-
- // initialize nodes
- for (LayoutNode ln: part.getNodeList()) {
- if ( !forceItems.containsKey(ln) )
- forceItems.put(ln, new ForceItem());
- ForceItem fitem = forceItems.get(ln);
- fitem.mass = getMassValue(ln);
- fitem.location[0] = 0f;
- fitem.location[1] = 0f;
- m_fsim.addItem(fitem);
- }
-
- // initialize edges
- for (LayoutEdge e: part.getEdgeList()) {
- LayoutNode n1 = e.getSource();
- ForceItem f1 = forceItems.get(n1);
- LayoutNode n2 = e.getTarget();
- ForceItem f2 = forceItems.get(n2);
- if ( f1 == null || f2 == null )
- continue;
- // System.out.println("Adding edge "+e+" with spring
coeffficient = "+getSpringCoefficient(e)+" and length "+getSpringLength(e));
- m_fsim.addSpring(f1, f2, getSpringCoefficient(e),
getSpringLength(e));
- }
-
- // setTaskStatus(5); // This is a rough approximation, but
probably good enough
- if (taskMonitor != null) {
- taskMonitor.setStatusMessage("Initializing partition
"+part.getPartitionNumber());
- }
-
- // Figure out our starting point
- if (selectedOnly) {
- initialLocation = part.getAverageLocation();
- }
-
- // perform layout
- long timestep = 1000L;
- for ( int i = 0; i < numIterations && !canceled; i++ ) {
- timestep *= (1.0 - i/(double)numIterations);
- long step = timestep+50;
- m_fsim.runSimulator(step);
-
setTaskStatus((int)(((double)i/(double)numIterations)*90.+5));
- }
-
- // update positions
- for (LayoutNode ln: part.getNodeList()) {
- if (!ln.isLocked()) {
- ForceItem fitem = forceItems.get(ln);
- ln.setX(fitem.location[0]);
- ln.setY(fitem.location[1]);
- part.moveNodeToLocation(ln);
- }
- }
- // Not quite done, yet. If we're only laying out selected
nodes, we need
- // to migrate the selected nodes back to their starting position
- if (selectedOnly) {
- double xDelta = 0.0;
- double yDelta = 0.0;
- Dimension finalLocation = part.getAverageLocation();
- xDelta = finalLocation.getWidth() -
initialLocation.getWidth();
- yDelta = finalLocation.getHeight() -
initialLocation.getHeight();
- for (LayoutNode v: part.getNodeList()) {
- if (!v.isLocked()) {
- v.decrement(xDelta, yDelta);
- part.moveNodeToLocation(v);
- }
- }
- }
- }
-
- /**
- * Get the mass value associated with the given node. Subclasses should
- * override this method to perform custom mass assignment.
- * @param n the node for which to compute the mass value
- * @return the mass value for the node. By default, all items are given
- * a mass value of 1.0.
- */
- protected float getMassValue(LayoutNode n) {
- return (float)defaultNodeMass;
- }
-
- /**
- * Get the spring length for the given edge. Subclasses should
- * override this method to perform custom spring length assignment.
- * @param e the edge for which to compute the spring length
- * @return the spring length for the edge. A return value of
- * -1 means to ignore this method and use the global default.
- */
- protected float getSpringLength(LayoutEdge e) {
- double weight = e.getWeight();
- return (float)(defaultSpringLength/weight);
- }
-
- /**
- * Get the spring coefficient for the given edge, which controls the
- * tension or strength of the spring. Subclasses should
- * override this method to perform custom spring tension assignment.
- * @param e the edge for which to compute the spring coefficient.
- * @return the spring coefficient for the edge. A return value of
- * -1 means to ignore this method and use the global default.
- */
- protected float getSpringCoefficient(LayoutEdge e) {
- return (float)defaultSpringCoefficient;
- }
-
- /**
- * Return information about our algorithm
- */
- public boolean supportsSelectedOnly() {
- return true;
- }
-
- public Set<Class<?>> supportsEdgeAttributes() {
- Set<Class<?>> ret = new HashSet<Class<?>>();
- if (!supportWeights)
- return ret;
-
- ret.add( Integer.class );
- ret.add( Double.class );
-
- return ret;
- }
-
- public List getInitialAttributeList() {
- ArrayList list = new ArrayList();
- list.add(UNWEIGHTEDATTRIBUTE);
-
- return list;
- }
-
-}
+package org.cytoscape.prefuse.layouts.internal;
+
+import java.io.IOException;
+
+import org.cytoscape.view.layout.AbstractLayout;
+import org.cytoscape.view.layout.CyLayouts;
+import org.cytoscape.work.TaskIterator;
+import org.cytoscape.work.Tunable;
+import org.cytoscape.work.TunableValidator;
+import org.cytoscape.work.undo.UndoSupport;
+import org.cytoscape.work.util.ListSingleSelection;
+
+import prefuse.util.force.EulerIntegrator;
+import prefuse.util.force.RungeKuttaIntegrator;
+import prefuse.util.force.Integrator;
+import org.cytoscape.work.util.ListSingleSelection;
+
+public class ForceDirectedLayout extends AbstractLayout implements
TunableValidator {
+
+ @Tunable(description="Number of Iterations", groups="Algorithm
settings")
+ public int numIterations = 100;
+ @Tunable(description="Default Spring Coefficient", groups="Algorithm
settings")
+ public double defaultSpringCoefficient = 1e-4;
+ @Tunable(description="Default Spring Length", groups="Algorithm
settings")
+ public double defaultSpringLength = 50.0;
+ @Tunable(description="Default Node Mass", groups="Algorithm settings")
+ public double defaultNodeMass = 3.0;
+
+ //@Tunable(description="Integration algorithm to use",
groups="Algorithm settings")
+ public Integrators integrator = Integrators.RUNGEKUTTA;
+ //public ListSingleSelection<String> integratorChoice = "RUNGEKUTTA";
+
+ //TODO refactor
+ public enum Integrators {
+ RUNGEKUTTA ("RUNGEKUTTA"),
+ EULER ("EULER");
+
+ private String name;
+ private Integrators(String str) { name=str; }
+ public String toString() { return name; }
+ public Integrator getNewIntegrator() {
+ // FIXME: could we use a switch on 'this' instead?
(can't use one on
+ // name, because that is string, but) 'this' would be
an enum, right?
+ // but eclipse complains if I have Integrators.EULER as
a switch
+ // label...
+
+ if (name.equals("EULER")){
+ return new EulerIntegrator();
+ }
+ else if (name.equals("RUNGEKUTTA")){
+ return new RungeKuttaIntegrator();
+ } else {// use Euler as default
+ return new EulerIntegrator();
+ }
+ }
+ }
+
+
+ /**
+ * Creates a new GridNodeLayout object.
+ */
+ public ForceDirectedLayout(UndoSupport un) {
+ super(un);
+ }
+
+ //TODO how to validate these values?
+ public boolean tunablesAreValid(final Appendable errMsg) {
+ // Do something here to validate the parameter values
+ // ??????????????
+
+ return true;
+ }
+
+ public TaskIterator getTaskIterator() {
+
+ return new TaskIterator(new
ForceDirectedLayoutTask(networkView, getName(), selectedOnly, staticNodes,
+ numIterations,
defaultSpringCoefficient,defaultSpringLength,defaultNodeMass,integrator));
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public String getName() {
+ return "Force-Directed";
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public String toString() {
+ return "Force Directed Layout";
+ }
+
+ /**
+ * We do support selected only
+ *
+ * @return true
+ */
+ public boolean supportsSelectedOnly() {
+ return true;
+ }
+}
--
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.