Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set layout node positions getting them from JSON metadata in network area diagram #656

Merged
merged 8 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ public abstract class AbstractLayout implements Layout {

private Map<String, Point> initialNodePositions = Collections.emptyMap();
private Set<String> nodesWithFixedPosition = Collections.emptySet();
private Map<String, TextPosition> textNodesWithFixedPosition = new HashMap<>();

record TextPosition(Point topLeftPosition, Point edgeConnection) {
}
private final Map<String, TextPosition> textNodesWithFixedPosition = new HashMap<>();

@Override
public void run(Graph graph, LayoutParameters layoutParameters) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,23 @@ public class FixedLayoutFactory implements LayoutFactory {

private final Map<String, Point> fixedPositions;
private final LayoutFactory layoutFactory;
private final Map<String, TextPosition> textNodesWithFixedPosition;

public FixedLayoutFactory(Map<String, Point> fixedPositions) {
this(fixedPositions, BasicFixedLayout::new);
}

public FixedLayoutFactory(Map<String, Point> fixedPositions, LayoutFactory layoutFactory) {
this(fixedPositions, Map.of(), layoutFactory);
}

public FixedLayoutFactory(Map<String, Point> fixedPositions, Map<String, TextPosition> textNodesWithFixedPosition) {
this(fixedPositions, textNodesWithFixedPosition, BasicFixedLayout::new);
}

public FixedLayoutFactory(Map<String, Point> fixedPositions, Map<String, TextPosition> textNodesWithFixedPosition, LayoutFactory layoutFactory) {
this.fixedPositions = Objects.requireNonNull(fixedPositions);
this.textNodesWithFixedPosition = Objects.requireNonNull(textNodesWithFixedPosition);
this.layoutFactory = Objects.requireNonNull(layoutFactory);
}

Expand All @@ -33,6 +43,7 @@ public Layout create() {
Layout layout = layoutFactory.create();
layout.setInitialNodePositions(fixedPositions);
layout.setNodesWithFixedPosition(fixedPositions.keySet());
textNodesWithFixedPosition.forEach((k, v) -> layout.setTextNodeFixedPosition(k, v.topLeftPosition(), v.edgeConnection()));
return layout;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* Copyright (c) 2024, 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.nad.layout;

import com.powsybl.nad.svg.metadata.DiagramMetadata;

import java.io.InputStream;
import java.io.Reader;
import java.nio.file.Path;

/**
* @author Massimo Ferraro {@literal <massimo.ferraro at soft.it>}
*/
public final class FixedLayoutFactoryUtils {

private FixedLayoutFactoryUtils() {
}

private static FixedLayoutFactory createFixedLayoutFactory(LayoutFactory layoutFactory, DiagramMetadata diagramMetadata) {
return new FixedLayoutFactory(diagramMetadata.getFixedPositions(), diagramMetadata.getFixedTextPositions(), layoutFactory);
}

private static FixedLayoutFactory createFixedLayoutFactory(DiagramMetadata diagramMetadata) {
return new FixedLayoutFactory(diagramMetadata.getFixedPositions(), diagramMetadata.getFixedTextPositions());
}

public static FixedLayoutFactory create(InputStream metadataIs, LayoutFactory layoutFactory) {
return createFixedLayoutFactory(layoutFactory, DiagramMetadata.parseJson(metadataIs));
}

public static FixedLayoutFactory create(InputStream metadataIs) {
return createFixedLayoutFactory(DiagramMetadata.parseJson(metadataIs));
}

public static FixedLayoutFactory create(Path metadataFile, LayoutFactory layoutFactory) {
return createFixedLayoutFactory(layoutFactory, DiagramMetadata.parseJson(metadataFile));
}

public static FixedLayoutFactory create(Path metadataFile) {
return createFixedLayoutFactory(DiagramMetadata.parseJson(metadataFile));
}

public static FixedLayoutFactory create(Reader metadataReader, LayoutFactory layoutFactory) {
return createFixedLayoutFactory(layoutFactory, DiagramMetadata.parseJson(metadataReader));
}

public static FixedLayoutFactory create(Reader metadataReader) {
return createFixedLayoutFactory(DiagramMetadata.parseJson(metadataReader));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Copyright (c) 2024, 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.nad.layout;

import com.powsybl.nad.model.Point;

/**
* @author Florian Dupuy {@literal <florian.dupuy at rte-france.com>}
*/
public record TextPosition(Point topLeftPosition, Point edgeConnection) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@
*/
package com.powsybl.nad.svg.metadata;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.powsybl.commons.json.JsonUtil;
import com.powsybl.diagram.metadata.AbstractMetadata;
import com.powsybl.nad.layout.LayoutParameters;
import com.powsybl.nad.layout.TextPosition;
import com.powsybl.nad.model.Graph;
import com.powsybl.nad.model.Point;
import com.powsybl.nad.svg.SvgParameters;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
Expand All @@ -15,16 +27,9 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.powsybl.commons.json.JsonUtil;
import com.powsybl.diagram.metadata.AbstractMetadata;
import com.powsybl.nad.layout.LayoutParameters;
import com.powsybl.nad.model.Graph;
import com.powsybl.nad.svg.SvgParameters;
import java.util.stream.Collectors;

/**
* @author Thomas Adam {@literal <tadam at silicom.fr>}
Expand Down Expand Up @@ -144,6 +149,7 @@ private double round(double number) {
}

public static DiagramMetadata parseJson(Path file) {
Objects.requireNonNull(file);
try (Reader reader = Files.newBufferedReader(file)) {
return parseJson(reader);
} catch (IOException e) {
Expand All @@ -170,4 +176,14 @@ public static DiagramMetadata parseJson(Reader reader) {
throw new UncheckedIOException(e);
}
}

@JsonIgnore
public Map<String, Point> getFixedPositions() {
return nodesMetadata.stream().collect(Collectors.toMap(NodeMetadata::getEquipmentId, NodeMetadata::getPosition));
}

@JsonIgnore
public Map<String, TextPosition> getFixedTextPositions() {
return textNodesMetadata.stream().collect(Collectors.toMap(TextNodeMetadata::getEquipmentId, TextNodeMetadata::getTextPosition));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
*/
package com.powsybl.nad.svg.metadata;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.powsybl.nad.model.Point;

/**
* @author Luma Zamarreño {@literal <zamarrenolm at aia.es>}
Expand All @@ -35,4 +37,9 @@ public double getX() {
public double getY() {
return y;
}

@JsonIgnore
public Point getPosition() {
return new Point(x, y);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
*/
package com.powsybl.nad.svg.metadata;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.powsybl.nad.layout.TextPosition;
import com.powsybl.nad.model.Point;

/**
* @author Massimo Ferraro {@literal <massimo.ferraro at soft.it>}
Expand Down Expand Up @@ -61,4 +64,9 @@ public double getConnectionShiftX() {
public double getConnectionShiftY() {
return connectionShiftY;
}

@JsonIgnore
public TextPosition getTextPosition() {
return new TextPosition(new Point(shiftX, shiftY), new Point(connectionShiftX, connectionShiftY));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,16 @@
import com.powsybl.nad.build.iidm.VoltageLevelFilter;
import com.powsybl.nad.model.Graph;
import com.powsybl.nad.model.Point;

import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -98,4 +106,85 @@ void testBasicFixedLayoutFallback() {
assertEquals(0, actual.get("VL8").getX());
assertEquals(0, actual.get("VL8").getY());
}

@Test
void testMetadataUtils() throws URISyntaxException, IOException {
Network network = Networks.createTwoVoltageLevels();
Path metadataFile = Paths.get(getClass().getResource("/two-voltage-levels_metadata.json").toURI());

Layout layout = new FixedLayoutFactory(new HashMap<>()).create();
testEmptyLayout(layout, network);

layout = FixedLayoutFactoryUtils.create(metadataFile).create();
testMetadataLayout(layout, network);
layout = FixedLayoutFactoryUtils.create(metadataFile, BasicFixedLayout::new).create();
testMetadataLayout(layout, network);

try (InputStream metadataIS = Files.newInputStream(metadataFile)) {
layout = FixedLayoutFactoryUtils.create(metadataIS).create();
testMetadataLayout(layout, network);
}
try (InputStream metadataIS = Files.newInputStream(metadataFile)) {
layout = FixedLayoutFactoryUtils.create(metadataIS, BasicFixedLayout::new).create();
testMetadataLayout(layout, network);
}

try (Reader metadataReader = Files.newBufferedReader(metadataFile)) {
layout = FixedLayoutFactoryUtils.create(metadataReader).create();
testMetadataLayout(layout, network);
}
try (Reader metadataReader = Files.newBufferedReader(metadataFile)) {
layout = FixedLayoutFactoryUtils.create(metadataReader, BasicFixedLayout::new).create();
testMetadataLayout(layout, network);
}
}

void testEmptyLayout(Layout layout, Network network) {
Graph graph = new NetworkGraphBuilder(network, VoltageLevelFilter.NO_FILTER).buildGraph();
layout.run(graph, new LayoutParameters());
Map<String, Point> nodePositions = graph.getNodePositions();
checkNodePosition(nodePositions.get("dl1"), 0, 0);
checkNodePosition(nodePositions.get("vl1"), 0, 0);
checkNodePosition(nodePositions.get("vl2"), 0, 0);
Map<String, TextPosition> textNodesPositions = getTextNodesPositions(graph);
checkNodeShift(nodePositions.get("vl1"), textNodesPositions.get("vl1").topLeftPosition(), 100, -40);
checkNodeShift(nodePositions.get("vl1"), textNodesPositions.get("vl1").edgeConnection(), 100, -15);
checkNodeShift(nodePositions.get("vl2"), textNodesPositions.get("vl2").topLeftPosition(), 100, -40);
checkNodeShift(nodePositions.get("vl2"), textNodesPositions.get("vl2").edgeConnection(), 100, -15);
}

void testMetadataLayout(Layout layout, Network network) {
Graph graph = new NetworkGraphBuilder(network, VoltageLevelFilter.NO_FILTER).buildGraph();
layout.run(graph, new LayoutParameters());
Map<String, Point> nodePositions = graph.getNodePositions();
checkNodePosition(nodePositions.get("dl1"), -49.12, 317.14);
checkNodePosition(nodePositions.get("vl1"), -56.06, -318.7);
checkNodePosition(nodePositions.get("vl2"), -230.42, 1.18);
Map<String, TextPosition> textNodesPositions = getTextNodesPositions(graph);
checkNodeShift(nodePositions.get("vl1"), textNodesPositions.get("vl1").topLeftPosition(), 80, -30);
checkNodeShift(nodePositions.get("vl1"), textNodesPositions.get("vl1").edgeConnection(), 80, -5);
checkNodeShift(nodePositions.get("vl2"), textNodesPositions.get("vl2").topLeftPosition(), 80, -30);
checkNodeShift(nodePositions.get("vl2"), textNodesPositions.get("vl2").edgeConnection(), 80, -5);
}

Map<String, TextPosition> getTextNodesPositions(Graph graph) {
Map<String, TextPosition> textNodesPositions = new HashMap<>();
graph.getTextEdgesMap()
.values()
.forEach(nodePair -> textNodesPositions.put(nodePair.getFirst().getEquipmentId(),
new TextPosition(nodePair.getSecond().getPosition(),
nodePair.getSecond().getEdgeConnection())));
return textNodesPositions;
}

void checkNodePosition(Point point, double x, double y) {
assertEquals(x, point.getX());
assertEquals(y, point.getY());
}

void checkNodeShift(Point point, Point shiftedPoint, double shiftX, double shiftY) {
Point expectedPoint = point.shift(shiftX, shiftY);
assertEquals(expectedPoint.getX(), shiftedPoint.getX());
assertEquals(expectedPoint.getY(), shiftedPoint.getY());
}
}
Loading