Skip to content
Open

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2026, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.sld.svg;

import java.util.HashMap;
import java.util.Map;

/**
* @author Florian Dupuy {@literal <florian.dupuy at rte-france.com>}
*/
public class DefaultIdProvider implements IdProvider {

private final String prefixId;
private final Map<String, String> idMap = new HashMap<>();
private int count;

public DefaultIdProvider(String prefixId) {
this.prefixId = prefixId;
this.count = 0;
}

@Override
public String getOrCreateSvgId(String equipmentId) {
return getOrCreateId("equipmentId_" + equipmentId);
}

@Override
public String getOrCreateSvgId(String equipmentId, String subType) {
return getOrCreateId(String.format("equipmentId_%s_subType_%s", equipmentId, subType));
}

@Override
public String getOrCreateSvgId(String containerId, String id1, String id2) {
return getOrCreateId(String.format("containerId_%s_id1_%s_id2_%s", containerId, id1, id2));
}

private String getOrCreateId(String key) {
return idMap.computeIfAbsent(key, ignored -> prefixId + count++);
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2026, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.sld.svg;

/**
* @author Florian Dupuy {@literal <florian.dupuy at rte-france.com>}
*/
public interface IdProvider {

String getOrCreateSvgId(String equipmentId);

String getOrCreateSvgId(String equipmentId, String subType);

String getOrCreateSvgId(String containerId, String id1, String id2);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2026, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.sld.svg;

import com.powsybl.sld.util.IdUtil;

import java.util.HashMap;
import java.util.Map;

/**
* @author Florian Dupuy {@literal <florian.dupuy at rte-france.com>}
*/
public class LegacyIdProvider implements IdProvider {

private final String prefixId;
private final Map<String, String> idMap = new HashMap<>();

public LegacyIdProvider(String prefixId) {
this.prefixId = prefixId;
}

@Override
public String getOrCreateSvgId(String equipmentId) {
return idMap.computeIfAbsent(prefixId + equipmentId, IdUtil::escapeId);
}

@Override
public String getOrCreateSvgId(String equipmentId, String subType) {
return idMap.computeIfAbsent(prefixId + equipmentId + "_" + subType, IdUtil::escapeId);
}

@Override
public String getOrCreateSvgId(String containerId, String id1, String id2) {
// For global unicity in all type of container (voltage level, substation, zone), we prefix with the container Id and
// we rely on the fact that node ids are unique inside a voltage level. We also prepend with a custom prefix id to
// allow multiple diagrams unicity.
return idMap.computeIfAbsent(prefixId + "_" + containerId + "_" + id1 + "_" + id2, IdUtil::escapeClassName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
import com.powsybl.sld.model.graphs.Graph;
import com.powsybl.sld.model.graphs.SubstationGraph;
import com.powsybl.sld.model.graphs.VoltageLevelGraph;
import com.powsybl.sld.svg.IdProvider;
import com.powsybl.sld.svg.LabelProvider;
import com.powsybl.sld.svg.LegacyIdProvider;
import com.powsybl.sld.svg.SVGLegendWriter;
import com.powsybl.sld.svg.SvgParameters;
import com.powsybl.sld.svg.styles.StyleProvider;
Expand Down Expand Up @@ -115,10 +117,22 @@ protected void overrideTestReference(String filename, StringWriter content) {

public abstract String toSVG(Graph g, String filename);

public String toSVG(Graph graph, String filename, SldComponentLibrary componentLibrary, LayoutParameters layoutParameters, SvgParameters svgParameters, LabelProvider labelProvider, StyleProvider styleProvider, SVGLegendWriter legendWriter) {
public String toSVG(Graph graph, String filename, SldComponentLibrary componentLibrary,
LayoutParameters layoutParameters, SvgParameters svgParameters,
LabelProvider labelProvider, StyleProvider styleProvider,
SVGLegendWriter legendWriter) {
return toSVG(graph, filename, componentLibrary, layoutParameters, svgParameters, labelProvider, styleProvider,
new LegacyIdProvider(svgParameters.getPrefixId()), legendWriter);
}

public String toSVG(Graph graph, String filename, SldComponentLibrary componentLibrary,
LayoutParameters layoutParameters, SvgParameters svgParameters,
LabelProvider labelProvider, StyleProvider styleProvider, IdProvider idProvider,
SVGLegendWriter legendWriter) {

try (StringWriter writer = new StringWriter()) {
SingleLineDiagram.draw(graph, writer, NullWriter.nullWriter(), componentLibrary, layoutParameters, svgParameters, labelProvider, styleProvider, legendWriter);
SingleLineDiagram.draw(graph, writer, NullWriter.nullWriter(), componentLibrary, layoutParameters,
svgParameters, labelProvider, styleProvider, idProvider, legendWriter);

if (debugSvgFiles) {
writeToFileInDebugDir(filename, writer);
Expand All @@ -135,11 +149,23 @@ public String toSVG(Graph graph, String filename, SldComponentLibrary componentL

public abstract String toMetadata(Graph g, String filename);

public String toMetadata(Graph graph, String refMetadataName, SldComponentLibrary componentLibrary, LayoutParameters layoutParameters, SvgParameters svgParameters, LabelProvider labelProvider, StyleProvider styleProvider, SVGLegendWriter legendWriter) {
public String toMetadata(Graph graph, String refMetadataName, SldComponentLibrary componentLibrary,
LayoutParameters layoutParameters, SvgParameters svgParameters,
LabelProvider labelProvider, StyleProvider styleProvider,
SVGLegendWriter legendWriter) {
return toMetadata(graph, refMetadataName, componentLibrary, layoutParameters, svgParameters, labelProvider,
styleProvider, new LegacyIdProvider(svgParameters.getPrefixId()), legendWriter);
}

public String toMetadata(Graph graph, String refMetadataName, SldComponentLibrary componentLibrary,
LayoutParameters layoutParameters, SvgParameters svgParameters,
LabelProvider labelProvider, StyleProvider styleProvider, IdProvider idProvider,
SVGLegendWriter legendWriter) {
try (StringWriter writer = new StringWriter();
StringWriter metadataWriter = new StringWriter()) {

SingleLineDiagram.draw(graph, writer, metadataWriter, componentLibrary, layoutParameters, svgParameters, labelProvider, styleProvider, legendWriter);
SingleLineDiagram.draw(graph, writer, metadataWriter, componentLibrary, layoutParameters, svgParameters,
labelProvider, styleProvider, idProvider, legendWriter);

if (debugJsonFiles) {
writeToFileInDebugDir(refMetadataName, metadataWriter);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* Copyright (c) 2026, RTE (https://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.sld;

import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import com.powsybl.diagram.test.Networks;
import com.powsybl.iidm.network.Network;
import com.powsybl.sld.iidm.AbstractTestCaseIidm;
import com.powsybl.sld.svg.LegacyIdProvider;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.StringWriter;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* @author Nicolas Rol {@literal <nicolas.rol at rte-france.com>}
*/
class SingleLineDiagramTest extends AbstractTestCaseIidm {

private FileSystem fileSystem;
protected Path tempDirectory;
private Network network;
private Path svgPath;
private final SldParameters sldParameters = new SldParameters();

@Override
@BeforeEach
public void setUp() throws IOException {
network = Networks.createNetworkWithTieLineInVoltageLevel();
fileSystem = Jimfs.newFileSystem(Configuration.unix());
tempDirectory = fileSystem.getPath("/tmp");
Files.createDirectory(tempDirectory);
svgPath = tempDirectory.resolve("test.svg");
sldParameters.getSvgParameters().setPrefixId("Test");
}

@AfterEach
void tearDown() throws IOException {
fileSystem.close();
}

@Test
void testDraw() throws IOException {
SingleLineDiagram.draw(network, "VL1", svgPath);
assertEquals(toString("/TestDrawVL1PrefixEmpty.svg"), normalizeLineSeparator(toString(Files.newInputStream(svgPath))));

SingleLineDiagram.draw(network, "VL1", svgPath, new LegacyIdProvider("Legacy"));
assertEquals(toString("/TestDrawVL1PrefixLegacy.svg"), normalizeLineSeparator(toString(Files.newInputStream(svgPath))));

try (StringWriter writer = new StringWriter()) {
SingleLineDiagram.draw(network, "VL1", writer, new StringWriter());
assertEquals(toString("/TestDrawVL1PrefixEmpty.svg"), normalizeLineSeparator(writer.toString()));
}

try (StringWriter writer = new StringWriter()) {
SingleLineDiagram.draw(network, "VL1", writer, new StringWriter(), new LegacyIdProvider("Legacy"));
assertEquals(toString("/TestDrawVL1PrefixLegacy.svg"), normalizeLineSeparator(writer.toString()));
}

SingleLineDiagram.draw(network, "VL1", svgPath, sldParameters);
assertEquals(toString("/TestDrawVL1PrefixTest.svg"), normalizeLineSeparator(toString(Files.newInputStream(svgPath))));

SingleLineDiagram.draw(network, "VL1", svgPath, sldParameters, new LegacyIdProvider("Legacy"));
assertEquals(toString("/TestDrawVL1PrefixLegacy.svg"), normalizeLineSeparator(toString(Files.newInputStream(svgPath))));

try (StringWriter writer = new StringWriter()) {
SingleLineDiagram.draw(network, "VL1", writer, new StringWriter(), sldParameters);
assertEquals(toString("/TestDrawVL1PrefixTest.svg"), normalizeLineSeparator(writer.toString()));
}

try (StringWriter writer = new StringWriter()) {
SingleLineDiagram.draw(network, "VL1", writer, new StringWriter(), sldParameters, new LegacyIdProvider("Legacy"));
assertEquals(toString("/TestDrawVL1PrefixLegacy.svg"), normalizeLineSeparator(writer.toString()));
}
}

@Test
void testDrawVoltageLevel() throws IOException {
SingleLineDiagram.drawVoltageLevel(network, "VL1", svgPath);
assertEquals(toString("/TestDrawVL1PrefixEmpty.svg"), normalizeLineSeparator(toString(Files.newInputStream(svgPath))));

SingleLineDiagram.drawVoltageLevel(network, "VL1", svgPath, new LegacyIdProvider("Legacy"));
assertEquals(toString("/TestDrawVL1PrefixLegacy.svg"), normalizeLineSeparator(toString(Files.newInputStream(svgPath))));

try (StringWriter writer = new StringWriter()) {
SingleLineDiagram.drawVoltageLevel(network, "VL1", writer, new StringWriter(), sldParameters);
assertEquals(toString("/TestDrawVL1PrefixTest.svg"), normalizeLineSeparator(writer.toString()));
}

try (StringWriter writer = new StringWriter()) {
SingleLineDiagram.drawVoltageLevel(network, "VL1", writer, new StringWriter(), sldParameters, new LegacyIdProvider("Legacy"));
assertEquals(toString("/TestDrawVL1PrefixLegacy.svg"), normalizeLineSeparator(writer.toString()));
}
}

@Test
void testDrawSubstation() throws IOException {
SingleLineDiagram.drawSubstation(network, "S1", svgPath);
assertEquals(toString("/TestDrawS1PrefixEmpty.svg"), normalizeLineSeparator(toString(Files.newInputStream(svgPath))));

SingleLineDiagram.drawSubstation(network, "S1", svgPath, new LegacyIdProvider("Legacy"));
assertEquals(toString("/TestDrawS1PrefixLegacy.svg"), normalizeLineSeparator(toString(Files.newInputStream(svgPath))));

try (StringWriter writer = new StringWriter()) {
SingleLineDiagram.drawSubstation(network, "S1", writer, new StringWriter(), sldParameters);
assertEquals(toString("/TestDrawS1PrefixTest.svg"), normalizeLineSeparator(writer.toString()));
}

try (StringWriter writer = new StringWriter()) {
SingleLineDiagram.drawSubstation(network, "S1", writer, new StringWriter(), sldParameters, new LegacyIdProvider("Legacy"));
assertEquals(toString("/TestDrawS1PrefixLegacy.svg"), normalizeLineSeparator(writer.toString()));
}
}

@Test
void testDrawMultiSubstation() throws IOException {
network = Networks.createTestCase11Network();

SingleLineDiagram.drawMultiSubstations(network, List.of("subst", "subst2"), svgPath);
assertEquals(toString("/TestDrawS1S2PrefixEmpty.svg"), normalizeLineSeparator(toString(Files.newInputStream(svgPath))));

SingleLineDiagram.drawMultiSubstations(network, List.of("subst", "subst2"), svgPath, new LegacyIdProvider("Legacy"));
assertEquals(toString("/TestDrawS1S2PrefixLegacy.svg"), normalizeLineSeparator(toString(Files.newInputStream(svgPath))));

try (StringWriter writer = new StringWriter()) {
SingleLineDiagram.drawMultiSubstations(network, List.of("subst", "subst2"), writer, new StringWriter(), sldParameters);
assertEquals(toString("/TestDrawS1S2PrefixTest.svg"), normalizeLineSeparator(writer.toString()));
}

try (StringWriter writer = new StringWriter()) {
SingleLineDiagram.drawMultiSubstations(network, List.of("subst", "subst2"), writer, new StringWriter(), sldParameters, new LegacyIdProvider("Legacy"));
assertEquals(toString("/TestDrawS1S2PrefixLegacy.svg"), normalizeLineSeparator(writer.toString()));
}
}
}
Loading