Skip to content

Commit 26e2de7

Browse files
authored
[NAD] enrich metadata (#781)
* adds new node and edge attributes to the NAD's metadata * replaces boundary and threeWindings attributes with an optional type, in NodeMetadata * adds css class names * decouple style provider processing from SvgWriter and DiagramMetadata * fix expected test file Signed-off-by: Christian Biasuzzi <christian.biasuzzi@soft.it>
1 parent 7ba76e2 commit 26e2de7

36 files changed

Lines changed: 1579 additions & 323 deletions

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.powsybl.nad.build.iidm.VoltageLevelFilter;
1414
import com.powsybl.nad.layout.LayoutParameters;
1515
import com.powsybl.nad.model.Graph;
16+
import com.powsybl.nad.svg.StyleProvider;
1617
import com.powsybl.nad.svg.SvgParameters;
1718
import com.powsybl.nad.svg.SvgWriter;
1819
import com.powsybl.nad.svg.metadata.DiagramMetadata;
@@ -72,8 +73,10 @@ public static void draw(Network network, Path svgFile, NadParameters param, Pred
7273
Objects.requireNonNull(svgFile);
7374
Objects.requireNonNull(param);
7475

76+
StyleProvider styleProvider = param.getStyleProviderFactory().create(network);
7577
Graph graph = getLayoutResult(network, param, voltageLevelFilter);
76-
createSvgWriter(network, param).writeSvg(graph, svgFile);
78+
NetworkGraphBuilder.applyStyle(graph, styleProvider);
79+
createSvgWriter(param).writeSvg(graph, svgFile);
7780
createMetadata(graph, param).writeJson(getMetadataPath(svgFile));
7881
}
7982

@@ -83,8 +86,10 @@ public static void draw(Network network, Writer writer, Writer metadataWriter, N
8386
Objects.requireNonNull(metadataWriter);
8487
Objects.requireNonNull(param);
8588

89+
StyleProvider styleProvider = param.getStyleProviderFactory().create(network);
8690
Graph graph = getLayoutResult(network, param, voltageLevelFilter);
87-
createSvgWriter(network, param).writeSvg(graph, writer);
91+
NetworkGraphBuilder.applyStyle(graph, styleProvider);
92+
createSvgWriter(param).writeSvg(graph, writer);
8893
createMetadata(graph, param).writeJson(metadataWriter);
8994
}
9095

@@ -100,9 +105,9 @@ private static Graph getLayoutResult(Network network, NadParameters param, Predi
100105
return graph;
101106
}
102107

103-
private static SvgWriter createSvgWriter(Network network, NadParameters param) {
104-
return new SvgWriter(param.getSvgParameters(), param.getStyleProviderFactory().create(network),
105-
param.getComponentLibrary(), param.getEdgeRouting());
108+
private static SvgWriter createSvgWriter(NadParameters param) {
109+
return new SvgWriter(param.getSvgParameters(), param.getComponentLibrary(),
110+
param.getEdgeRouting());
106111
}
107112

108113
private static Path getMetadataPath(Path svgPath) {

network-area-diagram/src/main/java/com/powsybl/nad/build/iidm/NetworkGraphBuilder.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import com.powsybl.nad.svg.SvgParameters;
2626
import com.powsybl.nad.svg.VoltageLevelLegend;
2727
import com.powsybl.nad.svg.iidm.DefaultLabelProvider;
28+
import com.powsybl.nad.svg.StyleProvider;
29+
import com.powsybl.nad.model.EdgeStyleInfo;
2830
import com.powsybl.nad.utils.iidm.IidmUtils;
2931

3032
import java.util.*;
@@ -306,4 +308,65 @@ private ThreeSides[] getSidesArray(ThreeSides sideA) {
306308
private int getNextSideNum(int sideNum, int steps) {
307309
return (sideNum + steps + 2) % 3 + 1;
308310
}
311+
312+
public static void applyStyle(Graph graph, StyleProvider styleProvider) {
313+
Objects.requireNonNull(graph);
314+
Objects.requireNonNull(styleProvider);
315+
316+
graph.getVoltageLevelNodesStream().forEach(vlNode -> {
317+
vlNode.setStyleClasses(styleProvider.getNodeStyleClasses(vlNode));
318+
vlNode.setHighlightStyleClasses(styleProvider.getHighlightNodeStyleClasses(vlNode));
319+
});
320+
321+
// Bus nodes depend on bus index assigned during layout
322+
graph.getBusNodesStream().forEach(busNode -> {
323+
busNode.setStyleClasses(styleProvider.getBusNodeStyleClasses(busNode));
324+
busNode.setStyleClass(styleProvider.getBusNodeStyle(busNode));
325+
});
326+
327+
graph.getThreeWtNodesStream().forEach(tn ->
328+
tn.setStyleClasses(styleProvider.getNodeStyleClasses(tn)));
329+
330+
graph.getInjections().forEach(injection -> {
331+
injection.setStyleClasses(styleProvider.getInjectionStyleClasses(injection));
332+
injection.setStyleClass(styleProvider.getInjectionStyle(injection));
333+
injection.getSvgEdgeInfo().ifPresent(sei ->
334+
sei.edgeInfo().setStyleClassesAB(styleProvider::getEdgeInfoStyleClasses));
335+
});
336+
337+
graph.getBranchEdgeStream().forEach(edge -> {
338+
edge.setStyleClasses(styleProvider.getBranchEdgeStyleClasses(edge));
339+
edge.setEdgeStyleInfo1(new EdgeStyleInfo(
340+
styleProvider.getSideEdgeStyleClasses(edge, BranchEdge.Side.ONE),
341+
styleProvider.getSideEdgeStyle(edge, BranchEdge.Side.ONE),
342+
styleProvider.getHighlightSideEdgeStyleClasses(edge, BranchEdge.Side.ONE)));
343+
edge.setEdgeStyleInfo2(new EdgeStyleInfo(
344+
styleProvider.getSideEdgeStyleClasses(edge, BranchEdge.Side.TWO),
345+
styleProvider.getSideEdgeStyle(edge, BranchEdge.Side.TWO),
346+
styleProvider.getHighlightSideEdgeStyleClasses(edge, BranchEdge.Side.TWO)));
347+
edge.getSvgEdgeInfo(BranchEdge.Side.ONE).ifPresent(sei ->
348+
sei.edgeInfo().setStyleClassesAB(styleProvider::getEdgeInfoStyleClasses));
349+
edge.getSvgEdgeInfo(BranchEdge.Side.TWO).ifPresent(sei ->
350+
sei.edgeInfo().setStyleClassesAB(styleProvider::getEdgeInfoStyleClasses));
351+
edge.getSvgEdgeInfoMiddle().ifPresent(sei ->
352+
sei.edgeInfo().setStyleClassesAB(styleProvider::getEdgeInfoStyleClasses));
353+
});
354+
355+
graph.getThreeWtEdgesStream().forEach(edge -> {
356+
edge.setEdgeStyleInfo(new EdgeStyleInfo(
357+
styleProvider.getThreeWtEdgeStyleClasses(edge),
358+
styleProvider.getThreeWtEdgeStyle(edge),
359+
styleProvider.getHighlightThreeWtEdgStyleClasses(edge)));
360+
edge.getSvgEdgeInfo().ifPresent(sei ->
361+
sei.edgeInfo().setStyleClassesAB(styleProvider::getEdgeInfoStyleClasses));
362+
});
363+
364+
graph.setUnknownBusStyleClasses(styleProvider.getBusNodeStyleClasses(BusNode.UNKNOWN));
365+
graph.setUnknownBusStyle(styleProvider.getBusNodeStyle(BusNode.UNKNOWN));
366+
367+
graph.setCssUrls(styleProvider.getCssUrls());
368+
graph.setCssFilenames(styleProvider.getCssFilenames());
369+
370+
graph.setStyleApplied();
371+
}
309372
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
*/
77
package com.powsybl.nad.model;
88

9+
import java.util.List;
10+
911
/**
1012
* @author Florian Dupuy {@literal <florian.dupuy at rte-france.com>}
1113
*/
@@ -69,4 +71,8 @@ public int getHeight() {
6971
public void setHeight(int height) {
7072
this.height = height;
7173
}
74+
75+
public List<String> getStyleClasses() {
76+
return List.of();
77+
}
7278
}

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ public int getNum() {
4848
private final SvgEdgeInfo svgEdgeInfo2;
4949
private final SvgEdgeInfo svgEdgeInfoMiddle;
5050

51+
private List<String> styleClasses = Collections.emptyList();
52+
private EdgeStyleInfo edgeStyleInfo1;
53+
private EdgeStyleInfo edgeStyleInfo2;
54+
5155
public BranchEdge(IdProvider idProvider, String equipmentId, String nameOrId, String type,
5256
EdgeInfo edgeInfo1, EdgeInfo edgeInfo2, EdgeInfo edgeInfoMiddle) {
5357
super(idProvider.createSvgId(equipmentId), equipmentId, nameOrId, type);
@@ -172,4 +176,33 @@ public Optional<SvgEdgeInfo> getSvgEdgeInfoMiddle() {
172176
private static boolean isEdgeInfoNotEmptyNorNull(EdgeInfo edgeInfo) {
173177
return edgeInfo != null && (edgeInfo.getInfoTypeB() != null || edgeInfo.getInfoTypeA() != null);
174178
}
179+
180+
public List<String> getStyleClasses() {
181+
return styleClasses;
182+
}
183+
184+
public void setStyleClasses(List<String> styleClasses) {
185+
this.styleClasses = styleClasses;
186+
}
187+
188+
public EdgeStyleInfo getEdgeStyleInfo1() {
189+
return edgeStyleInfo1;
190+
}
191+
192+
public void setEdgeStyleInfo1(EdgeStyleInfo edgeStyleInfo1) {
193+
this.edgeStyleInfo1 = edgeStyleInfo1;
194+
}
195+
196+
public EdgeStyleInfo getEdgeStyleInfo2() {
197+
return edgeStyleInfo2;
198+
}
199+
200+
public void setEdgeStyleInfo2(EdgeStyleInfo edgeStyleInfo2) {
201+
this.edgeStyleInfo2 = edgeStyleInfo2;
202+
}
203+
204+
public EdgeStyleInfo getEdgeStyleInfo(Side side) {
205+
Objects.requireNonNull(side);
206+
return side == Side.ONE ? edgeStyleInfo1 : edgeStyleInfo2;
207+
}
175208
}

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ public class BusNode extends AbstractNode {
2525
private int nbNeighbouringBusNodes;
2626
private final List<Injection> injections = new ArrayList<>();
2727
private final String legend;
28+
private List<String> styleClasses = Collections.emptyList();
29+
private String styleClass;
2830

2931
public BusNode(IdProvider idProvider, String id, List<Injection> injections, String legend) {
3032
this(idProvider.createSvgId(id), id, injections, legend);
@@ -71,5 +73,22 @@ public List<Injection> getInjections() {
7173
public String getLegend() {
7274
return legend;
7375
}
76+
77+
@Override
78+
public List<String> getStyleClasses() {
79+
return styleClasses;
80+
}
81+
82+
public void setStyleClasses(List<String> styleClasses) {
83+
this.styleClasses = styleClasses;
84+
}
85+
86+
public String getStyleClass() {
87+
return styleClass;
88+
}
89+
90+
public void setStyleClass(String styleClass) {
91+
this.styleClass = styleClass;
92+
}
7493
}
7594

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (c) 2026, RTE (http://www.rte-france.com)
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
* SPDX-License-Identifier: MPL-2.0
7+
*/
8+
package com.powsybl.nad.model;
9+
10+
import java.util.Collections;
11+
import java.util.List;
12+
13+
/**
14+
* @author Christian Biasuzzi {@literal <christian.biasuzzi at soft.it>}
15+
*/
16+
public record EdgeStyleInfo(List<String> styleClasses, String styleClass, List<String> highlightStyleClasses) {
17+
18+
public EdgeStyleInfo(List<String> styleClasses, String styleClass) {
19+
this(styleClasses, styleClass, Collections.emptyList());
20+
}
21+
}

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.jgrapht.graph.Pseudograph;
1111
import org.jgrapht.graph.WeightedPseudograph;
1212

13+
import java.net.URL;
1314
import java.util.*;
1415
import java.util.stream.Collectors;
1516
import java.util.stream.Stream;
@@ -32,6 +33,14 @@ public class Graph {
3233
private final org.jgrapht.Graph<Node, Edge> busGraph = new Pseudograph<>(Edge.class);
3334
private final Map<TextEdge, Pair<VoltageLevelNode, TextNode>> textEdges = new LinkedHashMap<>();
3435

36+
private List<URL> cssUrls;
37+
private List<String> cssFilenames;
38+
39+
private List<String> unknownBusStyleClasses = Collections.emptyList();
40+
private String unknownBusStyle;
41+
42+
private boolean styleApplied = false;
43+
3544
public void addNode(Node node) {
3645
Objects.requireNonNull(node);
3746
nodes.put(node.getEquipmentId(), node);
@@ -327,4 +336,44 @@ public Map<String, Point> getNodePositions() {
327336
VoltageLevelNode::getPosition
328337
));
329338
}
339+
340+
public List<URL> getCssUrls() {
341+
return cssUrls;
342+
}
343+
344+
public void setCssUrls(List<URL> cssUrls) {
345+
this.cssUrls = cssUrls;
346+
}
347+
348+
public List<String> getCssFilenames() {
349+
return cssFilenames;
350+
}
351+
352+
public void setCssFilenames(List<String> cssFilenames) {
353+
this.cssFilenames = cssFilenames;
354+
}
355+
356+
public List<String> getUnknownBusStyleClasses() {
357+
return unknownBusStyleClasses;
358+
}
359+
360+
public void setUnknownBusStyleClasses(List<String> unknownBusStyleClasses) {
361+
this.unknownBusStyleClasses = unknownBusStyleClasses;
362+
}
363+
364+
public String getUnknownBusStyle() {
365+
return unknownBusStyle;
366+
}
367+
368+
public void setUnknownBusStyle(String unknownBusStyle) {
369+
this.unknownBusStyle = unknownBusStyle;
370+
}
371+
372+
public void setStyleApplied() {
373+
this.styleApplied = true;
374+
}
375+
376+
public boolean isStyleApplied() {
377+
return styleApplied;
378+
}
330379
}

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.powsybl.nad.svg.EdgeInfo;
1212
import com.powsybl.nad.svg.SvgEdgeInfo;
1313

14+
import java.util.Collections;
1415
import java.util.List;
1516
import java.util.Optional;
1617

@@ -36,6 +37,8 @@ public enum Type {
3637
private Point busNodePoint;
3738
private Point arrowPoint;
3839
private final SvgEdgeInfo svgEdgeInfo;
40+
private List<String> styleClasses = Collections.emptyList();
41+
private String styleClass;
3942

4043
public Injection(IdProvider idProvider, String equipmentId, String nameOrId, Type type, EdgeInfo edgeInfo) {
4144
super(idProvider.createSvgId(equipmentId), equipmentId, nameOrId);
@@ -93,4 +96,20 @@ public Point getIconOrigin(double circleRadius) {
9396
public Optional<SvgEdgeInfo> getSvgEdgeInfo() {
9497
return Optional.ofNullable(svgEdgeInfo);
9598
}
99+
100+
public List<String> getStyleClasses() {
101+
return styleClasses;
102+
}
103+
104+
public void setStyleClasses(List<String> styleClasses) {
105+
this.styleClasses = styleClasses;
106+
}
107+
108+
public String getStyleClass() {
109+
return styleClass;
110+
}
111+
112+
public void setStyleClass(String styleClass) {
113+
this.styleClass = styleClass;
114+
}
96115
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
*/
77
package com.powsybl.nad.model;
88

9+
import java.util.List;
10+
911
/**
1012
* @author Florian Dupuy {@literal <florian.dupuy at rte-france.com>}
1113
*/
@@ -22,4 +24,6 @@ public interface Node extends Identifiable {
2224
double getY();
2325

2426
boolean isFictitious();
27+
28+
List<String> getStyleClasses();
2529
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ public enum Side {
3333
private final boolean visible;
3434
private final SvgEdgeInfo svgEdgeInfo;
3535

36+
private EdgeStyleInfo edgeStyleInfo = new EdgeStyleInfo(Collections.emptyList(), null);
37+
3638
public ThreeWtEdge(IdProvider idProvider, String equipmentId, String transformerName, Side side, String type, boolean visible, EdgeInfo edgeInfo) {
3739
super(idProvider.createSvgId(equipmentId), equipmentId, transformerName, type);
3840
this.side = side;
@@ -71,4 +73,12 @@ public double getEdgeAngle() {
7173
public Optional<SvgEdgeInfo> getSvgEdgeInfo() {
7274
return Optional.ofNullable(svgEdgeInfo);
7375
}
76+
77+
public EdgeStyleInfo getEdgeStyleInfo() {
78+
return edgeStyleInfo;
79+
}
80+
81+
public void setEdgeStyleInfo(EdgeStyleInfo edgeStyleInfo) {
82+
this.edgeStyleInfo = edgeStyleInfo;
83+
}
7484
}

0 commit comments

Comments
 (0)