SerialBlock.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/.
*/
package com.powsybl.sld.model.blocks;
import com.powsybl.commons.PowsyblException;
import com.powsybl.sld.model.graphs.VoltageLevelGraph;
import com.powsybl.sld.model.nodes.BusNode;
import com.powsybl.sld.model.nodes.FeederNode;
import com.powsybl.sld.model.nodes.Node;
import java.util.*;
import static com.powsybl.sld.model.blocks.Block.Type.SERIAL;
import static com.powsybl.sld.model.coordinate.Position.Dimension.H;
import static com.powsybl.sld.model.coordinate.Position.Dimension.V;
/**
* @author Benoit Jeanson {@literal <benoit.jeanson at rte-france.com>}
* @author Nicolas Duchene
* @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
* @author Franck Lecuyer {@literal <franck.lecuyer at rte-france.com>}
*/
public class SerialBlock extends AbstractComposedBlock<Block> {
/**
* Constructor
* A layout.block chain is oriented in order to have.
* Lower - embedding BusNode if only one of both layout.block embed a BusNode
* Upper - (as a consequence) can embed a BusNode only if Lower as one
*/
public SerialBlock(List<Block> blocks) {
super(SERIAL, blocks);
if (blocks.size() == 1 && blocks.get(0).getType() == SERIAL) {
subBlocks = ((SerialBlock) blocks.get(0)).getSubBlocks();
} else {
subBlocks = new ArrayList<>(blocks);
}
postConstruct();
}
public SerialBlock(Block block) {
this(Collections.singletonList(block));
}
@Override
public void replaceEndingNode(Node newEndingNode) {
getUpperBlock().replaceEndingNode(newEndingNode);
}
@Override
public int getOrder() {
return getExtremityNode(Block.Extremity.END).getType() == Node.NodeType.FEEDER ?
((FeederNode) getExtremityNode(Block.Extremity.END)).getOrder().orElse(-1) : 0;
}
@Override
public void accept(BlockVisitor blockVisitor) {
blockVisitor.visit(this);
}
private void postConstruct() {
if (subBlocks.size() != 1) {
for (int i = 0; i < subBlocks.size() - 1; i++) {
alignChaining(subBlocks.get(i), subBlocks.get(i + 1));
}
if (getLowerBlock().isEmbeddingNodeType(Node.NodeType.FEEDER)
|| getUpperBlock().isEmbeddingNodeType(Node.NodeType.BUS)) {
reverseBlock();
}
}
setCardinality(Extremity.START, getLowerBlock().getCardinality(Extremity.START));
setCardinality(Extremity.END, getUpperBlock().getCardinality(Extremity.END));
}
private void alignChaining(Block block1, Block block2) {
if (block1.getExtremityNode(Extremity.END) == block2.getExtremityNode(Extremity.START)) {
return;
}
if (block1.getExtremityNode(Extremity.END) == block2.getExtremityNode(Extremity.END)) {
block2.reverseBlock();
return;
}
if (block1.getExtremityNode(Extremity.START) == block2.getExtremityNode(Extremity.END)) {
block1.reverseBlock();
block2.reverseBlock();
return;
}
if (block1.getExtremityNode(Extremity.START) == block2.getExtremityNode(Extremity.START)) {
block1.reverseBlock();
return;
}
throw new PowsyblException("unconsistent chaining in SerialBlock");
}
public boolean addSubBlock(VoltageLevelGraph vlGraph, Block block) {
// Looking for a common extremity node between current serial block and given block
for (Extremity myExtremity : Extremity.values()) {
Node extremityNode = getExtremityNode(myExtremity);
if (extremityNode instanceof FeederNode || extremityNode instanceof BusNode) {
continue;
}
for (Extremity itsExtremity : Extremity.values()) {
if (extremityNode == block.getExtremityNode(itsExtremity)
&& extremityNode.getCardinality(vlGraph) == getCardinality(extremityNode) + block.getCardinality(itsExtremity)) {
insertBlock(block, myExtremity);
return true;
}
}
}
return false;
}
public Optional<Extremity> whichExtremity(Block block) {
if (block.equals(subBlocks.get(0))) {
return Optional.of(Extremity.START);
}
if (block.equals(subBlocks.get(subBlocks.size() - 1))) {
return Optional.of(Extremity.END);
}
return Optional.empty();
}
public Block extractBody(Collection<Block> blocks) {
List<Block> subBlocksCopy = new ArrayList<>(subBlocks);
subBlocksCopy.removeAll(blocks);
if (subBlocksCopy.size() == 1) {
return subBlocksCopy.get(0);
} else {
return new SerialBlock(subBlocksCopy);
}
}
private void insertBlock(Block block, Extremity myExtremity) {
block.setParentBlock(this);
if (myExtremity == Extremity.START) {
subBlocks.add(0, block);
} else {
subBlocks.add(block);
}
postConstruct();
}
public Block getUpperBlock() {
return subBlocks.get(subBlocks.size() - 1);
}
public Block getLowerBlock() {
return subBlocks.get(0);
}
public List<Node> getChainingNodes() {
List<Node> result = new ArrayList<>();
for (int i = 0; i < subBlocks.size() - 1; i++) {
result.add(subBlocks.get(i).getEndingNode());
}
return result;
}
@Override
public void sizing() {
subBlocks.forEach(Block::sizing);
if (getPosition().getOrientation().isVertical()) {
getPosition().getSegment(H).mergeEnvelop(getSegments(H));
getPosition().getSegment(V).glue(getSegments(V));
} else {
getPosition().getSegment(V).mergeEnvelop(getSegments(V));
getPosition().getSegment(H).glue(getSegments(H));
}
}
}