public class BusRouter extends AbstractLayoutStage
Carefully observe that the resulting representation, with many edge segments drawn on top of each other, leaves little room for a sensible interpretation of edge direction.
Edge segments are bundled to buses. A bus is a segment shared by multiple edges to which shorter segments that connect to actual nodes are attached. Buses and all other segments are routed orthogonally.
A bus can, for example, be created in parts of a diagram where each node is connected to each other node. There are no cycles induced by any two edge paths of the same bus, that is, the combination of all edge routes looks like an orthogonal tree.
The algorithm tries to produce routes where the edges share as much of their paths as possible. It yields long line segments (so-called backbone segments) where ideally all but the first and last segments of all edge paths are drawn on top of each other (forming a bus), with short connections branching off to the nodes (bus connections). These short connections bundle the respective first or last segments of a node's incident edges.
This algorithm will not modify positions or sizes of nodes in any way, but will route the edges of the graph.
Bus-style edge routing with default settings Edge routing sample including four different buses
The algorithm uses a two-phase process:
To determine which edges belong to a common bus, a mapping that assigns a bus ID to each edge must be specified using
BusDescriptor
s. A IDataProvider
holding BusDescriptor
instances is expected to be registered
with the graph using the
descriptor key
. In the absence of an individual bus ID for an edge, a bus consisting
only of the single edge is created.
This algorithm supports PortConstraint
s as well as
PortCandidate
s to control where edges should connect to nodes.
Note that if edges of the same bus connect to a common node but have inconsistent or contradicting port constraints/candidates, then any of these constraints/candidates can determine the actual location of the common port. The same applies for edges that, in addition, belong to the same edge group.
Also, the cardinality defined with a PortCandidateSet
object is interpreted in terms of different bus IDs (group
IDs) instead of number of edges.
This algorithm supports incremental edge routing, that is, extending or updating an already existing bus-style
representation. This is useful to rearrange existing edges or to include additional edges in an existing bus.
Incremental routing is supported by denoting so-called fixed edges using the
corresponding BusDescriptor property
. The paths of edges which are not
marked as fixed are calculated by the algorithm. The structure induced by the fixed edges must be orthogonal and
cycle-free.
Modifier and Type | Field and Description |
---|---|
static EdgeDpKey<Boolean> |
DEFAULT_AFFECTED_EDGES_DPKEY
A
DataProvider key for specifying the edge subset to be routed
This key is used if no custom key for specifying the subset is defined using
AffectedEdgesDpKey . |
static EdgeDpKey<BusDescriptor> |
EDGE_DESCRIPTOR_DPKEY
A
DataProvider key for specifying a bus descriptor object for each edge
The BusDescriptor for an edge provides the edge's bus ID, its optional group IDs and whether or not the edge is
fixed. |
Constructor and Description |
---|
BusRouter()
Creates a new instance of
BusRouter with default settings. |
Modifier and Type | Method and Description |
---|---|
void |
applyLayout(LayoutGraph graph)
Calculates bus-like routes for the edges in the given input graph.
|
Object |
getAffectedEdgesDpKey()
Gets the key to register a
IDataProvider for marking edges as selected. |
double |
getCrossingCost()
Gets the cost for each edge crossing.
|
int |
getGridSpacing()
Gets the equidistant spacing between the horizontal and vertical grid lines.
|
double |
getMinimumBackboneSegmentLength()
Gets the preferred minimum length of a backbone segment.
|
int |
getMinimumBusConnectionsCount()
Gets the minimum number of bus connections a backbone segment must have.
|
int |
getMinimumDistanceToEdge()
Gets the minimum distance between any two edge segments.
|
int |
getMinimumDistanceToNode()
Gets the minimum distance between edge segments and nodes.
|
int |
getPreferredBackboneSegmentCount()
Gets the maximum number of selected backbone segments with the same orientation.
|
Scope |
getScope()
Gets the scope for this routing algorithm that determines which edges are routed.
|
boolean |
isCollinearBendsRemovalEnabled()
Gets whether or not collinear bends are removed from the layout.
|
boolean |
isGridRoutingEnabled()
Gets whether or not to route edge segments on grid lines only.
|
boolean |
isReroutingEnabled()
Gets whether or not to perform an additional step to reroute the edges such that the number of edge crossings is
reduced.
|
void |
setAffectedEdgesDpKey(Object value)
Sets the key to register a
IDataProvider for marking edges as selected. |
void |
setCollinearBendsRemovalEnabled(boolean value)
Sets whether or not collinear bends are removed from the layout.
|
void |
setCrossingCost(double value)
Sets the cost for each edge crossing.
|
void |
setGridRoutingEnabled(boolean value)
Sets whether or not to route edge segments on grid lines only.
|
void |
setGridSpacing(int value)
Sets the equidistant spacing between the horizontal and vertical grid lines.
|
void |
setMinimumBackboneSegmentLength(double value)
Sets the preferred minimum length of a backbone segment.
|
void |
setMinimumBusConnectionsCount(int value)
Sets the minimum number of bus connections a backbone segment must have.
|
void |
setMinimumDistanceToEdge(int value)
Sets the minimum distance between any two edge segments.
|
void |
setMinimumDistanceToNode(int value)
Sets the minimum distance between edge segments and nodes.
|
void |
setPreferredBackboneSegmentCount(int value)
Sets the maximum number of selected backbone segments with the same orientation.
|
void |
setReroutingEnabled(boolean value)
Sets whether or not to perform an additional step to reroute the edges such that the number of edge crossings is
reduced.
|
void |
setScope(Scope value)
Sets the scope for this routing algorithm that determines which edges are routed.
|
applyLayoutCore, getCoreLayout, setCoreLayout
public static final EdgeDpKey<Boolean> DEFAULT_AFFECTED_EDGES_DPKEY
DataProvider
key for specifying the edge subset to be routed
This key is used if no custom key for specifying the subset is defined using
AffectedEdgesDpKey
.
Scope.ROUTE_AFFECTED_EDGES
.setScope(Scope)
,
setAffectedEdgesDpKey(Object)
public static final EdgeDpKey<BusDescriptor> EDGE_DESCRIPTOR_DPKEY
DataProvider
key for specifying a bus descriptor object for each edge
The BusDescriptor
for an edge provides the edge's bus ID, its optional group IDs and whether or not the edge is
fixed.
public BusRouter()
BusRouter
with default settings.public void applyLayout(LayoutGraph graph)
applyLayout
in interface ILayoutAlgorithm
applyLayout
in class AbstractLayoutStage
IllegalArgumentException
- if the graph is not supported by this algorithmgraph
- the input graphpublic Object getAffectedEdgesDpKey()
IDataProvider
for marking edges as selected.
If the scope
is set to Scope.ROUTE_AFFECTED_EDGES
, only the edges for which the
registered IDataProvider
returns true
will be routed. All other edges will be considered to have fixed
routes.
IllegalArgumentException
- if the specified key is null
DEFAULT_AFFECTED_EDGES_DPKEY
IDataProvider
key for edge selectionsetAffectedEdgesDpKey(Object)
public double getCrossingCost()
A cost value of n
means that it is more profitable for a path to change its direction n
times rather
than crossing the path of an edge. If the cost value is set to
0.0
, no global crossing optimization is performed.
The cost is defined to be a non-negative value.
IllegalArgumentException
- if the given cost value is negative1.0
and 3.0
.setCrossingCost(double)
public int getGridSpacing()
Positive values greater than 2
are allowed. Positive values less than 2
are ignored, while negative
values are mapped to their absolute value.
grid routing
is enabled.setGridRoutingEnabled(boolean)
,
setGridSpacing(int)
public double getMinimumBackboneSegmentLength()
This number defines the minimum length of backbone segments which are computed by the backbone selection phase. Some of the final backbone segments may be shorter due to changes in the routing and recombination phase.
The minimum length is defined to be a value greater than or equal to 1.0
.
IllegalArgumentException
- if the given minimum length is smaller than 1.0
bounding box
.setMinimumBackboneSegmentLength(double)
public int getMinimumBusConnectionsCount()
If a backbone segment has less connections, it is removed and the affected nodes connect to another backbone segment.
The minimum connection count must be a value greater than or equal to 1
.
IllegalArgumentException
- if the given minimum count is smaller than 1
3
or 4
is a good choice for small graphs. For larger graphs a much larger count can
be reasonable.setMinimumBusConnectionsCount(int)
public int getMinimumDistanceToEdge()
The edge routing algorithm adheres to this value if possible, but reduces the distance value selectively, i.e., only for a currently processed edge, when there is not enough space to find a path with the proper value.
Positive values greater than 4
are allowed. Positive values less than 4
are ignored, while negative
values are mapped to their absolute values.
setMinimumDistanceToEdge(int)
public int getMinimumDistanceToNode()
Positive values greater than 2
are allowed. Positive values less than 2
are ignored, while negative
values are mapped to their absolutes.
setMinimumDistanceToNode(int)
public int getPreferredBackboneSegmentCount()
This setting defines the number of backbone segments of the same orientation which are computed by the backbone selection phase. The final number of backbone segments may be different due to changes in the routing and recombination phase.
The number must be a value greater than or equal to 1
.
IllegalArgumentException
- if the given preferred number is smaller than 1
setPreferredBackboneSegmentCount(int)
public Scope getScope()
IllegalArgumentException
- if an unknown scope is givenScope.ROUTE_ALL_EDGES
setScope(Scope)
public boolean isCollinearBendsRemovalEnabled()
A collinear bend is a bend that lies on a common line with its predecessor bend and successor bend.
If an edge has a collinear bend, there is another edge which has a real bend at this point, i.e., the bend location is an intersection of the bus. Therefore, it may be advantageous for some applications to keep such bends.
true
. true
if collinear bends are removed, false
otherwisesetCollinearBendsRemovalEnabled(boolean)
public boolean isGridRoutingEnabled()
GridSpacing
.false
. Edges are freely routed.true
if edge segments are routed on a grid, false
otherwisesetGridRoutingEnabled(boolean)
public boolean isReroutingEnabled()
This features does not guarantee that the number of crossings will be the minimal.
0.0
is assigned to the
crossing cost
.false
. true
if the rerouting feature is enabled, false
otherwisesetCrossingCost(double)
,
setReroutingEnabled(boolean)
public void setAffectedEdgesDpKey(Object value)
IDataProvider
for marking edges as selected.
If the scope
is set to Scope.ROUTE_AFFECTED_EDGES
, only the edges for which the
registered IDataProvider
returns true
will be routed. All other edges will be considered to have fixed
routes.
IllegalArgumentException
- if the specified key is null
DEFAULT_AFFECTED_EDGES_DPKEY
value
- the IDataProvider
key for edge selectiongetAffectedEdgesDpKey()
public void setCollinearBendsRemovalEnabled(boolean value)
A collinear bend is a bend that lies on a common line with its predecessor bend and successor bend.
If an edge has a collinear bend, there is another edge which has a real bend at this point, i.e., the bend location is an intersection of the bus. Therefore, it may be advantageous for some applications to keep such bends.
true
. value
- true
if collinear bends are removed, false
otherwiseisCollinearBendsRemovalEnabled()
public void setCrossingCost(double value)
A cost value of n
means that it is more profitable for a path to change its direction n
times rather
than crossing the path of an edge. If the cost value is set to
0.0
, no global crossing optimization is performed.
The cost is defined to be a non-negative value.
IllegalArgumentException
- if the given cost value is negative1.0
and 3.0
.value
- the non-negative cost value for each crossinggetCrossingCost()
public void setGridRoutingEnabled(boolean value)
GridSpacing
.false
. Edges are freely routed.value
- true
if edge segments are routed on a grid, false
otherwiseisGridRoutingEnabled()
public void setGridSpacing(int value)
Positive values greater than 2
are allowed. Positive values less than 2
are ignored, while negative
values are mapped to their absolute value.
grid routing
is enabled.value
- the grid spacingsetGridRoutingEnabled(boolean)
,
getGridSpacing()
public void setMinimumBackboneSegmentLength(double value)
This number defines the minimum length of backbone segments which are computed by the backbone selection phase. Some of the final backbone segments may be shorter due to changes in the routing and recombination phase.
The minimum length is defined to be a value greater than or equal to 1.0
.
IllegalArgumentException
- if the given minimum length is smaller than 1.0
bounding box
.value
- the preferred minimum length of a backbone segmentgetMinimumBackboneSegmentLength()
public void setMinimumBusConnectionsCount(int value)
If a backbone segment has less connections, it is removed and the affected nodes connect to another backbone segment.
The minimum connection count must be a value greater than or equal to 1
.
IllegalArgumentException
- if the given minimum count is smaller than 1
3
or 4
is a good choice for small graphs. For larger graphs a much larger count can
be reasonable.value
- the minimum number of bus connections each backbone segment must havegetMinimumBusConnectionsCount()
public void setMinimumDistanceToEdge(int value)
The edge routing algorithm adheres to this value if possible, but reduces the distance value selectively, i.e., only for a currently processed edge, when there is not enough space to find a path with the proper value.
Positive values greater than 4
are allowed. Positive values less than 4
are ignored, while negative
values are mapped to their absolute values.
value
- the minimum distance between edgesgetMinimumDistanceToEdge()
public void setMinimumDistanceToNode(int value)
Positive values greater than 2
are allowed. Positive values less than 2
are ignored, while negative
values are mapped to their absolutes.
value
- the minimum distance between edges and nodesgetMinimumDistanceToNode()
public void setPreferredBackboneSegmentCount(int value)
This setting defines the number of backbone segments of the same orientation which are computed by the backbone selection phase. The final number of backbone segments may be different due to changes in the routing and recombination phase.
The number must be a value greater than or equal to 1
.
IllegalArgumentException
- if the given preferred number is smaller than 1
value
- the maximum number of backbone candidates with the same orientationgetPreferredBackboneSegmentCount()
public void setReroutingEnabled(boolean value)
This features does not guarantee that the number of crossings will be the minimal.
0.0
is assigned to the
crossing cost
.false
. value
- true
if the rerouting feature is enabled, false
otherwisesetCrossingCost(double)
,
isReroutingEnabled()
public void setScope(Scope value)
IllegalArgumentException
- if an unknown scope is givenScope.ROUTE_ALL_EDGES
value
- one of the predefined scope valuesgetScope()