Changeset 8618 in josm


Ignore:
Timestamp:
2015-07-26T17:03:37+02:00 (10 years ago)
Author:
wiktorn
Message:

Fix calculation of World Bounds for WMS when no projection has no bounds defined, and bogus results are returned on boundaries.

Closes: #11697, #11701

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/imagery/TemplatedWMSTileSource.java

    r8598 r8618  
    1616
    1717import org.openstreetmap.gui.jmapviewer.Coordinate;
     18import org.openstreetmap.gui.jmapviewer.OsmMercator;
    1819import org.openstreetmap.gui.jmapviewer.Tile;
    1920import org.openstreetmap.gui.jmapviewer.TileXY;
     
    3940    private final List<String> serverProjections;
    4041    private EastNorth topLeftCorner;
     42    private Bounds worldBounds;
    4143
    4244    private static final String PATTERN_HEADER  = "\\{header\\(([^,]+),([^}]+)\\)\\}";
     
    7981     */
    8082    public void initProjection(Projection proj) {
    81         Bounds bounds = proj.getWorldBoundsLatLon();
    82         EastNorth min = proj.latlon2eastNorth(bounds.getMin());
    83         EastNorth max = proj.latlon2eastNorth(bounds.getMax());
     83        this.worldBounds = getWorldBounds();
     84        EastNorth min = proj.latlon2eastNorth(worldBounds.getMin());
     85        EastNorth max = proj.latlon2eastNorth(worldBounds.getMax());
    8486        this.topLeftCorner = new EastNorth(min.east(), max.north());
    8587    }
     
    230232    @Override
    231233    public int getTileXMax(int zoom) {
    232         Projection proj = Main.getProjection();
    233         double scale = getDegreesPerTile(zoom);
    234         Bounds bounds = Main.getProjection().getWorldBoundsLatLon();
    235         EastNorth min = proj.latlon2eastNorth(bounds.getMin());
    236         EastNorth max = proj.latlon2eastNorth(bounds.getMax());
    237         return (int) Math.ceil(Math.abs(max.getX() - min.getX()) / scale);
     234        LatLon bottomRight = new LatLon(worldBounds.getMinLat(), worldBounds.getMaxLon());
     235        return latLonToTileXY(bottomRight.toCoordinate(), zoom).getXIndex();
    238236    }
    239237
     
    245243    @Override
    246244    public int getTileYMax(int zoom) {
    247         Projection proj = Main.getProjection();
    248         double scale = getDegreesPerTile(zoom);
    249         Bounds bounds = Main.getProjection().getWorldBoundsLatLon();
    250         EastNorth min = proj.latlon2eastNorth(bounds.getMin());
    251         EastNorth max = proj.latlon2eastNorth(bounds.getMax());
    252         return (int) Math.ceil(Math.abs(max.getY() - min.getY()) / scale);
     245        LatLon bottomRight = new LatLon(worldBounds.getMinLat(), worldBounds.getMaxLon());
     246        return latLonToTileXY(bottomRight.toCoordinate(), zoom).getYIndex();
    253247    }
    254248
     
    354348
    355349    private double getDegreesPerTile(int zoom) {
    356         return getDegreesPerTile(zoom, Main.getProjection());
    357     }
    358 
    359     private double getDegreesPerTile(int zoom, Projection proj) {
    360         Bounds bounds = proj.getWorldBoundsLatLon();
    361         EastNorth min = proj.latlon2eastNorth(bounds.getMin());
    362         EastNorth max = proj.latlon2eastNorth(bounds.getMax());
     350        Projection proj = Main.getProjection();
     351        EastNorth min = proj.latlon2eastNorth(worldBounds.getMin());
     352        EastNorth max = proj.latlon2eastNorth(worldBounds.getMax());
     353
    363354        int tilesPerZoom = (int) Math.pow(2, zoom - 1);
    364355        return Math.max(
     
    368359    }
    369360
     361    /**
     362     * returns world bounds, but detect situation, when default bounds are provided (-90, -180, 90, 180), and projection
     363     * returns very close values for both min and max X. To work around this problem, cap this projection on north and south
     364     * pole, the same way they are capped in Mercator projection, so conversions should work properly
     365     */
     366    private final static Bounds getWorldBounds() {
     367        Projection proj = Main.getProjection();
     368        Bounds bounds = proj.getWorldBoundsLatLon();
     369        EastNorth min = proj.latlon2eastNorth(bounds.getMin());
     370        EastNorth max = proj.latlon2eastNorth(bounds.getMax());
     371
     372        if (Math.abs(min.getX() - max.getX()) < 1 && bounds.equals(new Bounds(new LatLon(-90, -180), new LatLon(90, 180)))) {
     373            return new Bounds(
     374                    new LatLon(OsmMercator.MIN_LAT, bounds.getMinLon()),
     375                    new LatLon(OsmMercator.MAX_LAT, bounds.getMaxLon())
     376                    );
     377        }
     378        return bounds;
     379    }
     380
    370381    @Override
    371382    public String getTileId(int zoom, int tilex, int tiley) {
  • trunk/test/unit/org/openstreetmap/josm/data/imagery/TemplatedWMSTileSourceTest.java

    r8599 r8618  
    1515import org.openstreetmap.josm.data.coor.LatLon;
    1616import org.openstreetmap.josm.data.osm.BBox;
     17import org.openstreetmap.josm.data.projection.CustomProjection;
    1718import org.openstreetmap.josm.data.projection.Projection;
    1819import org.openstreetmap.josm.data.projection.Projections;
     
    6768
    6869    @Test
     70    public void testEPSG4326_widebounds() {
     71        Main.setProjection(new CustomProjection("+proj=lonlat +datum=WGS84 +axis=neu +bounds=-180,53,180,54"));
     72        TemplatedWMSTileSource source = getSource();
     73
     74        verifyLocation(source, new LatLon(53.5937132, 19.5652017));
     75        verifyLocation(source, new LatLon(53.501565692302854, 18.54455233898721));
     76    }
     77
     78    @Test
     79    public void testEPSG4326_narrowbounds() {
     80        Main.setProjection(new CustomProjection("+proj=lonlat +datum=WGS84 +axis=neu +bounds=18,-90,20,90"));
     81        TemplatedWMSTileSource source = getSource();
     82
     83        verifyLocation(source, new LatLon(53.5937132, 19.5652017));
     84        verifyLocation(source, new LatLon(53.501565692302854, 18.54455233898721));
     85    }
     86
     87    @Test
    6988    public void testEPSG2180() {
    7089        Main.setProjection(Projections.getProjectionByCode("EPSG:2180"));
     
    7796        verifyTileSquarness(source, 150, 20, 18);
    7897        verifyTileSquarness(source, 2270, 1323, 12);
     98    }
     99
     100    @Test
     101    public void testEPSG3006_withbounds() {
     102        Main.setProjection(
     103                new CustomProjection("+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 "
     104                        + "+units=m +no_defs +axis=neu +wmssrs=EPSG:3006 +bounds=10.5700,55.2000,24.1800,69.1000 "));
     105        TemplatedWMSTileSource source = getSource();
     106
     107        verifyLocation(source, new LatLon(60, 18), 3);
     108        verifyLocation(source, new LatLon(60, 18));
     109
     110    }
     111
     112    @Test
     113    public void testEPSG3006_withoutbounds() {
     114        Main.setProjection(
     115                new CustomProjection("+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 "
     116                        + "+units=m +no_defs +axis=neu +wmssrs=EPSG:3006"));
     117        TemplatedWMSTileSource source = getSource();
     118
     119        verifyTileSquarness(source, 0, 1, 4);
     120        verifyLocation(source, new LatLon(60, 18.1), 3);
     121        verifyLocation(source, new LatLon(60, 18.1));
     122
    79123    }
    80124
     
    83127        LatLon result = getTileLatLon(source, x, y, z);
    84128        LatLon expected = new LatLon(verifier.tileYToLat(y, z - 1), verifier.tileXToLon(x, z - 1)); //
    85         System.out.println(z + "/" + x + "/" + y + " - result: " + result.toDisplayString() + " osmMercator: " +  expected.toDisplayString());
    86129        assertTrue("result: " + result.toDisplayString() + " osmMercator: " +  expected.toDisplayString(), result.equalsEpsilon(expected));
    87130        LatLon tileCenter = new Bounds(result, getTileLatLon(source, x+1, y+1, z)).getCenter();
     
    92135
    93136    private void verifyLocation(TemplatedWMSTileSource source, LatLon location) {
    94         for (int z = 1; z < 22; z++) {
    95             TileXY tileIndex = source.latLonToTileXY(location.toCoordinate(), z);
    96             BBox bbox = new BBox(
    97                     getTileLatLon(source, tileIndex, z),
    98                     getTileLatLon(source, tileIndex.getXIndex() + 1, tileIndex.getYIndex() + 1, z)
    99                     );
    100             assertTrue(location.toDisplayString() + " not within " + bbox.toString() +
    101                     " for tile " + z + "/" + tileIndex.getXIndex() + "/" + tileIndex.getYIndex(),
    102                     bbox.bounds(location));
     137        for (int z = 22; z > 1; z--) {
     138            verifyLocation(source, location, z);
    103139        }
     140    }
     141
     142    private void verifyLocation(TemplatedWMSTileSource source, LatLon location, int z) {
     143        assertTrue(
     144                "Point outside world bounds",
     145                Main.getProjection().getWorldBoundsLatLon().contains(location)
     146                );
     147
     148        TileXY tileIndex = source.latLonToTileXY(location.toCoordinate(), z);
     149
     150        assertTrue("X index: " + tileIndex.getXIndex() + " greater than tileXmax: " + source.getTileXMax(z) + " at zoom: " + z,
     151                tileIndex.getXIndex() <= source.getTileXMax(z));
     152
     153        assertTrue("Y index: " + tileIndex.getYIndex() + " greater than tileYmax: " + source.getTileYMax(z) + " at zoom: " + z,
     154                tileIndex.getYIndex() <= source.getTileYMax(z));
     155
     156        // test that location is within tile bounds
     157        BBox bbox = new BBox(
     158                getTileLatLon(source, tileIndex, z),
     159                getTileLatLon(source, tileIndex.getXIndex() + 1, tileIndex.getYIndex() + 1, z)
     160                );
     161        assertTrue(location.toDisplayString() + " not within " + bbox.toString() +
     162                " for tile " + z + "/" + tileIndex.getXIndex() + "/" + tileIndex.getYIndex(),
     163                bbox.bounds(location));
     164        verifyTileSquarness(source, tileIndex.getXIndex(), tileIndex.getYIndex(), z);
    104165    }
    105166
     
    119180         * t3 | t4
    120181         */
    121         EastNorth t1 = proj.latlon2eastNorth(getTileLatLon(source, x, y, z));
    122         EastNorth t2 = proj.latlon2eastNorth(getTileLatLon(source, x + 1, y, z));
    123         EastNorth t3 = proj.latlon2eastNorth(getTileLatLon(source, x, y + 1, z));
    124         EastNorth t4 = proj.latlon2eastNorth(getTileLatLon(source, x + 1, y + 1, z));
     182        EastNorth t1 = source.getTileEastNorth(x, y, z);
     183        EastNorth t2 = source.getTileEastNorth(x + 1, y, z);
     184        EastNorth t3 = source.getTileEastNorth(x, y + 1, z);
     185        EastNorth t4 = source.getTileEastNorth(x + 1, y + 1, z);
    125186        double y_size = Math.abs(t1.getY() - t4.getY());
    126187        double x_size = Math.abs(t1.getX() - t4.getX());
    127188
    128         assertEquals(x_size, y_size, Math.max(x_size, y_size) * 1e-05);
    129         assertEquals(y_size, Math.abs(t1.getY() - t3.getY()), y_size * 1e-05);
    130         assertEquals(x_size, Math.abs(t1.getX() - t2.getX()), x_size * 1e-05);
     189        assertEquals(x_size, y_size, Math.max(x_size, y_size) * 1e-06);
     190        assertEquals(y_size, Math.abs(t1.getY() - t3.getY()), y_size * 1e-06);
     191        assertEquals(x_size, Math.abs(t1.getX() - t2.getX()), x_size * 1e-06);
    131192
    132193        t1 = source.getTileEastNorth(x, y, z);
Note: See TracChangeset for help on using the changeset viewer.