// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.data.imagery; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Rule; import org.junit.Test; import org.openstreetmap.gui.jmapviewer.TileXY; import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; import org.openstreetmap.gui.jmapviewer.tilesources.TemplatedTMSTileSource; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.Bounds; import org.openstreetmap.josm.data.coor.EastNorth; import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.projection.CustomProjection; import org.openstreetmap.josm.data.projection.Projection; import org.openstreetmap.josm.data.projection.Projections; import org.openstreetmap.josm.testutils.JOSMTestRules; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; /** * Unit tests for class {@link TemplatedWMSTileSource}. */ public class TemplatedWMSTileSourceTest { private final ImageryInfo testImageryWMS = new ImageryInfo("test imagery", "http://localhost", "wms", null, null); private final ImageryInfo testImageryTMS = new ImageryInfo("test imagery", "http://localhost", "tms", null, null); /** * Setup test. */ @Rule @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") public JOSMTestRules test = new JOSMTestRules(); /** * Test EPSG:3857 */ @Test public void testEPSG3857() { Projection projection = Projections.getProjectionByCode("EPSG:3857"); Main.setProjection(projection); TemplatedWMSTileSource source = new TemplatedWMSTileSource(testImageryWMS, projection); verifyMercatorTile(source, 0, 0, 1); verifyMercatorTile(source, 0, 0, 2); verifyMercatorTile(source, 0, 1, 2); verifyMercatorTile(source, 1, 0, 2); verifyMercatorTile(source, 1, 1, 2); for (int x = 0; x < 4; x++) { for (int y = 0; y < 4; y++) { verifyMercatorTile(source, x, y, 3); verifyTileSquarness(source, x, y, 3); } } verifyTileSquarness(source, 150, 20, 18); verifyTileSquarness(source, 2270, 1323, 12); verifyLocation(source, new LatLon(53.5937132, 19.5652017)); verifyLocation(source, new LatLon(53.501565692302854, 18.54455233898721)); } /** * Test EPSG:4326 */ @Test public void testEPSG4326() { Projection projection = Projections.getProjectionByCode("EPSG:4326"); Main.setProjection(projection); TemplatedWMSTileSource source = getSource(projection); verifyLocation(source, new LatLon(53.5937132, 19.5652017)); verifyLocation(source, new LatLon(53.501565692302854, 18.54455233898721)); verifyTileSquarness(source, 2, 2, 2); verifyTileSquarness(source, 150, 20, 18); verifyTileSquarness(source, 2270, 1323, 12); } /** * Test EPSG:4326 - wide bounds */ @Test public void testEPSG4326widebounds() { Projection projection = new CustomProjection("+proj=lonlat +datum=WGS84 +axis=neu +bounds=-180,53,180,54"); Main.setProjection(projection); TemplatedWMSTileSource source = getSource(projection); verifyLocation(source, new LatLon(53.5937132, 19.5652017)); verifyLocation(source, new LatLon(53.501565692302854, 18.54455233898721)); } /** * Test EPSG:4326 - narrow bounds */ @Test public void testEPSG4326narrowbounds() { Projection projection = new CustomProjection("+proj=lonlat +datum=WGS84 +axis=neu +bounds=18,-90,20,90"); Main.setProjection(projection); TemplatedWMSTileSource source = getSource(projection); verifyLocation(source, new LatLon(53.5937132, 19.5652017)); verifyLocation(source, new LatLon(53.501565692302854, 18.54455233898721)); } /** * Test EPSG:2180 */ @Test public void testEPSG2180() { Projection projection = Projections.getProjectionByCode("EPSG:2180"); Main.setProjection(projection); TemplatedWMSTileSource source = getSource(projection); verifyLocation(source, new LatLon(53.5937132, 19.5652017)); verifyLocation(source, new LatLon(53.501565692302854, 18.54455233898721)); verifyTileSquarness(source, 2, 2, 2); verifyTileSquarness(source, 150, 20, 18); verifyTileSquarness(source, 2270, 1323, 12); } /** * Test EPSG:3006 with bounds */ @Test public void testEPSG3006withbounds() { Projection projection = new CustomProjection("+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 " + "+units=m +no_defs +axis=neu +wmssrs=EPSG:3006 +bounds=10.5700,55.2000,24.1800,69.1000 "); Main.setProjection(projection); TemplatedWMSTileSource source = getSource(projection); verifyTileSquarness(source, 0, 1, 4); verifyLocation(source, new LatLon(60, 18.1), 3); verifyLocation(source, new LatLon(60, 18.1)); } /** * Test EPSG:3006 without bounds */ @Test public void testEPSG3006withoutbounds() { Projection projection = new CustomProjection("+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 " + "+units=m +no_defs +axis=neu +wmssrs=EPSG:3006"); Main.setProjection(projection); TemplatedWMSTileSource source = getSource(projection); verifyTileSquarness(source, 0, 1, 4); verifyLocation(source, new LatLon(60, 18.1), 3); verifyLocation(source, new LatLon(60, 18.1)); } private void verifyMercatorTile(TemplatedWMSTileSource source, int x, int y, int z) { TemplatedTMSTileSource verifier = new TemplatedTMSTileSource(testImageryTMS); LatLon result = getTileLatLon(source, x, y, z); ICoordinate expected = verifier.tileXYToLatLon(x, y, z - 1); assertEquals(expected.getLat(), result.lat(), 1e-4); assertEquals(LatLon.normalizeLon(expected.getLon() - result.lon()), 0.0, 1e-4); LatLon tileCenter = new Bounds(result, getTileLatLon(source, x+1, y+1, z)).getCenter(); TileXY backwardsResult = source.latLonToTileXY(tileCenter.toCoordinate(), z); assertEquals(x, backwardsResult.getXIndex()); assertEquals(y, backwardsResult.getYIndex()); } private void verifyLocation(TemplatedWMSTileSource source, LatLon location) { for (int z = source.getMaxZoom(); z > source.getMinZoom() + 1; z--) { if (source.getTileXMax(z) != source.getTileXMin(z) && source.getTileYMax(z) != source.getTileYMin(z)) { // do the tests only where there is more than one tile verifyLocation(source, location, z); } } } private void verifyLocation(TemplatedWMSTileSource source, LatLon location, int z) { assertTrue( "Point outside world bounds", Main.getProjection().getWorldBoundsLatLon().contains(location) ); TileXY tileIndex = source.latLonToTileXY(location.toCoordinate(), z); assertTrue("X index: " + tileIndex.getXIndex() + " greater than tileXmax: " + source.getTileXMax(z) + " at zoom: " + z, tileIndex.getXIndex() <= source.getTileXMax(z)); assertTrue("Y index: " + tileIndex.getYIndex() + " greater than tileYmax: " + source.getTileYMax(z) + " at zoom: " + z, tileIndex.getYIndex() <= source.getTileYMax(z)); EastNorth locationEN = Main.getProjection().latlon2eastNorth(location); EastNorth x1 = Main.getProjection().latlon2eastNorth(getTileLatLon(source, tileIndex, z)); EastNorth x2 = Main.getProjection().latlon2eastNorth(getTileLatLon(source, tileIndex.getXIndex() + 1, tileIndex.getYIndex() + 1, z)); // test that location is within tile bounds assertTrue(locationEN.toString() + " not within " + bboxStr(x1, x2) + " for tile " + z + "/" + tileIndex.getXIndex() + "/" + tileIndex.getYIndex(), isWithin(locationEN, x1, x2)); verifyTileSquarness(source, tileIndex.getXIndex(), tileIndex.getYIndex(), z); } private static boolean isWithin(EastNorth point, EastNorth topLeft, EastNorth bottomRight) { return Math.min(topLeft.east(), bottomRight.east()) <= point.east() && point.east() <= Math.max(topLeft.east(), bottomRight.east()) && Math.min(topLeft.north(), bottomRight.north()) <= point.north() && point.north() <= Math.max(topLeft.north(), bottomRight.north()); } private static String bboxStr(EastNorth x1, EastNorth x2) { return "[" + x1.east() +", " + x1.north() + ", " + x2.east() + ", " + x2.north() +"]"; } private LatLon getTileLatLon(TemplatedWMSTileSource source, TileXY tileIndex, int z) { return getTileLatLon(source, tileIndex.getXIndex(), tileIndex.getYIndex(), z); } private LatLon getTileLatLon(TemplatedWMSTileSource source, int x, int y, int z) { return new LatLon(source.tileXYToLatLon(x, y, z)); } private void verifyTileSquarness(TemplatedWMSTileSource source, int x, int y, int z) { /** * t1 | t2 * ------- * t3 | t4 */ EastNorth t1 = source.getTileEastNorth(x, y, z); EastNorth t2 = source.getTileEastNorth(x + 1, y, z); EastNorth t3 = source.getTileEastNorth(x, y + 1, z); EastNorth t4 = source.getTileEastNorth(x + 1, y + 1, z); double y_size = Math.abs(t1.getY() - t4.getY()); double x_size = Math.abs(t1.getX() - t4.getX()); assertEquals(x_size, y_size, Math.max(x_size, y_size) * 1e-06); assertEquals(y_size, Math.abs(t1.getY() - t3.getY()), y_size * 1e-06); assertEquals(x_size, Math.abs(t1.getX() - t2.getX()), x_size * 1e-06); t1 = source.getTileEastNorth(x, y, z); t2 = source.getTileEastNorth(x + 1, y, z); t3 = source.getTileEastNorth(x, y + 1, z); t4 = source.getTileEastNorth(x + 1, y + 1, z); y_size = Math.abs(t1.getY() - t4.getY()); x_size = Math.abs(t1.getX() - t4.getX()); assertEquals(x_size, y_size, Math.max(x_size, y_size) * 1e-05); assertEquals(y_size, Math.abs(t1.getY() - t3.getY()), y_size * 1e-05); assertEquals(x_size, Math.abs(t1.getX() - t2.getX()), x_size * 1e-05); } private TemplatedWMSTileSource getSource(Projection projection) { return new TemplatedWMSTileSource(testImageryWMS, projection); } }