CalculateCoordCellVisitor.java
/**
* Copyright (c) 2022, 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.layout;
import com.powsybl.sld.model.blocks.Block;
import com.powsybl.sld.model.blocks.BodyPrimaryBlock;
import com.powsybl.sld.model.cells.*;
import com.powsybl.sld.model.coordinate.Coord;
import com.powsybl.sld.model.coordinate.Position;
import com.powsybl.sld.model.coordinate.Side;
import com.powsybl.sld.model.nodes.Node;
import static com.powsybl.sld.model.blocks.Block.Extremity.END;
import static com.powsybl.sld.model.blocks.Block.Extremity.START;
import static com.powsybl.sld.model.coordinate.Coord.Dimension.X;
import static com.powsybl.sld.model.coordinate.Coord.Dimension.Y;
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>}
*/
public final class CalculateCoordCellVisitor implements CellVisitor {
private final LayoutParameters layoutParameters;
private final LayoutContext layoutContext;
CalculateCoordCellVisitor(LayoutParameters layoutParameters, LayoutContext layoutContext) {
this.layoutParameters = layoutParameters;
this.layoutContext = layoutContext;
}
@Override
public void visit(InternCell cell) {
cell.getLegs().values().forEach(lb -> calculateRootCoord(lb, layoutContext));
calculateRootCoord(cell.getBodyBlock(), layoutContext);
}
@Override
public void visit(ExternCell cell) {
calculateRootCoord(cell.getRootBlock(), layoutContext);
}
@Override
public void visit(ArchCell cell) {
Block rootBlock = cell.getRootBlock();
Position position = rootBlock.getPosition();
setCoordX(rootBlock.getCoord(), position);
// pillar block Coord has been calculated beforehand
rootBlock.getCoord().set(Y, cell.getPillarBlock().getCoord());
CalculateCoordBlockVisitor cc = CalculateCoordBlockVisitor.create(layoutParameters, layoutContext);
rootBlock.accept(cc);
}
@Override
public void visit(ShuntCell cell) {
Position lPos = cell.getSidePosition(Side.LEFT);
coordShuntCase(cell.getRootBlock(), lPos.get(H) + lPos.getSpan(H), cell.getSidePosition(Side.RIGHT).get(H));
}
private void calculateRootCoord(Block block, LayoutContext layoutContext) {
if (block == null) {
return;
}
Position position = block.getPosition();
setCoordX(block.getCoord(), position);
double spanY = getRootSpanYCoord(position, layoutParameters, layoutContext.getMaxInternCellHeight(), layoutContext.isInternCell());
double valueY = getRootYCoord(position, layoutParameters, spanY, layoutContext);
block.getCoord().set(Y, valueY, spanY);
CalculateCoordBlockVisitor cc = CalculateCoordBlockVisitor.create(layoutParameters, layoutContext);
block.accept(cc);
}
private void setCoordX(Coord coord, Position position) {
double spanX = position.getSpan(H) / 2. * layoutParameters.getCellWidth();
double valueX = hToX(layoutParameters, position.get(H)) + spanX / 2;
coord.set(X, valueX, spanX);
}
private double hToX(LayoutParameters layoutParameters, int h) {
return layoutParameters.getCellWidth() * h / 2;
}
private double getRootSpanYCoord(Position position, LayoutParameters layoutParam, double externCellHeight, boolean isInternCell) {
double ySpan;
if (isInternCell) {
ySpan = position.getSpan(V) / 2. * layoutParam.getInternCellHeight();
} else {
// The Y span of root block does not consider the space needed for the FeederPrimaryBlock (feeder span)
// nor the one needed for the LegPrimaryBlock (layoutParam.getStackHeight())
ySpan = externCellHeight - layoutParam.getStackHeight() - layoutParam.getFeederSpan();
}
return ySpan;
}
private double getRootYCoord(Position position, LayoutParameters layoutParam, double spanY, LayoutContext layoutContext) {
double dyToBus = 0;
if (layoutContext.isInternCell() && !layoutContext.isFlat()) {
dyToBus = spanY / 2 + layoutParam.getInternCellHeight() * (1 + position.get(V)) / 2.;
} else {
dyToBus = spanY / 2 + layoutParam.getStackHeight();
}
switch (layoutContext.getDirection()) {
case BOTTOM:
return layoutContext.getLastBusY() + dyToBus;
case TOP:
return layoutContext.getFirstBusY() - dyToBus;
case MIDDLE:
return layoutContext.getFirstBusY() + (position.get(V) - 1) * layoutParam.getVerticalSpaceBus();
default:
return 0;
}
}
public void coordShuntCase(BodyPrimaryBlock block, int hLeft, int hRight) {
double x0 = hToX(layoutParameters, hLeft);
double y0 = block.getExtremityNode(START).getY();
double x1 = hToX(layoutParameters, hRight);
double y1 = block.getExtremityNode(END).getY();
double y = (y0 + y1) / 2;
block.getNodes().get(1).setCoordinates(x0, y);
block.getNodes().get(block.getNodes().size() - 2).setCoordinates(x1, y);
double dx = (x1 - x0) / (block.getNodes().size() - 4);
for (int i = 2; i < block.getNodes().size() - 2; i++) {
Node node = block.getNodes().get(i);
node.setCoordinates(x0 + (i - 1.5) * dx, y);
}
}
}