Ticket #11419: 11419_highres_tiles.patch

File 11419_highres_tiles.patch, 23.5 KB (added by wiktorn, 11 years ago)
  • data/maps.xsd

    diff --git a/data/maps.xsd b/data/maps.xsd
    index 2643b2d..308edd4 100644
    a b  
    670670                                                                        </xs:all>
    671671                                                                </xs:complexType>
    672672                                                        </xs:element>
     673                                                        <!-- list of HTTP headers, that indicate "no tile at this zoom level" situation -->
    673674                                                        <xs:element name="no-tile-header" minOccurs="0" maxOccurs="unbounded">
    674675                                                                <xs:complexType>
    675676                                                                        <xs:attribute name="name" type="xs:string" />
    676677                                                                        <xs:attribute name="value" type="xs:string" />
    677678                                                                </xs:complexType>
    678679                                                        </xs:element>
     680                                                        <!-- tile size provided by imagery source. Default - 256 -->
     681                                                        <xs:element name="tile-size" minOccurs="0" maxOccurs="1" type="xs:positiveInteger" />
    679682                                                </xs:choice>
    680683                                        </xs:sequence>
    681684                                        <xs:attribute name="last-check" type="xs:date" use="optional" />
  • src/org/openstreetmap/gui/jmapviewer/OsmMercator.java

    diff --git a/src/org/openstreetmap/gui/jmapviewer/OsmMercator.java b/src/org/openstreetmap/gui/jmapviewer/OsmMercator.java
    index 903ee25..ab08dd2 100644
    a b package org.openstreetmap.gui.jmapviewer;  
    1010 */
    1111public class OsmMercator {
    1212
    13     public static int TILE_SIZE = 256;
     13    /**
     14     * default tile size
     15     */
     16    public static int DEFAUL_TILE_SIZE = 256;
    1417    public static final double MAX_LAT = 85.05112877980659;
    1518    public static final double MIN_LAT = -85.05112877980659;
    1619    private static double EARTH_RADIUS = 6378137; // equatorial earth radius for EPSG:3857 (Mercator)
    1720
    18     public static double radius(int aZoomlevel) {
    19         return (TILE_SIZE * (1 << aZoomlevel)) / (2.0 * Math.PI);
     21    /**
     22     * instance with tile size of 256 for easy conversions
     23     */
     24    public static final OsmMercator MERCATOR_256 = new OsmMercator();
     25
     26    private int tileSize = DEFAUL_TILE_SIZE;
     27
     28    /**
     29     * Creates instance with default tile size of 256
     30     */
     31    public OsmMercator() {
     32    }
     33
     34    /**
     35     * Creates instance with provided tile size.
     36     * @param tileSize
     37     */
     38    public OsmMercator(int tileSize) {
     39        this.tileSize = tileSize;
     40    }
     41
     42    public double radius(int aZoomlevel) {
     43        return (tileSize * (1 << aZoomlevel)) / (2.0 * Math.PI);
    2044    }
    2145
    2246    /**
    2347     * Returns the absolut number of pixels in y or x, defined as: 2^Zoomlevel *
    24      * TILE_WIDTH where TILE_WIDTH is the width of a tile in pixels
     48     * tileSize where tileSize is the width of a tile in pixels
    2549     *
    2650     * @param aZoomlevel zoom level to request pixel data
    2751     * @return number of pixels
    2852     */
    29     public static int getMaxPixels(int aZoomlevel) {
    30         return TILE_SIZE * (1 << aZoomlevel);
     53    public int getMaxPixels(int aZoomlevel) {
     54        return tileSize * (1 << aZoomlevel);
    3155    }
    3256
    33     public static int falseEasting(int aZoomlevel) {
     57    public int falseEasting(int aZoomlevel) {
    3458        return getMaxPixels(aZoomlevel) / 2;
    3559    }
    3660
    37     public static int falseNorthing(int aZoomlevel) {
     61    public int falseNorthing(int aZoomlevel) {
    3862        return (-1 * getMaxPixels(aZoomlevel) / 2);
    3963    }
    4064
    public class OsmMercator {  
    5074     * @return the distance
    5175     * @author Jason Huntley
    5276     */
    53     public static double getDistance(int x1, int y1, int x2, int y2, int zoomLevel) {
     77    public double getDistance(int x1, int y1, int x2, int y2, int zoomLevel) {
    5478        double la1 = YToLat(y1, zoomLevel);
    5579        double lo1 = XToLon(x1, zoomLevel);
    5680        double la2 = YToLat(y2, zoomLevel);
    public class OsmMercator {  
    6993     * @return the distance
    7094     * @author Jason Huntley
    7195     */
    72     public static double getDistance(double la1, double lo1, double la2, double lo2) {
     96    public double getDistance(double la1, double lo1, double la2, double lo2) {
    7397        double aStartLat = Math.toRadians(la1);
    7498        double aStartLong = Math.toRadians(lo1);
    7599        double aEndLat =Math.toRadians(la2);
    public class OsmMercator {  
    100124     * @return [0..2^Zoomlevel*TILE_SIZE[
    101125     * @author Jan Peter Stotz
    102126     */
    103     public static double LonToX(double aLongitude, int aZoomlevel) {
     127    public double LonToX(double aLongitude, int aZoomlevel) {
    104128        int mp = getMaxPixels(aZoomlevel);
    105129        double x = (mp * (aLongitude + 180l)) / 360l;
    106130        return Math.min(x, mp - 1);
    public class OsmMercator {  
    124148     * @return [0..2^Zoomlevel*TILE_SIZE[
    125149     * @author Jan Peter Stotz
    126150     */
    127     public static double LatToY(double aLat, int aZoomlevel) {
     151    public double LatToY(double aLat, int aZoomlevel) {
    128152        if (aLat < MIN_LAT)
    129153            aLat = MIN_LAT;
    130154        else if (aLat > MAX_LAT)
    public class OsmMercator {  
    154178     * @return ]-180..180[
    155179     * @author Jan Peter Stotz
    156180     */
    157     public static double XToLon(int aX, int aZoomlevel) {
     181    public double XToLon(int aX, int aZoomlevel) {
    158182        return ((360d * aX) / getMaxPixels(aZoomlevel)) - 180.0;
    159183    }
    160184
    public class OsmMercator {  
    165189     *            [0..2^Zoomlevel*TILE_WIDTH[
    166190     * @return [MIN_LAT..MAX_LAT] is about [-85..85]
    167191     */
    168     public static double YToLat(int aY, int aZoomlevel) {
     192    public double YToLat(int aY, int aZoomlevel) {
    169193        aY += falseNorthing(aZoomlevel);
    170194        double latitude = (Math.PI / 2) - (2 * Math.atan(Math.exp(-1.0 * aY / radius(aZoomlevel))));
    171195        return -1 * Math.toDegrees(latitude);
  • src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java

    diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java
    index 9e44ea0..4842ae4 100644
    a b public abstract class AbstractTMSTileSource extends AbstractTileSource {  
    1414    protected String baseUrl;
    1515    protected String id;
    1616    private Map<String, String> noTileHeaders;
     17    protected int tileSize;
     18    protected OsmMercator osmMercator;
    1719
    1820    public AbstractTMSTileSource(TileSourceInfo info) {
    1921        this.name = info.getName();
    public abstract class AbstractTMSTileSource extends AbstractTileSource {  
    2325        }
    2426        this.id = info.getUrl();
    2527        this.noTileHeaders = info.getNoTileHeaders();
     28        this.tileSize = info.getTileSize();
     29        osmMercator = new OsmMercator(this.tileSize);
    2630    }
    2731
    2832    @Override
    public abstract class AbstractTMSTileSource extends AbstractTileSource {  
    8084     */
    8185    @Override
    8286    public int getTileSize() {
    83         return OsmMercator.TILE_SIZE;
     87        return tileSize;
    8488    }
    8589
    8690    @Override
    8791    public double getDistance(double lat1, double lon1, double lat2, double lon2) {
    88         return OsmMercator.getDistance(lat1, lon1, lat2, lon2);
     92        return osmMercator.getDistance(lat1, lon1, lat2, lon2);
    8993    }
    9094
    9195    @Override
    9296    public int LonToX(double lon, int zoom) {
    93         return (int )OsmMercator.LonToX(lon, zoom);
     97        return (int )osmMercator.LonToX(lon, zoom);
    9498    }
    9599
    96100    @Override
    97101    public int LatToY(double lat, int zoom) {
    98         return (int )OsmMercator.LatToY(lat, zoom);
     102        return (int )osmMercator.LatToY(lat, zoom);
    99103    }
    100104
    101105    @Override
    102106    public double XToLon(int x, int zoom) {
    103         return OsmMercator.XToLon(x, zoom);
     107        return osmMercator.XToLon(x, zoom);
    104108    }
    105109
    106110    @Override
    107111    public double YToLat(int y, int zoom) {
    108         return OsmMercator.YToLat(y, zoom);
     112        return osmMercator.YToLat(y, zoom);
    109113    }
    110114
    111115    @Override
    112116    public double latToTileY(double lat, int zoom) {
    113         return OsmMercator.LatToY(lat, zoom) / OsmMercator.TILE_SIZE;
     117        return osmMercator.LatToY(lat, zoom) / tileSize;
    114118    }
    115119
    116120    @Override
    117121    public double lonToTileX(double lon, int zoom) {
    118         return OsmMercator.LonToX(lon, zoom) / OsmMercator.TILE_SIZE;
     122        return osmMercator.LonToX(lon, zoom) / tileSize;
    119123    }
    120124
    121125    @Override
    122126    public double tileYToLat(int y, int zoom) {
    123         return OsmMercator.YToLat(y * OsmMercator.TILE_SIZE, zoom);
     127        return osmMercator.YToLat(y * tileSize, zoom);
    124128    }
    125129
    126130    @Override
    127131    public double tileXToLon(int x, int zoom) {
    128         return OsmMercator.XToLon(x * OsmMercator.TILE_SIZE, zoom);
     132        return osmMercator.XToLon(x * tileSize, zoom);
    129133    }
    130134
    131135    @Override
  • src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java

    diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java
    index 6acd716..9f67568 100644
    a b public class ScanexTileSource extends TMSTileSource {  
    9393
    9494    @Override
    9595    public int LatToY(double lat, int zoom) {
    96         return (int )(latToTileY(lat, zoom) * OsmMercator.TILE_SIZE);
     96        return (int )(latToTileY(lat, zoom) * tileSize);
    9797    }
    9898
    9999    @Override
    100100    public double YToLat(int y, int zoom) {
    101         return tileYToLat((double )y / OsmMercator.TILE_SIZE, zoom);
     101        return tileYToLat((double )y / tileSize, zoom);
    102102    }
    103103
    104104    @Override
  • src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java

    diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java
    index f5b342c..c45eb8b 100644
    a b package org.openstreetmap.gui.jmapviewer.tilesources;  
    33
    44import java.util.Map;
    55
     6import org.openstreetmap.gui.jmapviewer.OsmMercator;
     7
    68/**
    79 * Data class that keeps basic information about a tile source.
    810 */
    public class TileSourceInfo {  
    2729    /** cookies that needs to be sent to tile source */
    2830    protected String cookies;
    2931
     32    private int tileSize = OsmMercator.DEFAUL_TILE_SIZE;
    3033
    3134    /**
    3235     * Create a TileSourceInfo class
    public class TileSourceInfo {  
    104107        return cookies;
    105108    }
    106109
     110    /**
     111     *
     112     * @return tile size provided by this tile source
     113     */
     114    public int getTileSize() {
     115        return tileSize;
     116    }
     117
     118    /**
     119     * sets the tile size provided by this tile source
     120     * @param tileSize
     121     */
     122    public void setTileSize(int tileSize) {
     123        if (tileSize <= 0) {
     124            throw new AssertionError("Invalid tile size: " + tileSize);
     125        }
     126        this.tileSize = tileSize;
     127    }
     128
     129
    107130}
  • src/org/openstreetmap/josm/data/imagery/ImageryInfo.java

    diff --git a/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java b/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java
    index 608ebed..bc54b8b 100644
    a b import java.util.regex.Pattern;  
    1818import javax.swing.ImageIcon;
    1919
    2020import org.openstreetmap.gui.jmapviewer.Coordinate;
     21import org.openstreetmap.gui.jmapviewer.OsmMercator;
    2122import org.openstreetmap.gui.jmapviewer.interfaces.Attributed;
    2223import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTileSource;
    2324import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource.Mapnik;
    public class ImageryInfo extends TileSourceInfo implements Comparable<ImageryInf  
    224225        @pref String icon;
    225226        @pref String description;
    226227        @pref Map<String, String> noTileHeaders;
     228        @pref int tileSize = OsmMercator.DEFAUL_TILE_SIZE;
    227229
    228230        /**
    229231         * Constructs a new empty WMS {@code ImageryPreferenceEntry}.
    public class ImageryInfo extends TileSourceInfo implements Comparable<ImageryInf  
    280282            if (i.noTileHeaders != null && !i.noTileHeaders.isEmpty()) {
    281283                noTileHeaders = i.noTileHeaders;
    282284            }
     285
     286            tileSize = i.getTileSize();
    283287        }
    284288
    285289        @Override
    public class ImageryInfo extends TileSourceInfo implements Comparable<ImageryInf  
    401405        if (e.noTileHeaders != null) {
    402406            noTileHeaders = e.noTileHeaders;
    403407        }
     408        setTileSize(e.tileSize);
    404409    }
    405410
    406411    /**
  • src/org/openstreetmap/josm/data/imagery/ImageryLayerInfo.java

    diff --git a/src/org/openstreetmap/josm/data/imagery/ImageryLayerInfo.java b/src/org/openstreetmap/josm/data/imagery/ImageryLayerInfo.java
    index e6231a2..f835dfb 100644
    a b public class ImageryLayerInfo {  
    149149        Collection<String> newKnownDefaults = new TreeSet<>(knownDefaults);
    150150        for (ImageryInfo def : defaultLayers) {
    151151            // temporary migration code, so all user preferences will get updated with new settings from JOSM site (can be removed ~Dez. 2015)
    152             if (def.getNoTileHeaders() != null) {
     152            if (def.getNoTileHeaders() != null || def.getTileSize() > 0) {
    153153                for (ImageryInfo i: layers) {
    154154                    if (isSimilar(def,  i)) {
    155                         i.setNoTileHeaders(def.getNoTileHeaders());
     155                        if (def.getNoTileHeaders() != null) {
     156                            i.setNoTileHeaders(def.getNoTileHeaders());
     157                        }
     158                        if (def.getTileSize() > 0) {
     159                            i.setTileSize(def.getTileSize());
     160                        }
    156161                        changed = true;
    157162                    }
    158163                }
  • src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java

    diff --git a/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java b/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java
    index 7b41c59..c98d890 100644
    a b public class SlippyMapBBoxChooser extends JMapViewer implements BBoxChooser {  
    124124    private transient Bounds bbox;
    125125
    126126    // upper left and lower right corners of the selection rectangle (x/y on ZOOM_MAX)
    127     private Point iSelectionRectStart;
    128     private Point iSelectionRectEnd;
     127    private Coordinate iSelectionRectStart;
     128    private Coordinate iSelectionRectEnd;
    129129
    130130    /**
    131131     * Constructs a new {@code SlippyMapBBoxChooser}.
    public class SlippyMapBBoxChooser extends JMapViewer implements BBoxChooser {  
    209209
    210210            // draw selection rectangle
    211211            if (iSelectionRectStart != null && iSelectionRectEnd != null) {
     212                Rectangle box = new Rectangle(getMapPosition(iSelectionRectStart, false));
     213                box.add(getMapPosition(iSelectionRectEnd, false));
    212214
    213                 int zoomDiff = MAX_ZOOM - zoom;
    214                 Point tlc = getTopLeftCoordinates();
    215                 int x_min = (iSelectionRectStart.x >> zoomDiff) - tlc.x;
    216                 int y_min = (iSelectionRectStart.y >> zoomDiff) - tlc.y;
    217                 int x_max = (iSelectionRectEnd.x >> zoomDiff) - tlc.x;
    218                 int y_max = (iSelectionRectEnd.y >> zoomDiff) - tlc.y;
    219 
    220                 int w = x_max - x_min;
    221                 int h = y_max - y_min;
    222215                g.setColor(new Color(0.9f, 0.7f, 0.7f, 0.6f));
    223                 g.fillRect(x_min, y_min, w, h);
     216                g.fillRect(box.x, box.y, box.width, box.height);
    224217
    225218                g.setColor(Color.BLACK);
    226                 g.drawRect(x_min, y_min, w, h);
     219                g.drawRect(box.x, box.y, box.width, box.height);
    227220            }
    228221        } catch (Exception e) {
    229222            Main.error(e);
    public class SlippyMapBBoxChooser extends JMapViewer implements BBoxChooser {  
    256249        Point p_max = new Point(Math.max(aEnd.x, aStart.x), Math.max(aEnd.y, aStart.y));
    257250        Point p_min = new Point(Math.min(aEnd.x, aStart.x), Math.min(aEnd.y, aStart.y));
    258251
    259         Point tlc = getTopLeftCoordinates();
    260         int zoomDiff = MAX_ZOOM - zoom;
    261         Point pEnd = new Point(p_max.x + tlc.x, p_max.y + tlc.y);
    262         Point pStart = new Point(p_min.x + tlc.x, p_min.y + tlc.y);
    263 
    264         pEnd.x <<= zoomDiff;
    265         pEnd.y <<= zoomDiff;
    266         pStart.x <<= zoomDiff;
    267         pStart.y <<= zoomDiff;
     252        iSelectionRectStart = getPosition(p_min);
     253        iSelectionRectEnd =   getPosition(p_max);
    268254
    269         iSelectionRectStart = pStart;
    270         iSelectionRectEnd = pEnd;
    271 
    272         Coordinate l1 = getPosition(p_max); // lon may be outside [-180,180]
    273         Coordinate l2 = getPosition(p_min); // lon may be outside [-180,180]
    274255        Bounds b = new Bounds(
    275256                new LatLon(
    276                         Math.min(l2.getLat(), l1.getLat()),
    277                         LatLon.toIntervalLon(Math.min(l1.getLon(), l2.getLon()))
     257                        Math.min(iSelectionRectStart.getLat(), iSelectionRectEnd.getLat()),
     258                        LatLon.toIntervalLon(Math.min(iSelectionRectStart.getLon(), iSelectionRectEnd.getLon()))
    278259                        ),
    279260                        new LatLon(
    280                                 Math.max(l2.getLat(), l1.getLat()),
    281                                 LatLon.toIntervalLon(Math.max(l1.getLon(), l2.getLon())))
     261                                Math.max(iSelectionRectStart.getLat(), iSelectionRectEnd.getLat()),
     262                                LatLon.toIntervalLon(Math.max(iSelectionRectStart.getLon(), iSelectionRectEnd.getLon())))
    282263                );
    283264        Bounds oldValue = this.bbox;
    284265        this.bbox = b;
    public class SlippyMapBBoxChooser extends JMapViewer implements BBoxChooser {  
    331312            minLon -= 360.0;
    332313        }
    333314
    334         int y1 = tileSource.LatToY(bbox.getMinLat(), MAX_ZOOM);
    335         int y2 = tileSource.LatToY(bbox.getMaxLat(), MAX_ZOOM);
    336         int x1 = tileSource.LonToX(minLon, MAX_ZOOM);
    337         int x2 = tileSource.LonToX(maxLon, MAX_ZOOM);
    338 
    339         iSelectionRectStart = new Point(Math.min(x1, x2), Math.min(y1, y2));
    340         iSelectionRectEnd = new Point(Math.max(x1, x2), Math.max(y1, y2));
     315        iSelectionRectStart = new Coordinate(bbox.getMinLat(), bbox.getMinLon());
     316        iSelectionRectEnd = new Coordinate(bbox.getMaxLat(), bbox.getMaxLon());
    341317
    342318        // calc the screen coordinates for the new selection rectangle
    343319        MapMarkerDot xmin_ymin = new MapMarkerDot(bbox.getMinLat(), bbox.getMinLon());
  • src/org/openstreetmap/josm/gui/layer/TMSLayer.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/TMSLayer.java b/src/org/openstreetmap/josm/gui/layer/TMSLayer.java
    index f4a29dd..63b716e 100644
    a b import org.openstreetmap.josm.data.preferences.BooleanProperty;  
    6565import org.openstreetmap.josm.data.preferences.IntegerProperty;
    6666import org.openstreetmap.josm.data.preferences.StringProperty;
    6767import org.openstreetmap.josm.data.projection.Projection;
     68import org.openstreetmap.josm.gui.ExtendedDialog;
    6869import org.openstreetmap.josm.gui.MapFrame;
    6970import org.openstreetmap.josm.gui.MapView;
    7071import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
    public class TMSLayer extends ImageryLayer implements ImageObserver, TileLoaderL  
    422423    }
    423424
    424425    private final int getBestZoom() {
    425         double factor = getScaleFactor(1);
     426        double factor = getScaleFactor(1); // check the ratio between area of tilesize at zoom 1 to current view
    426427        double result = Math.log(factor)/Math.log(2)/2+1;
    427         // In general, smaller zoom levels are more readable.  We prefer big,
    428         // block, pixelated (but readable) map text to small, smeared,
    429         // unreadable underzoomed text.  So, use .floor() instead of rounding
    430         // to skew things a bit toward the lower zooms.
     428        /*
     429         * Math.log(factor)/Math.log(2) - gives log base 2 of factor
     430         * We divide result by 2, as factor contains ratio between areas. We could do Math.sqrt before log, or just divide log by 2
     431         * In general, smaller zoom levels are more readable.  We prefer big,
     432         * block, pixelated (but readable) map text to small, smeared,
     433         * unreadable underzoomed text.  So, use .floor() instead of rounding
     434         * to skew things a bit toward the lower zooms.
     435         * Remember, that result here, should correspond to TMSLayer.paint(...)
     436         * getScaleFactor(...) is supposed to be between 0.75 and 3
     437         */
    431438        int intResult = (int)Math.floor(result);
    432439        if (intResult > getMaxZoomLvl())
    433440            return getMaxZoomLvl();
    public class TMSLayer extends ImageryLayer implements ImageObserver, TileLoaderL  
    513520            @Override
    514521            public void actionPerformed(ActionEvent ae) {
    515522                if (clickedTile != null) {
    516                     showMetadataTile = clickedTile;
    517                     redraw();
     523                    ExtendedDialog ed = new ExtendedDialog(Main.parent, tr("Tile Info"), new String[]{tr("OK")});
     524                    ed.setIcon(JOptionPane.INFORMATION_MESSAGE);
     525                    StringBuilder content = new StringBuilder();
     526                    content.append("Tile name: ").append(clickedTile.getKey()).append("\n");
     527                    try {
     528                        content.append("Tile url: ").append(clickedTile.getUrl()).append("\n");
     529                    } catch (IOException e) {
     530                    }
     531                    content.append("Tile size: ").append(clickedTile.getTileSource().getTileSize()).append("x").append(clickedTile.getTileSource().getTileSize()).append("\n");
     532                    Rectangle displaySize = tileToRect(clickedTile);
     533                    content.append("Tile display size: ").append(displaySize.width).append("x").append(displaySize.height).append("\n");
     534                    ed.setContent(content.toString());
     535                    ed.showDialog();
    518536                }
    519537            }
    520538        }));
    public class TMSLayer extends ImageryLayer implements ImageObserver, TileLoaderL  
    13831401            myDrawString(g, tr("Current zoom: {0}", currentZoomLevel), 50, 140);
    13841402            myDrawString(g, tr("Display zoom: {0}", displayZoomLevel), 50, 155);
    13851403            myDrawString(g, tr("Pixel scale: {0}", getScaleFactor(currentZoomLevel)), 50, 170);
    1386             myDrawString(g, tr("Best zoom: {0}", Math.log(getScaleFactor(1))/Math.log(2)/2+1), 50, 185);
     1404            myDrawString(g, tr("Best zoom: {0}", getBestZoom()), 50, 185);
    13871405            if(tileLoader instanceof TMSCachedTileLoader) {
    13881406                TMSCachedTileLoader cachedTileLoader = (TMSCachedTileLoader)tileLoader;
    13891407                int offset = 185;
  • src/org/openstreetmap/josm/io/imagery/ImageryReader.java

    diff --git a/src/org/openstreetmap/josm/io/imagery/ImageryReader.java b/src/org/openstreetmap/josm/io/imagery/ImageryReader.java
    index c50e66f..04dc890 100644
    a b public class ImageryReader {  
    137137                        "terms-of-use-url",
    138138                        "country-code",
    139139                        "icon",
     140                        "tile-size",
    140141                }).contains(qName)) {
    141142                    newState = State.ENTRY_ATTRIBUTE;
    142143                    lang = atts.getValue("lang");
    public class ImageryReader {  
    299300                case "icon":
    300301                    entry.setIcon(accumulator.toString());
    301302                    break;
     303                case "tile-size":
     304                    Integer tileSize = null;
     305                    try {
     306                        tileSize  = Integer.parseInt(accumulator.toString());
     307                    } catch(NumberFormatException e) {
     308                        tileSize = null;
     309                    }
     310                    if (tileSize == null) {
     311                        skipEntry = true;
     312                    } else {
     313                        entry.setTileSize(tileSize.intValue());
     314                    }
     315                    break;
    302316                }
    303317                break;
    304318            case BOUNDS: