DefaultLabelProvider.java
/**
* Copyright (c) 2019, 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.iidm.network.*;
import com.powsybl.iidm.network.extensions.OperatingStatus;
import com.powsybl.sld.layout.LayoutParameters;
import com.powsybl.sld.library.ComponentLibrary;
import com.powsybl.sld.model.coordinate.Direction;
import com.powsybl.sld.model.graphs.VoltageLevelGraph;
import com.powsybl.sld.model.nodes.*;
import com.powsybl.sld.model.nodes.feeders.FeederTwLeg;
import com.powsybl.sld.model.nodes.feeders.FeederWithSides;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static com.powsybl.sld.library.ComponentTypeName.*;
import static com.powsybl.sld.model.coordinate.Direction.BOTTOM;
/**
* @author Giovanni Ferrari {@literal <giovanni.ferrari at techrain.eu>}
* @author Franck Lecuyer {@literal <franck.lecuyer at franck.lecuyer@rte-france.com>}
*/
public class DefaultLabelProvider extends AbstractLabelProvider {
private static final String PLANNED_OUTAGE_BRANCH_NODE_DECORATOR = "LOCK";
private static final String FORCED_OUTAGE_BRANCH_NODE_DECORATOR = "FLASH";
protected final Network network;
public DefaultLabelProvider(Network net, ComponentLibrary componentLibrary, LayoutParameters layoutParameters, SvgParameters svgParameters) {
super(componentLibrary, layoutParameters, svgParameters);
this.network = Objects.requireNonNull(net);
}
@Override
public List<FeederInfo> getFeederInfos(FeederNode node) {
Objects.requireNonNull(node);
List<FeederInfo> feederInfos = new ArrayList<>();
Feeder feeder = node.getFeeder();
switch (feeder.getFeederType()) {
case INJECTION:
feederInfos = getInjectionFeederInfos(node);
break;
case BRANCH:
feederInfos = getBranchFeederInfos(node, (FeederWithSides) feeder);
break;
case TWO_WINDINGS_TRANSFORMER_LEG:
feederInfos = get2WTFeederInfos(node, (FeederTwLeg) feeder);
break;
case THREE_WINDINGS_TRANSFORMER_LEG:
feederInfos = get3WTFeederInfos(node, (FeederTwLeg) feeder);
break;
case HVDC:
feederInfos = getHvdcFeederInfos(node, (FeederWithSides) feeder);
break;
default:
break;
}
if (node.getDirection() == BOTTOM && !svgParameters.isFeederInfoSymmetry()) {
Collections.reverse(feederInfos);
}
return feederInfos;
}
private List<FeederInfo> getInjectionFeederInfos(FeederNode node) {
List<FeederInfo> measures = new ArrayList<>();
Injection<?> injection = (Injection<?>) network.getIdentifiable(node.getEquipmentId());
if (injection != null) {
measures = buildFeederInfos(injection);
}
return measures;
}
private List<FeederInfo> getBranchFeederInfos(FeederNode node, FeederWithSides feeder) {
List<FeederInfo> measures = new ArrayList<>();
Branch<?> branch = network.getBranch(node.getEquipmentId());
if (branch != null) {
TwoSides side = TwoSides.valueOf(feeder.getSide().name());
measures = buildFeederInfos(branch, side);
}
return measures;
}
private List<FeederInfo> get3WTFeederInfos(FeederNode node, FeederTwLeg feeder) {
List<FeederInfo> feederInfos = new ArrayList<>();
ThreeWindingsTransformer transformer = network.getThreeWindingsTransformer(node.getEquipmentId());
if (transformer != null) {
ThreeSides side = ThreeSides.valueOf(feeder.getSide().name());
boolean insideVoltageLevel = feeder.getOwnVoltageLevelInfos().getId().equals(feeder.getVoltageLevelInfos().getId());
feederInfos = buildFeederInfos(transformer, side, insideVoltageLevel);
}
return feederInfos;
}
private List<FeederInfo> get2WTFeederInfos(FeederNode node, FeederTwLeg feeder) {
List<FeederInfo> measures = new ArrayList<>();
TwoWindingsTransformer transformer = network.getTwoWindingsTransformer(node.getEquipmentId());
if (transformer != null) {
TwoSides side = TwoSides.valueOf(feeder.getSide().name());
measures = buildFeederInfos(transformer, side);
}
return measures;
}
private List<FeederInfo> getHvdcFeederInfos(FeederNode node, FeederWithSides feeder) {
List<FeederInfo> measures = new ArrayList<>();
HvdcLine hvdcLine = network.getHvdcLine(node.getEquipmentId());
if (hvdcLine != null) {
NodeSide side = feeder.getSide();
measures = buildFeederInfos(hvdcLine, side);
}
return measures;
}
@Override
public List<NodeDecorator> getNodeDecorators(Node node, Direction direction) {
Objects.requireNonNull(node);
List<NodeDecorator> nodeDecorators = new ArrayList<>();
if (node instanceof EquipmentNode equipmentNode && !(node instanceof SwitchNode)) {
if (node instanceof FeederNode feederNode) {
switch (feederNode.getFeeder().getFeederType()) {
case BRANCH, TWO_WINDINGS_TRANSFORMER_LEG -> addOperatingStatusDecorator(nodeDecorators, node, direction, network.getBranch(feederNode.getEquipmentId()));
case THREE_WINDINGS_TRANSFORMER_LEG -> {
// if this is an outer leg (leg corresponding to another voltage level), we display the decorator on the inner 3wt
if (node.getAdjacentNodes().stream().noneMatch(Middle3WTNode.class::isInstance)) {
addOperatingStatusDecorator(nodeDecorators, node, direction, network.getThreeWindingsTransformer(feederNode.getEquipmentId()));
}
}
case HVDC -> addOperatingStatusDecorator(nodeDecorators, node, direction, network.getHvdcLine(feederNode.getEquipmentId()));
default -> { /* No decorator for other feeder types */ }
}
} else if (node instanceof MiddleTwtNode) {
if (node instanceof Middle3WTNode middle3WTNode && middle3WTNode.isEmbeddedInVlGraph()) {
addOperatingStatusDecorator(nodeDecorators, node, direction, network.getThreeWindingsTransformer(middle3WTNode.getEquipmentId()));
}
} else {
addOperatingStatusDecorator(nodeDecorators, node, direction, network.getIdentifiable(equipmentNode.getEquipmentId()));
}
}
return nodeDecorators;
}
@Override
public List<BusLegendInfo> getBusLegendInfos(VoltageLevelGraph graph) {
VoltageLevel vl = network.getVoltageLevel(graph.getVoltageLevelInfos().getId());
return vl.getBusView().getBusStream()
.map(b -> new BusLegendInfo(b.getId(), List.of(
new BusLegendInfo.Caption(valueFormatter.formatVoltage(b.getV(), "kV"), "v"),
new BusLegendInfo.Caption(valueFormatter.formatAngleInDegrees(b.getAngle()), "angle")
)))
.collect(Collectors.toList());
}
private <T extends Identifiable<T>> void addOperatingStatusDecorator(List<NodeDecorator> nodeDecorators, Node node, Direction direction, Identifiable<T> identifiable) {
if (identifiable != null) {
OperatingStatus<T> operatingStatus = identifiable.getExtension(OperatingStatus.class);
if (operatingStatus != null) {
switch (operatingStatus.getStatus()) {
case PLANNED_OUTAGE -> nodeDecorators.add(getOperatingStatusDecorator(node, direction, PLANNED_OUTAGE_BRANCH_NODE_DECORATOR));
case FORCED_OUTAGE -> nodeDecorators.add(getOperatingStatusDecorator(node, direction, FORCED_OUTAGE_BRANCH_NODE_DECORATOR));
case IN_OPERATION -> { /* No decorator for IN_OPERATION equipment */ }
}
}
}
}
private NodeDecorator getOperatingStatusDecorator(Node node, Direction direction, String decoratorType) {
if (node instanceof Middle3WTNode middle3WTNode) {
return new NodeDecorator(decoratorType, getMiddle3WTDecoratorPosition(middle3WTNode, direction));
} else if (node instanceof BusNode) {
return new NodeDecorator(decoratorType, getBusDecoratorPosition());
} else if (node instanceof FeederNode) {
return new NodeDecorator(decoratorType, getFeederDecoratorPosition(direction, decoratorType));
} else if (node instanceof Internal2WTNode) {
return new NodeDecorator(decoratorType, getInternal2WTDecoratorPosition(node.getOrientation()));
} else {
return new NodeDecorator(decoratorType, getGenericDecoratorPosition());
}
}
private List<FeederInfo> buildFeederInfos(ThreeWindingsTransformer transformer, ThreeSides side, boolean insideVoltageLevel) {
return this.buildFeederInfos(transformer.getTerminal(side), insideVoltageLevel);
}
private List<FeederInfo> buildFeederInfos(Injection<?> injection) {
return this.buildFeederInfos(injection.getTerminal());
}
private List<FeederInfo> buildFeederInfos(Branch<?> branch, TwoSides side) {
return this.buildFeederInfos(branch.getTerminal(side));
}
private List<FeederInfo> buildFeederInfos(HvdcLine hvdcLine, NodeSide side) {
HvdcConverterStation<?> hvdcConverterStation = side == NodeSide.ONE ? hvdcLine.getConverterStation1()
: hvdcLine.getConverterStation2();
return this.buildFeederInfos(hvdcConverterStation.getTerminal());
}
private List<FeederInfo> buildFeederInfos(Terminal terminal) {
return buildFeederInfos(terminal, true);
}
private List<FeederInfo> buildFeederInfos(Terminal terminal, boolean insideVoltageLevel) {
List<FeederInfo> feederInfoList = new ArrayList<>();
double terminalP = terminal.getP();
double terminalQ = terminal.getQ();
double terminalI = terminal.getI();
if (!insideVoltageLevel) {
terminalP = -terminalP;
terminalQ = -terminalQ;
terminalI = -terminalI;
}
feederInfoList.add(new DirectionalFeederInfo(ARROW_ACTIVE, terminalP, svgParameters.getActivePowerUnit(), valueFormatter::formatPower));
feederInfoList.add(new DirectionalFeederInfo(ARROW_REACTIVE, terminalQ, svgParameters.getReactivePowerUnit(), valueFormatter::formatPower));
if (this.svgParameters.isDisplayCurrentFeederInfo()) {
feederInfoList.add(new DirectionalFeederInfo(ARROW_CURRENT, terminalI, svgParameters.getCurrentUnit(), valueFormatter::formatPower));
}
return feederInfoList;
}
}