package games.strategy.triplea.ui.logic; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class RouteCalculator { public final boolean isInfiniteY; public final boolean isInfiniteX; private Point endPoint; private final int mapWidth; private final int mapHeight; public RouteCalculator(boolean isInfiniteX, boolean isInfiniteY, int mapWidth, int mapHeight) { this.isInfiniteX = isInfiniteX; this.isInfiniteY = isInfiniteY; this.mapWidth = mapWidth; this.mapHeight = mapHeight; } /** * Algorithm for finding the shortest path for the given Route. * * @param route The joints on the Map * @return A Point array which goes through Map Borders if necessary */ public Point[] getTranslatedRoute(Point... route) { if (route == null || route.length == 0) { // Or the array is too small return route; } if (!isInfiniteX && !isInfiniteY) { // If the Map is not infinite scrolling, we can safely return the given Points endPoint = route[route.length - 1]; return route; } List<Point> result = new ArrayList<>(); Point previousPoint = null; for (Point point : route) { if (previousPoint == null) { previousPoint = point; result.add(point); continue; } Point closestPoint = getClosestPoint(previousPoint, getPossiblePoints(point)); result.add(closestPoint); previousPoint = closestPoint; } endPoint = result.get(result.size() - 1); return result.toArray(new Point[result.size()]); } /** * Returns the Closest Point out of the given Pool. * * @param source the reference Point * @param pool Point List with all possible options * @return the closest point in the Pool to the source */ public static Point getClosestPoint(Point source, List<Point> pool) { double closestDistance = Double.MAX_VALUE; Point closestPoint = null; for (Point possibleClosestPoint : pool) { if (closestPoint == null) { closestDistance = source.distance(possibleClosestPoint); closestPoint = possibleClosestPoint; } else { double distance = source.distance(possibleClosestPoint); if (closestDistance > distance) { closestPoint = possibleClosestPoint; closestDistance = distance; } } } return closestPoint; } /** * Method for getting Points, which are a mapHeight/Width away from the actual Point * Used to display routes with higher offsets than the map width/height. * * @param point The Point to "clone" * @return A List of all possible Points depending in map Properties * size may vary */ public List<Point> getPossiblePoints(Point point) { List<Point> result = new ArrayList<>(); result.add(point); if (isInfiniteX && isInfiniteY) { result.addAll(Arrays.asList( new Point(point.getX() - mapWidth, point.getY() - mapHeight), new Point(point.getX() - mapWidth, point.getY() + mapHeight), new Point(point.getX() + mapWidth, point.getY() - mapHeight), new Point(point.getX() + mapWidth, point.getY() + mapHeight))); } if (isInfiniteX) { result.addAll(Arrays.asList( new Point(point.getX() - mapWidth, point.getY()), new Point(point.getX() + mapWidth, point.getY()))); } if (isInfiniteY) { result.addAll(Arrays.asList( new Point(point.getX(), point.getY() - mapHeight), new Point(point.getX(), point.getY() + mapHeight))); } return result; } public Point getLastEndPoint() { return endPoint; } /** * Matrix Transpose method to transpose the 2dimensional point list. * * @param points A Point array * @return Offset Point Arrays including points */ public List<Point[]> getAllPoints(Point... points) { List<Point[]> allPoints = new ArrayList<>(); for (int i = 0; i < points.length; i++) { List<Point> subPoints = getPossiblePoints(points[i]); for (int y = 0; y < subPoints.size(); y++) { if (i == 0) { allPoints.add(new Point[points.length]); } allPoints.get(y)[i] = (subPoints.get(y)); } } return allPoints; } /** * Generates a List of Lines which represent "normalized forms" of the given arrays. * * @param xcoords an array of xCoordinates * @param ycoords an array of yCoordinates * @return a List of corresponding Lines */ private List<Line> getNormalizedLines(double[] xcoords, double[] ycoords) { List<Line> lines = new ArrayList<>(); Point previousPoint = null; for (int i = 0; i < xcoords.length; i++) { Point trimmedPoint = new Point(xcoords[i], ycoords[i]); if (previousPoint != null) { lines.add(new Line(previousPoint, trimmedPoint)); } previousPoint = trimmedPoint; } return lines; } /** * A List of Lines which represent all possible lines on multiple screens size may vary. * * @param xcoords an array of xCoordinates * @param ycoords an array of yCoordinates * @return a List of corresponding Lines on every possible screen */ public List<Line> getAllNormalizedLines(double[] xcoords, double[] ycoords) { List<Line> centerLines = getNormalizedLines(xcoords, ycoords); List<Line> result = new ArrayList<>(); for (Line line : centerLines) { List<Point[]> allPoints = getAllPoints(line.getP1(), line.getP2()); for (Point[] points : allPoints) { result.add(new Line(points[0], points[1])); } } return result; } }