Skip to content

Commit 652e226

Browse files
authored
[NAD] Edge routing (#714)
* Introduce EdgeRouting and CustomPathsRouting * Add unit test and fixes * Fix direction start * Fix text-edge style * Compute text edge points at once instead of shifting it in SvgWriter * Fix code smells * Add missing Objects.requireNonNull * Compute arrow point and angle in EdgeRouting * Add documentation * Fix code smells * Rename CustomPathsRouting -> CustomPathRouting * Create RadiusUtils replacing public static methods of SvgWriter * Fixes --------- Signed-off-by: Florian Dupuy <florian.dupuy@rte-france.com>
1 parent 6958116 commit 652e226

File tree

83 files changed

+1452
-237
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+1452
-237
lines changed

docs/_static/img/nad/3wt-edges.png

24.7 KB
Loading
23.1 KB
Loading
30.8 KB
Loading
36.5 KB
Loading
36.8 KB
Loading
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Edge Routing
2+
3+
The `EdgeRouting` interface provides a way to customize the computation of paths of the network-area diagram.
4+
The chosen edge routing can be specified through `NadParameters::setEdgeRouting`.
5+
Note that, internally, the edge routing is passed to the `SvgWriter` which launches the computation.
6+
7+
Currently, there are 2 implementations of the `EdgeRouting`: the `StraightEdgeRouting` and the `CustomPathRouting`.
8+
The default implementation if none specified is the `StraightEdgeRouting`.
9+
10+
## Common features
11+
The common features are factorized in the abstract class `AbstractEdgeRouting`.
12+
13+
### Loops
14+
The loop edges points are computed so that they are distributed between branch edges when the space available is big enough.
15+
16+
![loops](/_static/img/nad/loops-distribution.png)
17+
18+
### Injections
19+
If injections are displayed, the injection edge points are computed similarly to loops: they are distributed between branch edges when the space available is big enough.
20+
21+
![injections](/_static/img/nad/injections-distribution.png)
22+
23+
### Three-winding transformers
24+
The three-winding edge points are computed by finding a "leading" transformer edge and then placing the other edges at 120°.
25+
The leading edge is defined as the opposite edge of the smallest aperture.
26+
27+
![3WTedges](/_static/img/nad/3wt-edges.png)
28+
29+
## StraightEdgeRouting feature
30+
In the `StraightEdgeRouting` implementation,
31+
- the parallel edges points are computed so that they form a fork,
32+
- the other edges points are computed as straight lines.
33+
34+
![forkstraight](/_static/img/nad/fork-straight.png)
35+
36+
## CustomPathRouting feature
37+
In the `CustomPathRouting` implementation, custom paths can be provided through two maps in the constructor
38+
- a map whose keys are branch ids and whose values are the list of "bending" points to add to the corresponding branch edge,
39+
- a map whose keys are voltage level ids and whose values are the list of "bending" points to add to the corresponding text edge.
40+
41+
If a branch id is missing in the given map, we fall back to `StraightEdgeRouting` implementation.
42+
Similarly for text edges, if a voltage level id is missing in the corresponding map, we fall back to `StraightEdgeRouting` implementation.
43+
44+
![custompaths](/_static/img/nad/custom-paths.png)

docs/network_area_diagrams/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ hidden: true
1010
layout/layout.md
1111
labelProvider/labelProvider.md
1212
styleProvider/styleProvider.md
13+
edgeRouting/edgeRouting.md
1314
```
1415

1516

@@ -21,6 +22,7 @@ The powsybl-network-area-diagram artifact provides features to generate concise
2122
- Possible use of your own graph layout implementation;
2223
- Possible use of your own label provider to display custom directed values on the graph edges (default label provider displays the active power);
2324
- Possible use of your own style provider to have a custom style for nodes and edges (default style provider gives the nodes and edges a class corresponding to their voltage level and gives disconnected lines a specific class);
25+
- Possible use of your own edge routing to have custom edge paths;
2426
- Possible use of your custom layout parameters and svg rendering parameters.
2527

2628
![nad-example](/_static/img/nad/nad-example.png)

network-area-diagram/src/main/java/com/powsybl/nad/NadParameters.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import com.powsybl.nad.layout.LayoutParameters;
1515
import com.powsybl.nad.library.DefaultComponentLibrary;
1616
import com.powsybl.nad.library.NadComponentLibrary;
17+
import com.powsybl.nad.routing.StraightEdgeRouting;
18+
import com.powsybl.nad.routing.EdgeRouting;
1719
import com.powsybl.nad.svg.LabelProvider;
1820
import com.powsybl.nad.svg.SvgParameters;
1921
import com.powsybl.nad.svg.iidm.*;
@@ -33,6 +35,7 @@ public class NadParameters {
3335
private LayoutFactory layoutFactory = new BasicForceLayoutFactory();
3436
private IdProviderFactory idProviderFactory = IntIdProvider::new;
3537
private NadComponentLibrary componentLibrary = new DefaultComponentLibrary();
38+
private EdgeRouting edgeRouting = new StraightEdgeRouting();
3639

3740
public SvgParameters getSvgParameters() {
3841
return svgParameters;
@@ -96,4 +99,13 @@ public NadParameters setComponentLibrary(NadComponentLibrary componentLibrary) {
9699
this.componentLibrary = componentLibrary;
97100
return this;
98101
}
102+
103+
public EdgeRouting getEdgeRouting() {
104+
return edgeRouting;
105+
}
106+
107+
public NadParameters setEdgeRouting(EdgeRouting edgeRouting) {
108+
this.edgeRouting = edgeRouting;
109+
return this;
110+
}
99111
}

network-area-diagram/src/main/java/com/powsybl/nad/NetworkAreaDiagram.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ private static Graph getLayoutResult(Network network, NadParameters param, Predi
103103

104104
private static SvgWriter createSvgWriter(Network network, NadParameters param) {
105105
return new SvgWriter(param.getSvgParameters(), param.getStyleProviderFactory().create(network),
106-
param.createLabelProvider(network), param.getComponentLibrary());
106+
param.createLabelProvider(network), param.getComponentLibrary(), param.getEdgeRouting());
107107
}
108108

109109
private static Path getMetadataPath(Path svgPath) {

network-area-diagram/src/main/java/com/powsybl/nad/model/BranchEdge.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ public int getNum() {
3737

3838
private List<Point> points1 = Collections.emptyList();
3939
private List<Point> points2 = Collections.emptyList();
40+
private Point arrowPoint1 = new Point();
41+
private Point arrowPoint2 = new Point();
42+
private double arrowAngle1;
43+
private double arrowAngle2;
4044
private final boolean[] visible = new boolean[] {true, true};
4145

4246
public BranchEdge(String diagramId, String equipmentId, String nameOrId, String type) {
@@ -79,6 +83,50 @@ public void setPoints2(Point... points) {
7983
this.points2 = Arrays.asList(points);
8084
}
8185

86+
public Point getArrow(Side side) {
87+
Objects.requireNonNull(side);
88+
return side == Side.ONE ? getArrowPoint1() : getArrowPoint2();
89+
}
90+
91+
public Point getArrowPoint1() {
92+
return arrowPoint1;
93+
}
94+
95+
public Point getArrowPoint2() {
96+
return arrowPoint2;
97+
}
98+
99+
public void setArrow(Side side, Point arrow) {
100+
Objects.requireNonNull(side);
101+
if (side == Side.ONE) {
102+
setArrowPoint1(arrow);
103+
} else {
104+
setArrowPoint2(arrow);
105+
}
106+
}
107+
108+
public void setArrowPoint1(Point arrowPoint1) {
109+
this.arrowPoint1 = arrowPoint1;
110+
}
111+
112+
public void setArrowPoint2(Point arrowPoint2) {
113+
this.arrowPoint2 = arrowPoint2;
114+
}
115+
116+
public void setArrowAngle(Side side, double edgeStartAngle) {
117+
Objects.requireNonNull(side);
118+
if (side == Side.ONE) {
119+
this.arrowAngle1 = edgeStartAngle;
120+
} else {
121+
this.arrowAngle2 = edgeStartAngle;
122+
}
123+
}
124+
125+
public double getArrowAngle(Side side) {
126+
Objects.requireNonNull(side);
127+
return side == Side.ONE ? arrowAngle1 : arrowAngle2;
128+
}
129+
82130
public boolean isVisible(Side side) {
83131
Objects.requireNonNull(side);
84132
return visible[side.ordinal()];

0 commit comments

Comments
 (0)