Skip to content

Commit

Permalink
Height is computated by row & width is computed by column
Browse files Browse the repository at this point in the history
Signed-off-by: Thomas ADAM <[email protected]>
  • Loading branch information
tadam50 committed Jan 25, 2024
1 parent dea8dce commit f72bc9c
Show file tree
Hide file tree
Showing 15 changed files with 1,015 additions and 943 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
*/
package com.powsybl.sld.layout;

import com.powsybl.sld.model.graphs.SubstationGraph;
import com.powsybl.sld.model.graphs.VoltageLevelGraph;
import com.powsybl.sld.model.graphs.ZoneGraph;
import com.powsybl.sld.layout.pathfinding.*;
import com.powsybl.sld.model.graphs.*;
import com.powsybl.sld.model.nodes.*;

import java.util.*;
Expand All @@ -20,7 +19,8 @@
public abstract class AbstractZoneLayout extends AbstractBaseLayout<ZoneGraph> {
protected SubstationLayoutFactory sLayoutFactory;
protected VoltageLevelLayoutFactory vLayoutFactory;
protected Map<SubstationGraph, AbstractLayout<SubstationGraph>> layoutBySubstation;
protected Map<BaseGraph, AbstractLayout<SubstationGraph>> layoutBySubstation;
protected PathFinder pathFinder;

protected AbstractZoneLayout(ZoneGraph graph, SubstationLayoutFactory sLayoutFactory, VoltageLevelLayoutFactory vLayoutFactory) {
super(graph);
Expand All @@ -35,6 +35,8 @@ protected AbstractZoneLayout(ZoneGraph graph, SubstationLayoutFactory sLayoutFac

@Override
public void run(LayoutParameters layoutParameters) {
pathFinder = new PathFinderFactory().create(layoutParameters.getZoneLayoutPathFinder());

// Calculate all the coordinates for the substation graphs in the zone graph
calculateCoordSubstations(layoutParameters);

Expand All @@ -44,7 +46,7 @@ public void run(LayoutParameters layoutParameters) {

protected abstract void calculateCoordSubstations(LayoutParameters layoutParameters);

protected void move(SubstationGraph subGraph, double dx, double dy) {
protected void move(BaseGraph subGraph, double dx, double dy) {
for (VoltageLevelGraph vlGraph : subGraph.getVoltageLevels()) {
vlGraph.setCoord(vlGraph.getX() + dx, vlGraph.getY() + dy);
vlGraph.getLineEdges().forEach(s -> s.shiftSnakeLine(dx, dy));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
package com.powsybl.sld.layout;

import com.powsybl.commons.*;
import com.powsybl.sld.layout.pathfinding.*;
import com.powsybl.sld.layout.zonebygrid.*;
import com.powsybl.sld.model.coordinate.*;
import com.powsybl.sld.model.coordinate.Point;
Expand All @@ -23,55 +22,57 @@
*/
public class MatrixZoneLayout extends AbstractZoneLayout {
private final MatrixZoneLayoutModel model;
private final String[][] matrix;

protected MatrixZoneLayout(ZoneGraph graph, String[][] matrix, SubstationLayoutFactory sLayoutFactory, VoltageLevelLayoutFactory vLayoutFactory) {
super(graph, sLayoutFactory, vLayoutFactory);
this.model = new MatrixZoneLayoutModel();
this.matrix = matrix;
}

/**
* Calculate relative coordinate of substations in the zone
*/
@Override
protected void calculateCoordSubstations(LayoutParameters layoutParameters) {
this.model = new MatrixZoneLayoutModel(Objects.requireNonNull(matrix));
for (int row = 0; row < matrix.length; row++) {
for (int col = 0; col < matrix[row].length; col++) {
String id = matrix[row][col];
SubstationGraph graph = getGraph().getSubstationGraph(id);
if (graph != null) {
// Display substations
layoutBySubstation.get(graph).run(layoutParameters);
} else if (!id.isEmpty()) {
SubstationGraph sGraph = graph.getSubstationGraph(id);
if (sGraph == null && !id.isEmpty()) {
throw new PowsyblException("Substation '" + id + "' was not found in zone graph '" + getGraph().getId() + "'");
}
model.addSubstationSubgraph(graph, col, row);
model.addSubstationGraph(sGraph, row, col);
}
}
}

/**
* Calculate relative coordinate of substations in the zone
*/
@Override
protected void calculateCoordSubstations(LayoutParameters layoutParameters) {
Matrix matrix = model.getMatrix();
// Display substations on not empty Matrix cell
matrix.stream().filter(c -> !c.isEmpty()).map(MatrixCell::graph).forEach(graph -> layoutBySubstation.get(graph).run(layoutParameters));
// Height by rows
int maxHeightRow = model.getMatrixCellHeight();
int maxHeightRow = 0;
// Width by col
int maxWidthCol = model.getMatrixCellWidth();
int maxWidthCol = 0;
// Snakeline hallway (horizontal & vertical)
int snakelineMargin = (int) layoutParameters.getZoneLayoutSnakeLinePadding();
// Zone size
int nbRows = matrix.length;
int nbCols = matrix[0].length;
int nbRows = matrix.rowCount();
int nbCols = matrix.columnCount();
// Move each substation into its matrix position
for (int row = 0; row < nbRows; row++) {
maxWidthCol = 0;
for (int col = 0; col < nbCols; col++) {
String id = matrix[row][col];
SubstationGraph graph = getGraph().getSubstationGraph(id);
MatrixCell cell = matrix.get(row, col);
BaseGraph graph = cell.graph();
if (graph != null) {
double dx = col * maxWidthCol + (col + 1.0) * snakelineMargin;
double dy = row * maxHeightRow + (row + 1.0) * snakelineMargin;
double dx = maxWidthCol + (col + 1.0) * snakelineMargin;
double dy = maxHeightRow + (row + 1.0) * snakelineMargin;
move(graph, dx, dy);
}
maxWidthCol += matrix.getMatrixCellWidth(col);
}
double tmp = matrix.getMatrixCellHeight(row);
maxHeightRow += tmp;
}
double zoneWidth = nbCols * maxWidthCol + (nbCols + 1.0) * snakelineMargin;
double zoneHeight = nbRows * maxHeightRow + (nbRows + 1.0) * snakelineMargin;
double zoneWidth = maxWidthCol + (nbCols + 1.0) * snakelineMargin;
double zoneHeight = maxHeightRow + (nbRows + 1.0) * snakelineMargin;
getGraph().setSize(zoneWidth, zoneHeight);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Copyright (c) 2023, 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.layout.zonebygrid;

import com.powsybl.sld.model.graphs.*;

import java.util.*;
import java.util.stream.*;

/**
* @author Thomas Adam {@literal <tadam at neverhack.com>}
*/
public class Matrix {
// [row] [col]
private final MatrixCell[][] cells;

public Matrix(int rows, int cols) {
cells = new MatrixCell[rows][cols];
}

public Matrix set(int row, int col, MatrixCell cell) {
cells[row][col] = cell;
return this;
}

public MatrixCell get(int row, int col) {
return cells[row][col];
}

public Stream<MatrixCell> stream() {
return Arrays.stream(cells).flatMap(Arrays::stream);
}

public double getMatrixCellHeight(int row) {
return Stream.of(cells[row]).filter(cell -> !cell.isEmpty()).mapToDouble(cell -> cell.graph().getHeight()).max().orElse(0.0);
}

public double getMatrixCellWidth(int col) {
double maxWidth = 0.0;
for (int row = 0; row < rowCount(); row++) {
BaseGraph graph = cells[row][col].graph();
if (graph != null) {
maxWidth = Math.max(maxWidth, graph.getWidth());
}
}
return maxWidth;
}

public int rowCount() {
return cells.length;
}

public int columnCount() {
return cells[0].length;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,12 @@
/**
* @author Thomas Adam {@literal <tadam at neverhack.com>}
*/
public record MatrixCell(BaseGraph graph, int col, int row) {
public record MatrixCell(BaseGraph graph, int row, int col) {
public boolean isEmpty() {
return graph() == null;
}

public String getId() {
return graph == null ? "" : graph.getId();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,45 +20,32 @@
*/
public class MatrixZoneLayoutModel {

private final Map<String, MatrixCell> cellsById = new HashMap<>();
private final List<MatrixCell> emptyCells = new ArrayList<>();

private int matrixNbRow = 0;

private int matrixNbCol = 0;

private int matrixCellHeight = -1;

private int matrixCellWidth = -1;
private final Matrix matrix;

private Grid pathFinderGrid;

public void addSubstationSubgraph(SubstationGraph graph, int col, int row) {
if (graph != null) {
cellsById.put(graph.getId(), new MatrixCell(graph, col, row));
matrixCellHeight = Math.max(matrixCellHeight, (int) graph.getHeight());
matrixCellWidth = Math.max(matrixCellWidth, (int) graph.getWidth());
} else {
emptyCells.add(new MatrixCell(null, col, row));
}
matrixNbRow = Math.max(matrixNbRow, row + 1);
matrixNbCol = Math.max(matrixNbCol, col + 1);
public MatrixZoneLayoutModel(String[][] ids) {
this.matrix = new Matrix(ids.length, ids[0].length);
}

public int getMatrixCellWidth() {
return matrixCellWidth;
}

public int getMatrixCellHeight() {
return matrixCellHeight;
public void addSubstationGraph(SubstationGraph graph, int row, int col) {
this.matrix.set(row, col, new MatrixCell(graph, row, col));
}

private int getX(int col, double snakelineMargin) {
return ((col + 1) * (int) snakelineMargin) + (col * matrixCellWidth);
int matrixCellWidth = 0;
for (int c = 0; c < col; c++) {
matrixCellWidth += matrix.getMatrixCellWidth(c);
}
return ((col + 1) * (int) snakelineMargin) + matrixCellWidth;
}

private int getY(int row, double snakelineMargin) {
return (row + 1) * (int) snakelineMargin + row * matrixCellHeight;
int matrixCellHeight = 0;
for (int r = 0; r < row; r++) {
matrixCellHeight += matrix.getMatrixCellHeight(r);
}
return (row + 1) * (int) snakelineMargin + matrixCellHeight;
}

public List<Point> buildSnakeline(PathFinder pathfinder,
Expand Down Expand Up @@ -92,21 +79,22 @@ public void computePathFindingGrid(ZoneGraph graph, LayoutParameters layoutParam

pathFinderGrid = new Grid(width, height);

// Matrix cells grid lines
computeMatrixCellsAvailability(layoutParameters);

// Horizontal hallways lines
computeHorizontalHallwaysAvailability(width, height, layoutParameters);

// Vertical hallways lines
computeVerticalHallwaysAvailability(width, height, layoutParameters);

// Substations are not available
// Make available all matrix cells
computeMatrixCellsAvailability(layoutParameters);

// Make unavailable all voltagelevels
computeSubstationsAvailability(layoutParameters);
}

private void computeSubstationsAvailability(LayoutParameters layoutParameters) {
cellsById.values().forEach(cell -> {
// For each not empty cells
matrix.stream().filter(c -> !c.isEmpty()).forEach(cell -> {
BaseGraph graph = cell.graph();
graph.getVoltageLevelStream().forEach(vlGraph -> {
double elementaryWidth = layoutParameters.getCellWidth() / 2; // the elementary step within a voltageLevel Graph is half a cell width
Expand All @@ -126,19 +114,21 @@ private void computeSubstationsAvailability(LayoutParameters layoutParameters) {

private void computeMatrixCellsAvailability(LayoutParameters layoutParameters) {
int snakelineMargin = (int) layoutParameters.getZoneLayoutSnakeLinePadding();
List<MatrixCell> allCells = new ArrayList<>(cellsById.values().stream().toList());
// Make empty cells available for snakeline computation
allCells.addAll(emptyCells);
List<MatrixCell> allCells = matrix.stream().toList();
allCells.forEach(cell -> {
double matrixCellWidth = matrix.getMatrixCellWidth(cell.col());
double matrixCellHeight = matrix.getMatrixCellHeight(cell.row());
int ssX = getX(cell.col(), snakelineMargin);
int ssY = getY(cell.row(), snakelineMargin);
for (int x = ssX - snakelineMargin; x < ssX - snakelineMargin + matrixCellWidth + snakelineMargin; x++) {
for (int y = ssY - snakelineMargin; y < ssY - snakelineMargin + matrixCellHeight + snakelineMargin; y += layoutParameters.getHorizontalSnakeLinePadding()) {

for (int x = ssX - snakelineMargin; x < ssX + matrixCellWidth + snakelineMargin; x++) {
for (int y = ssY - snakelineMargin; y < ssY + matrixCellHeight + snakelineMargin; y += layoutParameters.getHorizontalSnakeLinePadding()) {
pathFinderGrid.setAvailability(x, y, true);
}
}
for (int x = ssX - snakelineMargin; x < ssX - snakelineMargin + matrixCellWidth + snakelineMargin; x += layoutParameters.getVerticalSnakeLinePadding()) {
for (int y = ssY - snakelineMargin; y < ssY - snakelineMargin + matrixCellHeight + snakelineMargin; y++) {
for (int x = ssX - snakelineMargin; x < ssX + matrixCellWidth + snakelineMargin; x += layoutParameters.getVerticalSnakeLinePadding()) {
for (int y = ssY - snakelineMargin; y < ssY + matrixCellHeight + snakelineMargin; y++) {
pathFinderGrid.setAvailability(x, y, true);
}
}
Expand All @@ -147,20 +137,28 @@ private void computeMatrixCellsAvailability(LayoutParameters layoutParameters) {

private void computeHorizontalHallwaysAvailability(int width, int height, LayoutParameters layoutParameters) {
int snakelineMargin = (int) layoutParameters.getZoneLayoutSnakeLinePadding();
for (int r = 0; r < matrixNbRow; r++) {
int nextY = 0;
for (int r = 0; r < matrix.rowCount(); r++) {
double matrixCellHeight = matrix.getMatrixCellHeight(r);
for (int x = 0; x < width; x++) {
for (int hy = 0; hy < height; hy += snakelineMargin + matrixCellHeight) {
for (int y = hy; y < hy + snakelineMargin; y += layoutParameters.getHorizontalSnakeLinePadding()) {
pathFinderGrid.setAvailability(x, y, true);
}
for (int y = nextY; y < nextY + snakelineMargin; y += layoutParameters.getHorizontalSnakeLinePadding()) {
pathFinderGrid.setAvailability(x, y, true);
}
}
nextY += snakelineMargin + matrixCellHeight;
}
// Last snakelineMargin
for (int x = 0; x < width; x++) {
for (int y = nextY; y < nextY + snakelineMargin; y += layoutParameters.getHorizontalSnakeLinePadding()) {
pathFinderGrid.setAvailability(x, y, true);
}
}
}

private void computeVerticalHallwaysAvailability(int width, int height, LayoutParameters layoutParameters) {
int snakelineMargin = (int) layoutParameters.getZoneLayoutSnakeLinePadding();
for (int c = 0; c < matrixNbCol; c++) {
for (int c = 0; c < matrix.columnCount(); c++) {
double matrixCellWidth = matrix.getMatrixCellWidth(c);
for (int y = 0; y < height; y++) {
for (int hx = 0; hx < width; hx += snakelineMargin + matrixCellWidth) {
for (int x = hx; x < hx + snakelineMargin; x += layoutParameters.getVerticalSnakeLinePadding()) {
Expand All @@ -171,8 +169,12 @@ private void computeVerticalHallwaysAvailability(int width, int height, LayoutPa
}
}

public boolean contains(String id) {
Objects.requireNonNull(id);
return cellsById.containsKey(id);
public boolean contains(String otherId) {
Objects.requireNonNull(otherId);
return matrix.stream().map(MatrixCell::getId).anyMatch(id -> id.equals(otherId));
}

public Matrix getMatrix() {
return matrix;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,8 @@ void testInvalidZoneGraphMatrix() {

// Run matrix zone layout
String[][] substationsIds = {{"B", "A"}};
Layout layout = new MatrixZoneLayoutFactory().create(g, substationsIds, new HorizontalSubstationLayoutFactory(), new PositionVoltageLevelLayoutFactory());

PowsyblException e = assertThrows(PowsyblException.class, () -> layout.run(layoutParameters));
PowsyblException e = assertThrows(PowsyblException.class, () -> new MatrixZoneLayoutFactory().create(g, substationsIds, new HorizontalSubstationLayoutFactory(), new PositionVoltageLevelLayoutFactory()));
assertEquals("Substation 'A' was not found in zone graph 'B_C'", e.getMessage());
}
}
Loading

0 comments on commit f72bc9c

Please sign in to comment.