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

[WIP] Display power production and power consumption icons at each voltage level node #668

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2021, RTE (http://www.rte-france.com)
* Copyright (c) 2021-2025, 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/.
Expand Down Expand Up @@ -71,6 +71,8 @@ private VoltageLevelNode addVoltageLevelGraphNode(VoltageLevel vl, Graph graph,
graph.addNode(vlNode);
if (visible) {
graph.addTextNode(vlNode);
graph.addProductionNode(vlNode);
graph.addConsumptionNode(vlNode);
}
return vlNode;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2022, RTE (http://www.rte-france.com)
* Copyright (c) 2022-2025, 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/.
Expand Down Expand Up @@ -31,7 +31,7 @@ public void run(Graph graph, LayoutParameters layoutParameters) {
busNodesLayout(graph);
edgesLayout(graph, layoutParameters);

computeSize(graph);
computeSize(graph, layoutParameters);
}

@Override
Expand Down Expand Up @@ -101,6 +101,39 @@ protected void fixedTextNodeLayout(Pair<VoltageLevelNode, TextNode> nodes, Layou
nodes.getSecond().setEdgeConnection(edgeConnection);
}

protected void fixedProductionNodeLayout(Pair<VoltageLevelNode, ProductionNode> nodes, LayoutParameters layoutParameters) {
Point nodeShift = layoutParameters.getProductionNodeFixedShift();
double radius = layoutParameters.getPowerNodeRadius();
fixedPowerNodeLayout(nodes.getFirst().getPosition(), nodes.getSecond(), nodeShift, radius);
}

protected void fixedConsumptionNodeLayout(Pair<VoltageLevelNode, ConsumptionNode> nodes, LayoutParameters layoutParameters) {
Point nodeShift = layoutParameters.getConsumptionNodeFixedShift();
double radius = layoutParameters.getPowerNodeRadius();
fixedPowerNodeLayout(nodes.getFirst().getPosition(), nodes.getSecond(), nodeShift, radius);
}

protected void adjustProductionNodeForceLayout(Pair<VoltageLevelNode, ProductionNode> nodes, LayoutParameters layoutParameters) {
Point nodeShift = new Point(nodes.getFirst().getX() - nodes.getSecond().getX(), nodes.getSecond().getY() - nodes.getFirst().getY());
double radius = layoutParameters.getPowerNodeRadius();
fixedPowerNodeLayout(nodes.getFirst().getPosition(), nodes.getSecond(), nodeShift, radius);
}

protected void adjustConsumptionNodeForceLayout(Pair<VoltageLevelNode, ConsumptionNode> nodes, LayoutParameters layoutParameters) {
Point nodeShift = new Point(nodes.getFirst().getX() - nodes.getSecond().getX(), nodes.getSecond().getY() - nodes.getFirst().getY());
double radius = layoutParameters.getPowerNodeRadius();
fixedPowerNodeLayout(nodes.getFirst().getPosition(), nodes.getSecond(), nodeShift, radius);
}

protected void fixedPowerNodeLayout(Point vlNodePosition, PowerNode powerNode, Point shift, double radius) {
Point position = vlNodePosition.shift(shift.getX(), shift.getY());
double angle = position.getAngle(vlNodePosition);
Point connectionShift = new Point(shift.getX() + radius * Math.cos(angle), shift.getY() + radius * Math.sin(angle));
Point edgeConnection = vlNodePosition.shift(connectionShift.getX(), connectionShift.getY());
powerNode.setPosition(position);
powerNode.setEdgeConnection(edgeConnection);
}

protected void edgesLayout(Graph graph, LayoutParameters layoutParameters) {
Objects.requireNonNull(graph);
Objects.requireNonNull(layoutParameters);
Expand All @@ -116,14 +149,25 @@ private void setEdgeVisibility(Node node, BranchEdge branchEdge, BranchEdge.Side
}
}

private void computeSize(Graph graph) {
private void computeSize(Graph graph, LayoutParameters layoutParameters) {
double[] dims = new double[] {Double.MAX_VALUE, -Double.MAX_VALUE, Double.MAX_VALUE, -Double.MAX_VALUE};
Stream.concat(graph.getTextNodesStream(), graph.getNodesStream()).forEach(node -> {
dims[0] = Math.min(dims[0], node.getX());
dims[1] = Math.max(dims[1], node.getX());
dims[2] = Math.min(dims[2], node.getY());
dims[3] = Math.max(dims[3], node.getY());
});
if (layoutParameters.isPowerNodesForceLayout()) {
Stream.of(graph.getTextNodesStream(), graph.getNodesStream(), graph.getProductionNodesStream(),
graph.getConsumptionNodesStream()).flatMap(i -> i).forEach(node -> {
dims[0] = Math.min(dims[0], node.getX());
dims[1] = Math.max(dims[1], node.getX());
dims[2] = Math.min(dims[2], node.getY());
dims[3] = Math.max(dims[3], node.getY());
});
} else {
Stream.concat(graph.getTextNodesStream(), graph.getNodesStream()).forEach(node -> {
dims[0] = Math.min(dims[0], node.getX());
dims[1] = Math.max(dims[1], node.getX());
dims[2] = Math.min(dims[2], node.getY());
dims[3] = Math.max(dims[3], node.getY());
});
}

graph.setDimensions(dims[0], dims[1], dims[2], dims[3]);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2022, RTE (http://www.rte-france.com)
* Copyright (c) 2022-2025, 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/.
Expand All @@ -18,7 +18,7 @@ public class BasicFixedLayout extends AbstractLayout {

@Override
protected void nodesLayout(Graph graph, LayoutParameters layoutParameters) {
org.jgrapht.Graph<Node, Edge> jgraphtGraph = graph.getJgraphtGraph(layoutParameters.isTextNodesForceLayout());
org.jgrapht.Graph<Node, Edge> jgraphtGraph = graph.getJgraphtGraph(layoutParameters.isTextNodesForceLayout(), layoutParameters.isPowerNodesForceLayout());

jgraphtGraph.vertexSet().forEach(node -> {
Point p = getInitialNodePositions().get(node.getEquipmentId());
Expand All @@ -30,5 +30,12 @@ protected void nodesLayout(Graph graph, LayoutParameters layoutParameters) {
if (!layoutParameters.isTextNodesForceLayout()) {
graph.getTextEdgesMap().values().forEach(nodePair -> fixedTextNodeLayout(nodePair, layoutParameters));
}
if (!layoutParameters.isPowerNodesForceLayout()) {
graph.getProductionEdgesMap().values().forEach(nodePair -> fixedProductionNodeLayout(nodePair, layoutParameters));
graph.getConsumptionEdgesMap().values().forEach(nodePair -> fixedConsumptionNodeLayout(nodePair, layoutParameters));
} else {
graph.getProductionEdgesMap().values().forEach(nodePair -> adjustProductionNodeForceLayout(nodePair, layoutParameters));
graph.getConsumptionEdgesMap().values().forEach(nodePair -> adjustConsumptionNodeForceLayout(nodePair, layoutParameters));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2021, RTE (http://www.rte-france.com)
* Copyright (c) 2021-2025, 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/.
Expand All @@ -12,6 +12,7 @@
import com.powsybl.nad.model.Graph;
import com.powsybl.nad.model.Node;
import com.powsybl.nad.model.Point;
import com.powsybl.nad.model.PowerNode;
import com.powsybl.nad.model.TextNode;

import java.util.Map;
Expand Down Expand Up @@ -40,7 +41,7 @@ public BasicForceLayout() {

@Override
protected void nodesLayout(Graph graph, LayoutParameters layoutParameters) {
org.jgrapht.Graph<Node, Edge> jgraphtGraph = graph.getJgraphtGraph(layoutParameters.isTextNodesForceLayout());
org.jgrapht.Graph<Node, Edge> jgraphtGraph = graph.getJgraphtGraph(layoutParameters.isTextNodesForceLayout(), layoutParameters.isPowerNodesForceLayout());
ForceLayout<Node, Edge> forceLayout = new ForceLayout<>(jgraphtGraph)
.setAttractToCenterForce(attractToCenterForce)
.setRepulsionForceFromFixedPoints(repulsionForceFromFixedPoints);
Expand All @@ -58,7 +59,10 @@ protected void nodesLayout(Graph graph, LayoutParameters layoutParameters) {

jgraphtGraph.vertexSet().forEach(node -> {
Vector p = forceLayout.getStablePosition(node);
if (node instanceof TextNode texNode) {
if (node instanceof PowerNode powerNode) {
powerNode.setPosition(SCALE * p.getX(), SCALE * p.getY());
powerNode.setEdgeConnection(new Point(SCALE * p.getX(), SCALE * p.getY()));
} else if (node instanceof TextNode texNode) {
texNode.setPosition(SCALE * p.getX(), SCALE * p.getY() - layoutParameters.getTextNodeEdgeConnectionYShift());
texNode.setEdgeConnection(new Point(SCALE * p.getX(), SCALE * p.getY()));
} else {
Expand All @@ -69,6 +73,13 @@ protected void nodesLayout(Graph graph, LayoutParameters layoutParameters) {
if (!layoutParameters.isTextNodesForceLayout()) {
graph.getTextEdgesMap().values().forEach(nodePair -> fixedTextNodeLayout(nodePair, layoutParameters));
}
if (!layoutParameters.isPowerNodesForceLayout()) {
graph.getProductionEdgesMap().values().forEach(nodePair -> fixedProductionNodeLayout(nodePair, layoutParameters));
graph.getConsumptionEdgesMap().values().forEach(nodePair -> fixedConsumptionNodeLayout(nodePair, layoutParameters));
} else {
graph.getProductionEdgesMap().values().forEach(nodePair -> adjustProductionNodeForceLayout(nodePair, layoutParameters));
graph.getConsumptionEdgesMap().values().forEach(nodePair -> adjustConsumptionNodeForceLayout(nodePair, layoutParameters));
}
}

private void setInitialPositions(ForceLayout<Node, Edge> forceLayout, Graph graph) {
Expand All @@ -83,4 +94,5 @@ private void setInitialPositions(ForceLayout<Node, Edge> forceLayout, Graph grap
));
forceLayout.setInitialPoints(initialPoints);
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2021, RTE (http://www.rte-france.com)
* Copyright (c) 2021-2025, 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/.
Expand All @@ -17,6 +17,10 @@ public class LayoutParameters {
private Point textNodeFixedShift = new Point(100, -40);
private int maxSteps = 1000;
private double textNodeEdgeConnectionYShift = 25;
private Point productionNodeFixedShift = new Point(-100, -50);
private Point consumptionNodeFixedShift = new Point(-100, +50);
private boolean powerNodesForceLayout = false;
private double powerNodeRadius = 15;

public LayoutParameters() {
}
Expand Down Expand Up @@ -56,6 +60,15 @@ public LayoutParameters setTextNodeFixedShift(double textNodeFixedShiftX, double
return this;
}

public Point getProductionNodeFixedShift() {
return productionNodeFixedShift;
}

public LayoutParameters setProductiontNodeFixedShift(double productionNodeFixedShiftX, double productionNodeFixedShiftY) {
this.productionNodeFixedShift = new Point(productionNodeFixedShiftX, productionNodeFixedShiftY);
return this;
}

public int getMaxSteps() {
return maxSteps;
}
Expand All @@ -73,4 +86,29 @@ public LayoutParameters setTextNodeEdgeConnectionYShift(double textNodeEdgeConne
this.textNodeEdgeConnectionYShift = textNodeEdgeConnectionYShift;
return this;
}

public double getPowerNodeRadius() {
return powerNodeRadius;
}

public void setPowerNodeRadius(double powerNodeRadius) {
this.powerNodeRadius = powerNodeRadius;
}

public Point getConsumptionNodeFixedShift() {
return consumptionNodeFixedShift;
}

public void setConsumptionNodeFixedShift(Point consumptionNodeFixedShift) {
this.consumptionNodeFixedShift = consumptionNodeFixedShift;
}

public boolean isPowerNodesForceLayout() {
return powerNodesForceLayout;
}

public void setPowerNodesForceLayout(boolean powerNodesForceLayout) {
this.powerNodesForceLayout = powerNodesForceLayout;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Copyright (c) 2025, 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/.
*/
package com.powsybl.nad.model;

public class ConsumptionEdge extends PowerEdge {

public static final String CONSUMPTION_EDGE = "ConsumptionEdge";

public ConsumptionEdge(String diagramId) {
super(diagramId, null, null, CONSUMPTION_EDGE);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Copyright (c) 2025, 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/.
*/
package com.powsybl.nad.model;

public class ConsumptionNode extends PowerNode {

public ConsumptionNode(String diagramId) {
super(diagramId);
}
}
Loading
Loading