-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Radial layout, rotation extensions. (#945)
* Adds options to control the rotation of radial layouts. Particularly with top-down layout. * Updated documentation and refactoring * update copyright dates
- Loading branch information
Showing
9 changed files
with
284 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
...lipse.elk.alg.radial/src/org/eclipse/elk/alg/radial/intermediate/EdgeAngleCalculator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2023 Kiel University and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*******************************************************************************/ | ||
package org.eclipse.elk.alg.radial.intermediate; | ||
|
||
import org.eclipse.elk.alg.radial.InternalProperties; | ||
import org.eclipse.elk.alg.radial.options.RadialOptions; | ||
import org.eclipse.elk.core.alg.ILayoutProcessor; | ||
import org.eclipse.elk.core.math.KVector; | ||
import org.eclipse.elk.core.util.IElkProgressMonitor; | ||
import org.eclipse.elk.graph.ElkEdge; | ||
import org.eclipse.elk.graph.ElkNode; | ||
|
||
/** | ||
* Calculates the angles of outgoing edges so that they can be used as an input by subsequent child | ||
* layouts. Only makes sense when used in a top-down layout. | ||
* | ||
*/ | ||
public class EdgeAngleCalculator implements ILayoutProcessor<ElkNode> { | ||
|
||
/** | ||
* For each of edges connected to the root node we calculate its angle and store that information on the | ||
* connected target node. This node can then later use that information as basis to align its own layout | ||
* to the incoming edge. Because this sets an option on child nodes, this is only useful when laying the | ||
* graph out in a top-down manner (or possibly in multiple layout runs). | ||
*/ | ||
@Override | ||
public void process(ElkNode graph, IElkProgressMonitor progressMonitor) { | ||
|
||
ElkNode root = graph.getProperty(InternalProperties.ROOT_NODE); | ||
for (ElkEdge edge : root.getOutgoingEdges()) { | ||
|
||
KVector start = new KVector(edge.getSections().get(0).getStartX(), edge.getSections().get(0).getStartY()); | ||
KVector end = new KVector(edge.getSections().get(0).getEndX(), edge.getSections().get(0).getEndY()); | ||
|
||
KVector edgeVector = KVector.diff(end, start); | ||
double angle = Math.atan2(edgeVector.y, edgeVector.x); | ||
|
||
edge.getTargets().get(0).setProperty(RadialOptions.ROTATION_TARGET_ANGLE, angle); | ||
} | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
...se.elk.alg.radial/src/org/eclipse/elk/alg/radial/intermediate/rotation/AngleRotation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2023 Kiel University and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*******************************************************************************/ | ||
package org.eclipse.elk.alg.radial.intermediate.rotation; | ||
|
||
import org.eclipse.elk.alg.radial.InternalProperties; | ||
import org.eclipse.elk.alg.radial.options.RadialOptions; | ||
import org.eclipse.elk.core.math.KVector; | ||
import org.eclipse.elk.graph.ElkNode; | ||
|
||
/** | ||
* Rotates the entire layout around the origin to a set target angle. | ||
* | ||
*/ | ||
public class AngleRotation implements IRadialRotator { | ||
|
||
@Override | ||
public void rotate(ElkNode graph) { | ||
double targetAngle = graph.getProperty(RadialOptions.ROTATION_TARGET_ANGLE); | ||
|
||
if (graph.getProperty(RadialOptions.ROTATION_COMPUTE_ADDITIONAL_WEDGE_SPACE)) { | ||
// Using the target angle as our base alignment we want to further rotate the layout such that a line | ||
// following the target angle runs directly through the middle of the wedge between the first and last node. | ||
ElkNode root = graph.getProperty(InternalProperties.ROOT_NODE); | ||
|
||
ElkNode lastNode = (ElkNode) root.getOutgoingEdges().get(root.getOutgoingEdges().size() - 1).getTargets().get(0); | ||
ElkNode firstNode = (ElkNode) root.getOutgoingEdges().get(0).getTargets().get(0); | ||
KVector lastVector = new KVector(lastNode.getX() + lastNode.getWidth() / 2, lastNode.getY() + lastNode.getHeight() / 2); | ||
KVector firstVector = new KVector(firstNode.getX() + firstNode.getWidth() / 2, firstNode.getY() + firstNode.getHeight() / 2); | ||
|
||
// we shift all angles into the range (0,pi] to avoid dealing with negative angles. | ||
double alpha = targetAngle; | ||
if (alpha <= 0) { | ||
alpha += 2*Math.PI; | ||
} | ||
|
||
double wedgeAngle = lastVector.angle(firstVector); | ||
if (wedgeAngle <= 0) { | ||
wedgeAngle += 2*Math.PI; | ||
} | ||
|
||
double alignmentAngle = Math.atan2(lastVector.y, lastVector.x); | ||
if (alignmentAngle <= 0) { | ||
alignmentAngle += 2*Math.PI; | ||
} | ||
|
||
// alpha (originally targetAngle) is the angle of the incoming edge that we wish to align ourselves with. | ||
// wedgeAngle is the angle between the first and last nodes of our own layout. For the case of a single | ||
// node this is 360 degrees. | ||
// alignmentAngle is the angle of the vector pointing to the last node i.e. the end part of the segment | ||
// we rotate the entire layout by subtracting the incoming angle alpha and we add half the wedge angle back | ||
// to make the alignment go through the center of the wedge. Finally, we need to do a transformation to | ||
// make all this work in our downward facing coordinate system. So everything is inverted and we need subtract | ||
// the result from 180 degrees. | ||
targetAngle = Math.PI - (alignmentAngle - alpha + wedgeAngle / 2); | ||
|
||
} | ||
|
||
// rotate all nodes around the origin, because the root node is positioned at the origin | ||
// nodes are positioned with their center on the radius so use that for the rotation | ||
for (ElkNode node : graph.getChildren()) { | ||
KVector pos = new KVector(node.getX() + node.getWidth() / 2, node.getY() + node.getHeight() / 2); | ||
pos.rotate(targetAngle); | ||
node.setLocation(pos.x - node.getWidth() / 2, pos.y - node.getHeight() / 2); | ||
} | ||
|
||
} | ||
|
||
} |
39 changes: 39 additions & 0 deletions
39
...e.elk.alg.radial/src/org/eclipse/elk/alg/radial/intermediate/rotation/GeneralRotator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2023 Kiel University and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*******************************************************************************/ | ||
package org.eclipse.elk.alg.radial.intermediate.rotation; | ||
|
||
import org.eclipse.elk.core.alg.ILayoutProcessor; | ||
import org.eclipse.elk.core.util.IElkProgressMonitor; | ||
import org.eclipse.elk.graph.ElkNode; | ||
|
||
/** | ||
* The layout processor for rotation. Sets up logging and calls the angle rotation implementation. | ||
* | ||
*/ | ||
public class GeneralRotator implements ILayoutProcessor<ElkNode> { | ||
|
||
@Override | ||
public void process(final ElkNode graph, final IElkProgressMonitor progressMonitor) { | ||
progressMonitor.begin("General 'Rotator", 1); | ||
// elkjs-exclude-start | ||
if (progressMonitor.isLoggingEnabled()) { | ||
progressMonitor.logGraph(graph, "Before"); | ||
} | ||
// elkjs-exclude-end | ||
IRadialRotator rotator = new AngleRotation(); | ||
rotator.rotate(graph); | ||
// elkjs-exclude-start | ||
if (progressMonitor.isLoggingEnabled()) { | ||
progressMonitor.logGraph(graph, "After"); | ||
} | ||
// elkjs-exclude-end | ||
} | ||
|
||
} |
28 changes: 28 additions & 0 deletions
28
...e.elk.alg.radial/src/org/eclipse/elk/alg/radial/intermediate/rotation/IRadialRotator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2023 Kiel University and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*******************************************************************************/ | ||
package org.eclipse.elk.alg.radial.intermediate.rotation; | ||
|
||
import org.eclipse.elk.graph.ElkNode; | ||
|
||
/** | ||
* An interface for rotating the radial layout. | ||
* | ||
*/ | ||
public interface IRadialRotator { | ||
|
||
/** | ||
* Rotate the graph. | ||
* | ||
* @param graph | ||
* The graph which is already radial. | ||
*/ | ||
void rotate(ElkNode graph); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters