forcedirectedlayout.java
来自「用applet实现很多应用小程序」· Java 代码 · 共 450 行 · 第 1/2 页
JAVA
450 行
package prefuse.action.layout.graph;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
import prefuse.action.layout.Layout;
import prefuse.data.Graph;
import prefuse.data.Schema;
import prefuse.data.tuple.TupleSet;
import prefuse.util.PrefuseLib;
import prefuse.util.force.DragForce;
import prefuse.util.force.ForceItem;
import prefuse.util.force.ForceSimulator;
import prefuse.util.force.NBodyForce;
import prefuse.util.force.SpringForce;
import prefuse.visual.EdgeItem;
import prefuse.visual.NodeItem;
import prefuse.visual.VisualItem;
/**
* <p>Layout that positions graph elements based on a physics simulation of
* interacting forces; by default, nodes repel each other, edges act as
* springs, and drag forces (similar to air resistance) are applied. This
* algorithm can be run for multiple iterations for a run-once layout
* computation or repeatedly run in an animated fashion for a dynamic and
* interactive layout.</p>
*
* <p>The running time of this layout algorithm is the greater of O(N log N)
* and O(E), where N is the number of nodes and E the number of edges.
* The addition of custom force calculation modules may, however, increase
* this value.</p>
*
* <p>The {@link prefuse.util.force.ForceSimulator} used to drive this layout
* can be set explicitly, allowing any number of custom force directed layouts
* to be created through the user's selection of included
* {@link prefuse.util.force.Force} components. Each node in the layout is
* mapped to a {@link prefuse.util.force.ForceItem} instance and each edge
* to a {@link prefuse.util.force.Spring} instance for storing the state
* of the simulation. See the {@link prefuse.util.force} package for more.</p>
*
* @author <a href="http://jheer.org">jeffrey heer</a>
*/
public class ForceDirectedLayout extends Layout {
private ForceSimulator m_fsim;
private long m_lasttime = -1L;
private long m_maxstep = 50L;
private boolean m_runonce;
private int m_iterations = 100;
private boolean m_enforceBounds;
protected transient VisualItem referrer;
protected String m_nodeGroup;
protected String m_edgeGroup;
/**
* Create a new ForceDirectedLayout. By default, this layout will not
* restrict the layout to the layout bounds and will assume it is being
* run in animated (rather than run-once) fashion.
* @param graph the data group to layout. Must resolve to a Graph instance.
*/
public ForceDirectedLayout(String graph)
{
this(graph, false, false);
}
/**
* Create a new ForceDirectedLayout. The layout will assume it is being
* run in animated (rather than run-once) fashion.
* @param group the data group to layout. Must resolve to a Graph instance.
* @param enforceBounds indicates whether or not the layout should require
* that all node placements stay within the layout bounds.
*/
public ForceDirectedLayout(String group, boolean enforceBounds)
{
this(group, enforceBounds, false);
}
/**
* Create a new ForceDirectedLayout.
* @param group the data group to layout. Must resolve to a Graph instance.
* @param enforceBounds indicates whether or not the layout should require
* that all node placements stay within the layout bounds.
* @param runonce indicates if the layout will be run in a run-once or
* animated fashion. In run-once mode, the layout will run for a set number
* of iterations when invoked. In animation mode, only one iteration of the
* layout is computed.
*/
public ForceDirectedLayout(String group,
boolean enforceBounds, boolean runonce)
{
super(group);
m_nodeGroup = PrefuseLib.getGroupName(group, Graph.NODES);
m_edgeGroup = PrefuseLib.getGroupName(group, Graph.EDGES);
m_enforceBounds = enforceBounds;
m_runonce = runonce;
m_fsim = new ForceSimulator();
m_fsim.addForce(new NBodyForce());
m_fsim.addForce(new SpringForce());
m_fsim.addForce(new DragForce());
}
/**
* Create a new ForceDirectedLayout. The layout will assume it is being
* run in animated (rather than run-once) fashion.
* @param group the data group to layout. Must resolve to a Graph instance.
* @param fsim the force simulator used to drive the layout computation
* @param enforceBounds indicates whether or not the layout should require
* that all node placements stay within the layout bounds.
*/
public ForceDirectedLayout(String group,
ForceSimulator fsim, boolean enforceBounds) {
this(group, fsim, enforceBounds, false);
}
/**
* Create a new ForceDirectedLayout.
* @param group the data group to layout. Must resolve to a Graph instance.
* @param fsim the force simulator used to drive the layout computation
* @param enforceBounds indicates whether or not the layout should require
* that all node placements stay within the layout bounds.
* @param runonce indicates if the layout will be run in a run-once or
* animated fashion. In run-once mode, the layout will run for a set number
* of iterations when invoked. In animation mode, only one iteration of the
* layout is computed.
*/
public ForceDirectedLayout(String group, ForceSimulator fsim,
boolean enforceBounds, boolean runonce)
{
super(group);
m_nodeGroup = PrefuseLib.getGroupName(group, Graph.NODES);
m_edgeGroup = PrefuseLib.getGroupName(group, Graph.EDGES);
m_enforceBounds = enforceBounds;
m_runonce = runonce;
m_fsim = fsim;
}
// ------------------------------------------------------------------------
/**
* Get the maximum timestep allowed for integrating node settings between
* runs of this layout. When computation times are longer than desired,
* and node positions are changing dramatically between animated frames,
* the max step time can be lowered to suppress node movement.
* @return the maximum timestep allowed for integrating between two
* layout steps.
*/
public long getMaxTimeStep() {
return m_maxstep;
}
/**
* Set the maximum timestep allowed for integrating node settings between
* runs of this layout. When computation times are longer than desired,
* and node positions are changing dramatically between animated frames,
* the max step time can be lowered to suppress node movement.
* @param maxstep the maximum timestep allowed for integrating between two
* layout steps
*/
public void setMaxTimeStep(long maxstep) {
this.m_maxstep = maxstep;
}
/**
* Get the force simulator driving this layout.
* @return the force simulator
*/
public ForceSimulator getForceSimulator() {
return m_fsim;
}
/**
* Set the force simulator driving this layout.
* @param fsim the force simulator
*/
public void setForceSimulator(ForceSimulator fsim) {
m_fsim = fsim;
}
/**
* Get the number of iterations to use when computing a layout in
* run-once mode.
* @return the number of layout iterations to run
*/
public int getIterations() {
return m_iterations;
}
/**
* Set the number of iterations to use when computing a layout in
* run-once mode.
* @param iter the number of layout iterations to run
*/
public void setIterations(int iter) {
if ( iter < 1 )
throw new IllegalArgumentException(
"Iterations must be a positive number!");
m_iterations = iter;
}
/**
* Explicitly sets the node and edge groups to use for this layout,
* overriding the group setting passed to the constructor.
* @param nodeGroup the node data group
* @param edgeGroup the edge data group
*/
public void setDataGroups(String nodeGroup, String edgeGroup) {
m_nodeGroup = nodeGroup;
m_edgeGroup = edgeGroup;
}
// ------------------------------------------------------------------------
/**
* @see prefuse.action.Action#run(double)
*/
public void run(double frac) {
// perform different actions if this is a run-once or
// run-continuously layout
if ( m_runonce ) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?