WireConnection.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.svg;
import com.powsybl.sld.library.AnchorOrientation;
import com.powsybl.sld.library.AnchorPoint;
import com.powsybl.sld.library.Component;
import com.powsybl.sld.library.ComponentLibrary;
import com.powsybl.sld.model.coordinate.Direction;
import com.powsybl.sld.model.coordinate.Orientation;
import com.powsybl.sld.model.coordinate.Point;
import com.powsybl.sld.model.graphs.Graph;
import com.powsybl.sld.model.graphs.VoltageLevelGraph;
import com.powsybl.sld.model.nodes.BusNode;
import com.powsybl.sld.model.nodes.ConnectivityNode;
import com.powsybl.sld.model.nodes.Node;
import java.util.*;
import java.util.stream.Collectors;
/**
* @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 final class WireConnection {
private final AnchorPoint anchorPoint1;
private final AnchorPoint anchorPoint2;
private WireConnection(AnchorPoint anchorPoint1, AnchorPoint anchorPoint2) {
this.anchorPoint1 = Objects.requireNonNull(anchorPoint1);
this.anchorPoint2 = Objects.requireNonNull(anchorPoint2);
}
public static List<AnchorPoint> getAnchorPoints(ComponentLibrary componentLibrary, Node node) {
String componentType = node.getComponentType();
Orientation nodeOrientation = node.getOrientation();
Component.Transformation transformation = componentLibrary.getTransformations(componentType).get(nodeOrientation);
return componentLibrary.getAnchorPoints(componentType)
.stream()
.map(anchorPoint -> anchorPoint.transformAnchorPoint(nodeOrientation, transformation))
.collect(Collectors.toList());
}
public static WireConnection searchBestAnchorPoints(ComponentLibrary componentLibrary, VoltageLevelGraph graph, Node node1, Node node2) {
Objects.requireNonNull(componentLibrary);
Objects.requireNonNull(node1);
Objects.requireNonNull(node2);
List<AnchorPoint> anchorPoints1 = node1 instanceof BusNode ? getBusNodeAnchorPoint(graph, (BusNode) node1, node2) : getAnchorPoints(componentLibrary, node1);
List<AnchorPoint> anchorPoints2 = node2 instanceof BusNode ? getBusNodeAnchorPoint(graph, (BusNode) node2, node1) : getAnchorPoints(componentLibrary, node2);
return searchBestAnchorPoints(node1.getCoordinates(), node2.getCoordinates(), anchorPoints1, anchorPoints2);
}
private static List<AnchorPoint> getBusNodeAnchorPoint(VoltageLevelGraph graph, BusNode busNode, Node otherNode) {
Direction direction = graph.getDirection(otherNode);
boolean undefinedMiddleDirection = direction == Direction.UNDEFINED
&& otherNode.getCoordinates().getY() == busNode.getCoordinates().getY()
&& (otherNode.getCoordinates().getX() < busNode.getCoordinates().getX()
|| otherNode.getCoordinates().getX() > busNode.getCoordinates().getX() + busNode.getPxWidth());
if (direction == Direction.MIDDLE || undefinedMiddleDirection) {
return Arrays.asList(
new AnchorPoint(0, 0, AnchorOrientation.HORIZONTAL),
new AnchorPoint(busNode.getPxWidth(), 0, AnchorOrientation.HORIZONTAL)
);
} else {
return Collections.singletonList(
new AnchorPoint(otherNode.getX() - busNode.getX(), 0, AnchorOrientation.VERTICAL));
}
}
public static AnchorPoint getBestAnchorPoint(ComponentLibrary componentLibrary, Graph graph, Node node, Point point) {
Objects.requireNonNull(componentLibrary);
Objects.requireNonNull(node);
Objects.requireNonNull(point);
List<AnchorPoint> anchorPoints1 = getAnchorPoints(componentLibrary, node);
List<AnchorPoint> anchorPoints2 = Collections.singletonList(new AnchorPoint(0, 0, AnchorOrientation.NONE));
return searchBestAnchorPoints(graph.getShiftedPoint(node), point, anchorPoints1, anchorPoints2).getAnchorPoint1();
}
private static WireConnection searchBestAnchorPoints(Point coord1, Point coord2,
List<AnchorPoint> anchorPoints1,
List<AnchorPoint> anchorPoints2) {
AnchorPoint betterAnchorPoint1 = anchorPoints1.get(0);
AnchorPoint betterAnchorPoint2 = anchorPoints2.get(0);
double currentDistance = coord1.getShiftedPoint(betterAnchorPoint1).distanceSquare(
coord2.getShiftedPoint(betterAnchorPoint2));
for (AnchorPoint anchorPoint1 : anchorPoints1) {
Point shiftedCoord1 = coord1.getShiftedPoint(anchorPoint1);
for (AnchorPoint anchorPoint2 : anchorPoints2) {
double distance = shiftedCoord1.distanceSquare(coord2.getShiftedPoint(anchorPoint2));
if (distance < currentDistance) {
betterAnchorPoint1 = anchorPoint1;
betterAnchorPoint2 = anchorPoint2;
currentDistance = distance;
}
}
}
return new WireConnection(betterAnchorPoint1, betterAnchorPoint2);
}
public AnchorPoint getAnchorPoint1() {
return anchorPoint1;
}
public AnchorPoint getAnchorPoint2() {
return anchorPoint2;
}
/*
* Calculating the polyline points for the voltageLevel graph edge
*/
public List<Point> calculatePolylinePoints(Node node1, Node node2, boolean straight, Point vlGraphCoord) {
Point point1 = node1.getCoordinates().getShiftedPoint(vlGraphCoord).getShiftedPoint(getAnchorPoint1());
Point point2 = node2.getCoordinates().getShiftedPoint(vlGraphCoord).getShiftedPoint(getAnchorPoint2());
if (point1.getX() == point2.getX() && point1.getY() == point2.getY()) {
return Collections.emptyList();
}
List<Point> pol = new ArrayList<>();
pol.add(point1);
if (!straight && point1.getX() != point2.getX() && point1.getY() != point2.getY()) {
if (invertNodes(node1, node2)) {
addMiddlePoints(point2, point1, anchorPoint2, anchorPoint1, pol);
} else {
addMiddlePoints(point1, point2, anchorPoint1, anchorPoint2, pol);
}
}
pol.add(point2);
return pol;
}
private boolean invertNodes(Node node1, Node node2) {
return node2 instanceof ConnectivityNode && ((ConnectivityNode) node2).isShunt()
|| node1.getOrientation() == Orientation.UP && node2.getOrientation() == Orientation.UP && node2.getY() > node1.getY()
|| node1.getOrientation() == Orientation.DOWN && node2.getOrientation() == Orientation.DOWN && node2.getY() < node1.getY();
}
private static void addMiddlePoints(Point pointA, Point pointB, AnchorPoint anchorPointA, AnchorPoint anchorPointB, List<Point> pol) {
double xA = pointA.getX();
double yA = pointA.getY();
double xB = pointB.getX();
double yB = pointB.getY();
switch (anchorPointA.getOrientation()) {
case VERTICAL:
if (anchorPointB.getOrientation() == AnchorOrientation.VERTICAL) {
double mid = (yA + yB) / 2;
pol.addAll(Point.createPointsList(xA, mid, xB, mid));
} else {
pol.add(new Point(xA, yB));
}
break;
case HORIZONTAL:
if (anchorPointB.getOrientation() == AnchorOrientation.HORIZONTAL) {
double mid = (xA + xB) / 2;
pol.addAll(Point.createPointsList(mid, yA, mid, yB));
} else {
pol.add(new Point(xB, yA));
}
break;
case NONE:
if (anchorPointB.getOrientation() == AnchorOrientation.HORIZONTAL) {
pol.add(new Point(xA, yB));
} else {
pol.add(new Point(xB, yA));
}
break;
default:
break;
}
}
}