public interface Layout extends Pipe
The layout algorithm role is to compute the best possible positions of nodes in a given space (2D or 3D) and eventually break points for edges if supported using either aesthetic constraints, hierarchical constraints or grouping constraints. As there are many such algorithms with distinct qualities and uses, this interface defines what is awaited from a general layout algorithm.
This algorithm is a Pipe
that receives notifications on the graph
eventually maintain an internal representation of it (or for some of them
work directly on the graph), and in return send graph events to give each
node a position via "xyz" attributes. Some algorithms may also export more
information for nodes and edges. For example some algorithms are also able to
work on the shape of an edge or the shape of a node.
The layout algorithm described by this interface may be iterative. Some algorithm will compute directly their final representation of the graph in one pass. However most algorithms will probably work step by step until a global quality function is satisfied. This is the best way to handle evolving graphs.
This behavior has been chosen because this algorithm is often run aside the
main thread that works on the graph. We want a thread to be able to compute a
new layout on its side, without disturbing the main algorithm run on the
graph. See the LayoutRunner
for an helper
class allowing to create such a thread.
To be notified of the layout changes dynamically, you must register as a sink of the layout.
The graph viewers in the UI package often use a layout algorithm to present graphs on screen.
Modifier and Type | Method and Description |
---|---|
void |
clear()
Clears the whole nodes and edges structures
|
void |
compute()
Method to call repeatedly to compute the layout.
|
void |
freezeNode(java.lang.String id,
boolean frozen)
Freeze or un-freeze a node.
|
double |
getForce()
The current layout force.
|
Point3 |
getHiPoint()
Largest point in space of the layout bounding box.
|
long |
getLastStepTime()
Time in nanoseconds used by the last call to step().
|
java.lang.String |
getLayoutAlgorithmName()
Name of the layout algorithm.
|
Point3 |
getLowPoint()
Smallest point in space of the layout bounding box.
|
int |
getNodeMovedCount()
How many nodes moved during the last step?.
|
double |
getQuality()
The current layout algorithm quality.
|
double |
getStabilization()
Estimate of how close to stabilization the layout algorithm is.
|
double |
getStabilizationLimit()
Above which value a correct stabilization is achieved?
|
int |
getSteps()
Number of calls made to step() so far.
|
void |
moveNode(java.lang.String id,
double x,
double y,
double z)
Move a node by force to a new location.
|
void |
setForce(double value)
The general "speed" of the algorithm.
|
void |
setQuality(double qualityLevel)
Set the overall quality level, a number between 0 and 1 with 1 the highest
quality available, but often with a slower computation.
|
void |
setSendNodeInfos(boolean send)
If true, node informations messages are sent for every node.
|
void |
setStabilizationLimit(double value)
Change the stabilization limit for this layout algorithm.
|
void |
shake()
Add a random vector whose length is 10% of the size of the graph to all node
positions.
|
addAttributeSink, addElementSink, addSink, clearAttributeSinks, clearElementSinks, clearSinks, removeAttributeSink, removeElementSink, removeSink
edgeAttributeAdded, edgeAttributeChanged, edgeAttributeRemoved, graphAttributeAdded, graphAttributeChanged, graphAttributeRemoved, nodeAttributeAdded, nodeAttributeChanged, nodeAttributeRemoved
edgeAdded, edgeRemoved, graphCleared, nodeAdded, nodeRemoved, stepBegins
java.lang.String getLayoutAlgorithmName()
int getNodeMovedCount()
double getStabilization()
double getStabilizationLimit()
Point3 getLowPoint()
Point3 getHiPoint()
int getSteps()
long getLastStepTime()
double getQuality()
double getForce()
void clear()
void setForce(double value)
value
- A number in [0..1].void setStabilizationLimit(double value)
The stabilization is a number between 0 and 1 that indicates how close to
stabilization (no nodes need to move) the layout is. The value 1 means the
layout is fully stabilized. Naturally this is often only an indication only,
for some algorithms, it is difficult to determine if the layout is correct or
acceptable enough. You can get the actual stabilization limit using
getStabilizationLimit()
. You can get the actual stabilization using
getStabilization()
.
Be careful, most layout classes do not use the stabilization limit, this
number is mostly used the process that control the layout, like the
LayoutRunner
for example. The stabilization limit is only an
indication with a default set for each layout algorithm. However this default
can be changed using this method, or by storing on the graph an attribute
"layout.stabilization-limit" (or "layout.stabilisation-limit").
The convention is that the value 0 means that the process controlling the layout will not stop the layout (will therefore not consider the stabilization limit). In other words the layout will compute endlessly.
value
- The new stabilization limit, 0 means no need to stabilize. Else a
value larger than zero or equal to 1 is accepted.void setQuality(double qualityLevel)
qualityLevel
- The quality level, a number between 0 and 1.void setSendNodeInfos(boolean send)
send
- If true, send node informations to a "layout.info" attribute.void shake()
void moveNode(java.lang.String id, double x, double y, double z)
id
- The node identifier.x
- The node new X.y
- The node new Y.z
- The node new Z.void freezeNode(java.lang.String id, boolean frozen)
id
- The node identifier.frozen
- If true the node is frozen.void compute()
This method implements the layout algorithm proper. It must be called in a
loop, until the layout stabilizes. You can know if the layout is stable by
using the getNodeMovedCount()
method that returns the number of node
that have moved during the last call to step().
The listener is called by this method, therefore each call to step() will also trigger layout events, allowing to reproduce the layout process graphically for example. You can insert the listener only when the layout stabilized, and then call step() anew if you do not want to observe the layout process.