diff --git a/src/games/strategy/triplea/ui/MapRouteDrawer.java b/src/games/strategy/triplea/ui/MapRouteDrawer.java index 88204806aae..8e1bf2febdd 100644 --- a/src/games/strategy/triplea/ui/MapRouteDrawer.java +++ b/src/games/strategy/triplea/ui/MapRouteDrawer.java @@ -2,6 +2,7 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Image; @@ -60,20 +61,20 @@ public void drawRoute(final Graphics2D graphics, final RouteDescription routeDes final int yOffset = mapPanel.getYOffset(); final int imageWidth = mapPanel.getImageWidth(); final int imageHeight = mapPanel.getImageHeight(); + final Dimension imageDimension = new Dimension(imageWidth, imageHeight); final Point[] points = - getRoutePoints(routeDescription, mapData, xOffset, yOffset, imageWidth, imageHeight); + getRoutePoints(routeDescription, mapData, xOffset, yOffset, imageDimension); final boolean tooFewTerritories = numTerritories <= 1; final boolean tooFewPoints = points.length <= 2; final double scale = mapPanel.getScale(); if (tooFewTerritories || tooFewPoints) { - if (routeDescription.getEnd() != null) {//AI has no End Point - drawDirectPath(graphics, getPointOnMap(routeDescription.getStart(), xOffset, yOffset, imageWidth, imageHeight), - getPointOnMap(routeDescription.getEnd(), xOffset, yOffset, imageWidth, imageHeight), xOffset, yOffset, - scale); + if (routeDescription.getEnd() != null) {// AI has no End Point + drawDirectPath(graphics, + getPointOnMap(routeDescription.getStart(), xOffset, yOffset, imageDimension), + getPointOnMap(routeDescription.getEnd(), xOffset, yOffset, imageDimension), xOffset, yOffset, scale); } else { - drawDirectPath(graphics, getPointOnMap(points[0], xOffset, yOffset, imageWidth, imageHeight), - getPointOnMap(points[points.length - 1], xOffset, yOffset, imageWidth, imageHeight), xOffset, yOffset, - scale); + drawDirectPath(graphics, getPointOnMap(points[0], xOffset, yOffset, imageDimension), + getPointOnMap(points[points.length - 1], xOffset, yOffset, imageDimension), xOffset, yOffset, scale); } if (tooFewPoints && !tooFewTerritories) { drawMoveLength(graphics, points, xOffset, yOffset, scale, numTerritories, maxMovement); @@ -83,7 +84,7 @@ public void drawRoute(final Graphics2D graphics, final RouteDescription routeDes drawMoveLength(graphics, points, xOffset, yOffset, scale, numTerritories, maxMovement); } drawJoints(graphics, points, xOffset, yOffset, scale); - drawCustomCursor(graphics, routeDescription, xOffset, yOffset, scale); + drawCustomCursor(graphics, routeDescription, xOffset, yOffset, scale, imageDimension); } /** @@ -116,12 +117,13 @@ private void drawJoints(Graphics2D graphics, Point[] points, int xOffset, int yO * @param scale The scale-factor of the Map */ private void drawCustomCursor(Graphics2D graphics, RouteDescription routeDescription, int xOffset, int yOffset, - double scale) { + double scale, Dimension imageDimension) { final Image cursorImage = routeDescription.getCursorImage(); if (cursorImage != null) { + Point wrappedEndPoint = getPointOnMap(routeDescription.getEnd(), xOffset, yOffset, imageDimension); graphics.drawImage(cursorImage, - (int) (((routeDescription.getEnd().x - xOffset) - (cursorImage.getWidth(null) / 2)) * scale), - (int) (((routeDescription.getEnd().y - yOffset) - (cursorImage.getHeight(null) / 2)) * scale), null); + (int) (((wrappedEndPoint.x - xOffset) - (cursorImage.getWidth(null) / 2)) * scale), + (int) (((wrappedEndPoint.y - yOffset) - (cursorImage.getHeight(null) / 2)) * scale), null); } } @@ -198,25 +200,26 @@ private void drawLineWithTranslate(Graphics2D graphics, Line2D line, double xOff * objects */ protected Point[] getRoutePoints(RouteDescription routeDescription, MapData mapData, int xOffset, int yOffset, - int width, int height) { + Dimension imageDimension) { final List territories = routeDescription.getRoute().getAllTerritories(); final int numTerritories = territories.size(); final Point[] points = new Point[numTerritories]; for (int i = 0; i < numTerritories; i++) { - points[i] = getPointOnMap(mapData.getCenter(territories.get(i)), xOffset, yOffset, width, height); + points[i] = getPointOnMap(mapData.getCenter(territories.get(i)), xOffset, yOffset, imageDimension); } if (routeDescription.getStart() != null) { - points[0] = getPointOnMap(routeDescription.getStart(), xOffset, yOffset, width, height); + points[0] = getPointOnMap(routeDescription.getStart(), xOffset, yOffset, imageDimension); } if (routeDescription.getEnd() != null && numTerritories > 1) { points[numTerritories - 1] = - getPointOnMap(routeDescription.getEnd(), xOffset, yOffset, width, height); + getPointOnMap(routeDescription.getEnd(), xOffset, yOffset, imageDimension); } return points; } /** - * This method ensures that Points are drawn correctly, even on an infinite-scroll Map + * This method moves point one width/length on an infinite-scroll Map + * so that they route goes beyond non existent borders * * @param point The reference {@linkplain Point} * @param xOffset The horizontal pixel-difference between the frame and the Map @@ -225,22 +228,26 @@ protected Point[] getRoutePoints(RouteDescription routeDescription, MapData mapD * @param height The height of the Map * @return The "real" Point */ - private static Point getPointOnMap(Point point, int xOffset, int yOffset, int width, int height) { - Point newPoint = point; - int x = (int) newPoint.getX(); - int y = (int) newPoint.getY(); + protected static Point getPointOnMap(Point point, int xOffset, int yOffset, Dimension dimension) { + Point newPoint = null; + int x = (int) point.getX(); + int y = (int) point.getY(); + int width = dimension.width; + int height = dimension.height; if (x - width > xOffset) { newPoint = new Point(x - width, y); - } else if (x - width > 0) { + x = (int) newPoint.getX(); + } else if (x < xOffset) { newPoint = new Point(x + width, y); + x = (int) newPoint.getX(); } - x = (int) newPoint.getX();// If the value changed if (y - height > yOffset) { newPoint = new Point(x, y - height); - } else if (y - height > 0) { + } + if (y < yOffset) { newPoint = new Point(x, y + height); } - return newPoint; + return newPoint != null ? newPoint : point; } /** diff --git a/test/games/strategy/triplea/ui/TestRoute.java b/test/games/strategy/triplea/ui/TestRoute.java index 51ba079ae11..3a16e8557e3 100644 --- a/test/games/strategy/triplea/ui/TestRoute.java +++ b/test/games/strategy/triplea/ui/TestRoute.java @@ -10,6 +10,7 @@ import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.times; +import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Shape; @@ -26,57 +27,83 @@ public class TestRoute { private MapRouteDrawer spyRouteDrawer = spy(new MapRouteDrawer()); - private Point[] dummyPoints = new Point[]{new Point(0,0), new Point(100,0), new Point(0,100)}; + private Point[] dummyPoints = new Point[] {new Point(0, 0), new Point(100, 0), new Point(0, 100)}; private double[] dummyIndex = spyRouteDrawer.createParameterizedIndex(dummyPoints); private Route dummyRoute = spy(new Route()); private MapData dummyMapData = mock(MapData.class); - private RouteDescription dummyRouteDescription = spy(new RouteDescription(dummyRoute, dummyPoints[0], dummyPoints[2], null)); - + private RouteDescription dummyRouteDescription = + spy(new RouteDescription(dummyRoute, dummyPoints[0], dummyPoints[2], null)); + @Before - public void setUp(){ - dummyRoute.add(mock(Territory.class));//This will be overridden with the startPoint, since it's the origin territory + public void setUp() { + dummyRoute.add(mock(Territory.class));// This will be overridden with the startPoint, since it's the origin + // territory dummyRoute.add(mock(Territory.class)); when(dummyMapData.getCenter(any(Territory.class))).thenReturn(dummyPoints[1]); } - + @Test - public void testIndex(){ - assertArrayEquals(spyRouteDrawer.createParameterizedIndex(new Point[]{}), new double[]{}, 0); + public void testIndex() { + assertArrayEquals(spyRouteDrawer.createParameterizedIndex(new Point[] {}), new double[] {}, 0); assertEquals(dummyIndex.length, dummyPoints.length); - //Not sure whether it makes sense to include a Test for specific values - //The way the index is being calculated may change to a better System - //Check the link for more information - //http://stackoverflow.com/a/37370620/5769952 + // Not sure whether it makes sense to include a Test for specific values + // The way the index is being calculated may change to a better System + // Check the link for more information + // http://stackoverflow.com/a/37370620/5769952 } - + @Test - public void testCurve(){ - final double[] testYValues = new double[]{20, 40, 90}; + public void testCurve() { + final double[] testYValues = new double[] {20, 40, 90}; final PolynomialSplineFunction testFunction = new SplineInterpolator().interpolate(dummyIndex, testYValues); final double[] coords = spyRouteDrawer.getCoords(testFunction, dummyIndex); final double stepSize = testFunction.getKnots()[testFunction.getKnots().length - 1] / coords.length; - assertEquals(testYValues[0] * stepSize, coords[(int)Math.round(dummyIndex[0])], 1); - assertEquals(testYValues[1] * stepSize, coords[(int)Math.round(dummyIndex[1])], 1); - assertEquals(testYValues[2] * stepSize, coords[(int)Math.round(dummyIndex[2])], 1); - //TODO change the calculation so that delta = 0; + assertEquals(testYValues[0] * stepSize, coords[(int) Math.round(dummyIndex[0])], 1); + assertEquals(testYValues[1] * stepSize, coords[(int) Math.round(dummyIndex[1])], 1); + assertEquals(testYValues[2] * stepSize, coords[(int) Math.round(dummyIndex[2])], 1); + // TODO change the calculation so that delta = 0; } - + @Test - public void testPointSplitting(){ - double[] xCoords = new double[]{0, 100, 0}; - double[] yCoords = new double[]{0, 0, 100}; + public void testPointSplitting() { + double[] xCoords = new double[] {0, 100, 0}; + double[] yCoords = new double[] {0, 0, 100}; assertArrayEquals(xCoords, spyRouteDrawer.getValues(dummyPoints, point -> point.getX()), 0); assertArrayEquals(yCoords, spyRouteDrawer.getValues(dummyPoints, point -> point.getY()), 0); } - + @Test - public void testPointAcquisition(){ - assertArrayEquals(dummyPoints, spyRouteDrawer.getRoutePoints(dummyRouteDescription, dummyMapData, 0, 0, 0, 0)); + public void testPointAcquisition() { + assertArrayEquals(dummyPoints, + spyRouteDrawer.getRoutePoints(dummyRouteDescription, dummyMapData, 0, 0, new Dimension(0, 0))); + for (int i = 0; i < 10; i++) { + assertArrayEquals(dummyPoints, spyRouteDrawer.getRoutePoints(dummyRouteDescription, dummyMapData, randomInt(), + randomInt(), new Dimension(0, 0))); + assertArrayEquals(dummyPoints, spyRouteDrawer.getRoutePoints(dummyRouteDescription, dummyMapData, 0, 0, + new Dimension(randomInt(1000, 100), randomInt(1000, 100)))); + int randX = randomInt(1000, 0); + int randY = randomInt(1000, 0); + assertEquals(new Point(randX, randY), + MapRouteDrawer.getPointOnMap(new Point(), randX, randY, new Dimension(randX, randY))); + } } - + + private static int randomInt(int max, int min) { + if (max - min < 0) { + int oldMax = max; + max = min; + min = oldMax; + } + return (int) ((Math.random() * (max - min)) + min); + } + + private static int randomInt() { + return randomInt(1000, -1000); + } + @Test - public void testCorrectParameterHandling(){ - //Should not throw any exception - should do nothing + public void testCorrectParameterHandling() { + // Should not throw any exception - should do nothing spyRouteDrawer.drawRoute(null, null, null, null, null); MapPanel mockedMapPanel = mock(MapPanel.class); when(mockedMapPanel.getXOffset()).thenReturn(0); @@ -88,10 +115,10 @@ public void testCorrectParameterHandling(){ when(mockGraphics.getClip()).thenReturn(mockShape); spyRouteDrawer.drawRoute(mockGraphics, dummyRouteDescription, mockedMapPanel, dummyMapData, "2"); verify(mockGraphics, atLeastOnce()).draw(any(Line2D.class)); - verify(mockedMapPanel).getXOffset();//Those methods are needed + verify(mockedMapPanel).getXOffset();// Those methods are needed verify(mockedMapPanel).getYOffset(); verify(mockedMapPanel).getScale(); - + verify(dummyRouteDescription, times(2)).getRoute(); verify(dummyRouteDescription.getRoute(), atLeastOnce()).getAllTerritories(); }