Changeset 11858 in josm


Ignore:
Timestamp:
2017-04-09T11:08:10+02:00 (6 months ago)
Author:
bastiK
Message:

fixed #7427 - Support reprojection (warping) of imagery layer

Location:
trunk/src/org/openstreetmap/josm
Files:
2 added
16 edited

Legend:

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

    r11830 r11858  
    1111import org.openstreetmap.gui.jmapviewer.tilesources.TMSTileSource;
    1212import org.openstreetmap.gui.jmapviewer.tilesources.TileSourceInfo;
    13 import org.openstreetmap.josm.Main;
    1413import org.openstreetmap.josm.data.Bounds;
    1514import org.openstreetmap.josm.data.ProjectionBounds;
     
    3231    private double[] degreesPerTile;
    3332    private static final float SCALE_DENOMINATOR_ZOOM_LEVEL_1 = 559082264.0287178f;
     33    private Projection tileProjection;
    3434
    3535    /**
    3636     * Constructs a new {@code AbstractWMSTileSource}.
    3737     * @param info tile source info
     38     * @param tileProjection the tile projection
    3839     */
    39     public AbstractWMSTileSource(TileSourceInfo info) {
     40    public AbstractWMSTileSource(TileSourceInfo info, Projection tileProjection) {
    4041        super(info);
     42        this.tileProjection = tileProjection;
    4143    }
    4244
     
    4850    }
    4951
     52    public void setTileProjection(Projection tileProjection) {
     53        this.tileProjection = tileProjection;
     54        initProjection();
     55    }
     56
     57    public Projection getTileProjection() {
     58        return this.tileProjection;
     59    }
     60
    5061    /**
    5162     * Initializes class with current projection in JOSM. This call is needed every time projection changes.
    5263     */
    5364    public void initProjection() {
    54         initProjection(Main.getProjection());
     65        initProjection(this.tileProjection);
    5566    }
    5667
     
    99110    @Override
    100111    public ICoordinate tileXYToLatLon(int x, int y, int zoom) {
    101         return Main.getProjection().eastNorth2latlon(getTileEastNorth(x, y, zoom)).toCoordinate();
     112        return tileProjection.eastNorth2latlon(getTileEastNorth(x, y, zoom)).toCoordinate();
    102113    }
    103114
     
    112123    @Override
    113124    public TileXY latLonToTileXY(double lat, double lon, int zoom) {
    114         EastNorth enPoint = Main.getProjection().latlon2eastNorth(new LatLon(lat, lon));
     125        EastNorth enPoint = tileProjection.latlon2eastNorth(new LatLon(lat, lon));
    115126        return eastNorthToTileXY(enPoint, zoom);
    116127    }
     
    144155    public Point latLonToXY(double lat, double lon, int zoom) {
    145156        double scale = getDegreesPerTile(zoom) / getTileSize();
    146         EastNorth point = Main.getProjection().latlon2eastNorth(new LatLon(lat, lon));
     157        EastNorth point = tileProjection.latlon2eastNorth(new LatLon(lat, lon));
    147158        return new Point(
    148159                (int) Math.round((point.east() - anchorPosition.east()) / scale),
     
    164175    public ICoordinate xyToLatLon(int x, int y, int zoom) {
    165176        double scale = getDegreesPerTile(zoom) / getTileSize();
    166         Projection proj = Main.getProjection();
    167177        EastNorth ret = new EastNorth(
    168178                anchorPosition.east() + x * scale,
    169179                anchorPosition.north() - y * scale
    170180                );
    171         return proj.eastNorth2latlon(ret).toCoordinate();
     181        return tileProjection.eastNorth2latlon(ret).toCoordinate();
    172182    }
    173183
     
    197207    @Override
    198208    public String getServerCRS() {
    199         return Main.getProjection().toCode();
     209        return this.tileProjection.toCode();
    200210    }
    201211}
  • trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java

    r11848 r11858  
    204204    /** is the geo reference correct - don't offer offset handling */
    205205    private boolean isGeoreferenceValid;
    206     /** does the EPSG:4326 to mercator woraround work as expected */
    207     private boolean isEpsg4326To3857Supported;
    208206    /** which layers should be activated by default on layer addition. **/
    209207    private Collection<DefaultLayer> defaultLayers = Collections.emptyList();
     
    244242        @pref boolean valid_georeference;
    245243        @pref boolean bestMarked;
    246         @pref boolean supports_epsg_4326_to_3857_conversion;
    247244        // TODO: disabled until change of layers is implemented
    248245        // @pref String default_layers;
     
    309306
    310307            valid_georeference = i.isGeoreferenceValid();
    311             supports_epsg_4326_to_3857_conversion = i.isEpsg4326To3857Supported();
    312308            // TODO disabled until change of layers is implemented
    313309            // default_layers = i.defaultLayers.stream().collect(Collectors.joining(","));
     
    439435        setTileSize(e.tileSize);
    440436        metadataHeaders = e.metadataHeaders;
    441         isEpsg4326To3857Supported = e.supports_epsg_4326_to_3857_conversion;
    442437        isGeoreferenceValid = e.valid_georeference;
    443438        // TODO disabled until change of layers is implemented
     
    476471        this.noTileChecksums = i.noTileChecksums;
    477472        this.metadataHeaders = i.metadataHeaders;
    478         this.isEpsg4326To3857Supported = i.isEpsg4326To3857Supported;
    479473        this.isGeoreferenceValid = i.isGeoreferenceValid;
    480474        this.defaultLayers = i.defaultLayers;
     
    506500                Objects.equals(this.url, other.url) &&
    507501                Objects.equals(this.bestMarked, other.bestMarked) &&
    508                 Objects.equals(this.isEpsg4326To3857Supported, other.isEpsg4326To3857Supported) &&
    509502                Objects.equals(this.isGeoreferenceValid, other.isGeoreferenceValid) &&
    510503                Objects.equals(this.cookies, other.cookies) &&
     
    11411134            this.metadataHeaders = metadataHeaders;
    11421135        }
    1143     }
    1144 
    1145     /**
    1146      * Gets the flag if epsg 4326 to 3857 is supported
    1147      * @return The flag.
    1148      */
    1149     public boolean isEpsg4326To3857Supported() {
    1150         return isEpsg4326To3857Supported;
    1151     }
    1152 
    1153     /**
    1154      * Sets the flag that epsg 4326 to 3857 is supported
    1155      * @param isEpsg4326To3857Supported The flag.
    1156      */
    1157     public void setEpsg4326To3857Supported(boolean isEpsg4326To3857Supported) {
    1158         this.isEpsg4326To3857Supported = isEpsg4326To3857Supported;
    11591136    }
    11601137
  • trunk/src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java

    r11843 r11858  
    4646    private static final LongProperty MAXIMUM_EXPIRES = new LongProperty("imagery.generic.maximum_expires", TimeUnit.DAYS.toMillis(30));
    4747    private static final LongProperty MINIMUM_EXPIRES = new LongProperty("imagery.generic.minimum_expires", TimeUnit.HOURS.toMillis(1));
    48     private final Tile tile;
     48    protected final Tile tile;
    4949    private volatile URL url;
    5050
  • trunk/src/org/openstreetmap/josm/data/imagery/TemplatedWMSTileSource.java

    r10990 r11858  
    1919import org.openstreetmap.josm.data.coor.EastNorth;
    2020import org.openstreetmap.josm.data.coor.LatLon;
     21import org.openstreetmap.josm.data.projection.Projection;
    2122import org.openstreetmap.josm.gui.layer.WMSLayer;
    2223import org.openstreetmap.josm.tools.CheckParameterUtil;
     
    5455     * Creates a tile source based on imagery info
    5556     * @param info imagery info
     57     * @param tileProjection the tile projection
    5658     */
    57     public TemplatedWMSTileSource(ImageryInfo info) {
    58         super(info);
     59    public TemplatedWMSTileSource(ImageryInfo info, Projection tileProjection) {
     60        super(info, tileProjection);
    5961        this.serverProjections = new TreeSet<>(info.getServerProjections());
    6062        handleTemplate();
     
    6971    @Override
    7072    public String getTileUrl(int zoom, int tilex, int tiley) {
    71         String myProjCode = Main.getProjection().toCode();
     73        String myProjCode = getServerCRS();
    7274
    7375        EastNorth nw = getTileEastNorth(tilex, tiley, zoom);
     
    7981        double s = se.getY();
    8082        double e = se.getX();
    81 
    82         if (!serverProjections.contains(myProjCode) && serverProjections.contains("EPSG:4326") && "EPSG:3857".equals(myProjCode)) {
    83             LatLon swll = Main.getProjection().eastNorth2latlon(new EastNorth(w, s));
    84             LatLon nell = Main.getProjection().eastNorth2latlon(new EastNorth(e, n));
    85             myProjCode = "EPSG:4326";
    86             s = swll.lat();
    87             w = swll.lon();
    88             n = nell.lat();
    89             e = nell.lon();
    90         }
    9183
    9284        if ("EPSG:4326".equals(myProjCode) && !serverProjections.contains(myProjCode) && serverProjections.contains("CRS:84")) {
  • trunk/src/org/openstreetmap/josm/data/imagery/WMSCachedTileLoaderJob.java

    r8624 r11858  
    88import org.openstreetmap.gui.jmapviewer.Tile;
    99import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
    10 import org.openstreetmap.josm.Main;
    1110import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
    1211
     
    4039        String key = super.getCacheKey();
    4140        if (key != null) {
    42             return key + Main.getProjection().toCode();
     41            return key + tile.getSource().getServerCRS();
    4342        }
    4443        return null;
  • trunk/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java

    r11830 r11858  
    1414import java.util.Collection;
    1515import java.util.Collections;
    16 import java.util.HashSet;
     16import java.util.LinkedHashSet;
    1717import java.util.List;
    1818import java.util.Map;
     
    2020import java.util.Objects;
    2121import java.util.Optional;
    22 import java.util.Set;
    2322import java.util.SortedSet;
    2423import java.util.Stack;
     
    6261
    6362/**
    64  * Tile Source handling WMS providers
     63 * Tile Source handling WMTS providers
    6564 *
    6665 * @author Wiktor Niesiobędzki
     
    269268    private final WMTSDefaultLayer defaultLayer;
    270269
     270    private Projection tileProjection;
     271
    271272    /**
    272273     * Creates a tile source based on imagery info
     
    598599     */
    599600    public void initProjection(Projection proj) {
    600         // getLayers will return only layers matching the name, if the user already choose the layer
    601         // so we will not ask the user again to chose the layer, if he just changes projection
    602         Collection<Layer> candidates = getLayers(
    603                 currentLayer != null ? new WMTSDefaultLayer(currentLayer.identifier, currentLayer.tileMatrixSet.identifier) : defaultLayer,
    604                 proj.toCode());
    605 
    606         if (candidates.size() > 1 && defaultLayer != null) {
    607             candidates = candidates.stream()
    608                     .filter(t -> t.tileMatrixSet.identifier.equals(defaultLayer.getTileMatrixSet()))
    609                     .collect(Collectors.toList());
    610         }
    611         if (candidates.size() == 1) {
    612             Layer newLayer = candidates.iterator().next();
    613             if (newLayer != null) {
    614                 this.currentTileMatrixSet = newLayer.tileMatrixSet;
    615                 this.currentLayer = newLayer;
    616                 Collection<Double> scales = new ArrayList<>(currentTileMatrixSet.tileMatrix.size());
    617                 for (TileMatrix tileMatrix : currentTileMatrixSet.tileMatrix) {
    618                     scales.add(tileMatrix.scaleDenominator * 0.28e-03);
    619                 }
    620                 this.nativeScaleList = new ScaleList(scales);
    621             }
    622         } else if (candidates.size() > 1) {
    623             Main.warn("More than one layer WMTS available: {0} for projection {1} and name {2}. Do not know which to process",
    624                     candidates.stream().map(x -> x.getUserTitle() + ": " + x.tileMatrixSet.identifier).collect(Collectors.joining(", ")),
    625                     proj.toCode(),
    626                     currentLayer != null ? currentLayer.getUserTitle() : defaultLayer
    627                     );
    628         }
    629         this.crsScale = getTileSize() * 0.28e-03 / proj.getMetersPerUnit();
     601        if (proj.equals(tileProjection))
     602            return;
     603        List<Layer> matchingLayers = layers.stream().filter(
     604                l -> l.identifier.equals(defaultLayer.layerName) && l.tileMatrixSet.crs.equals(proj.toCode()))
     605                .collect(Collectors.toList());
     606        if (matchingLayers.size() > 1) {
     607            this.currentLayer = matchingLayers.stream().filter(
     608                    l -> l.tileMatrixSet.identifier.equals(defaultLayer.getTileMatrixSet()))
     609                    .findFirst().orElse(null);
     610            this.tileProjection = proj;
     611        } else if (matchingLayers.size() == 1) {
     612            this.currentLayer = matchingLayers.get(0);
     613            this.tileProjection = proj;
     614        } else {
     615            // no tile matrix sets with current projection
     616            if (this.currentLayer == null) {
     617                this.tileProjection = null;
     618                for (Layer layer : layers) {
     619                    if (!layer.identifier.equals(defaultLayer.layerName)) {
     620                        continue;
     621                    }
     622                    Projection pr = Projections.getProjectionByCode(layer.tileMatrixSet.crs);
     623                    if (pr != null) {
     624                        this.currentLayer = layer;
     625                        this.tileProjection = pr;
     626                        break;
     627                    }
     628                }
     629                if (this.currentLayer == null)
     630                    return;
     631            } // else: keep currentLayer and tileProjection as is
     632        }
     633        this.currentTileMatrixSet = this.currentLayer.tileMatrixSet;
     634        Collection<Double> scales = new ArrayList<>(currentTileMatrixSet.tileMatrix.size());
     635        for (TileMatrix tileMatrix : currentTileMatrixSet.tileMatrix) {
     636            scales.add(tileMatrix.scaleDenominator * 0.28e-03);
     637        }
     638        this.nativeScaleList = new ScaleList(scales);
     639        this.crsScale = getTileSize() * 0.28e-03 / this.tileProjection.getMetersPerUnit();
    630640    }
    631641
     
    655665        // no support for non-square tiles (tileHeight != tileWidth)
    656666        // and for different tile sizes at different zoom levels
    657         Collection<Layer> projLayers = getLayers(null, Main.getProjection().toCode());
     667        Collection<Layer> projLayers = getLayers(null, tileProjection.toCode());
    658668        if (!projLayers.isEmpty()) {
    659669            return projLayers.iterator().next().tileMatrixSet.tileMatrix.get(0).tileHeight;
     
    736746        TileMatrix matrix = getTileMatrix(zoom);
    737747        if (matrix == null) {
    738             return Main.getProjection().getWorldBoundsLatLon().getCenter().toCoordinate();
     748            return tileProjection.getWorldBoundsLatLon().getCenter().toCoordinate();
    739749        }
    740750        double scale = matrix.scaleDenominator * this.crsScale;
    741751        EastNorth ret = new EastNorth(matrix.topLeftCorner.east() + x * scale, matrix.topLeftCorner.north() - y * scale);
    742         return Main.getProjection().eastNorth2latlon(ret).toCoordinate();
     752        return tileProjection.eastNorth2latlon(ret).toCoordinate();
    743753    }
    744754
     
    750760        }
    751761
    752         Projection proj = Main.getProjection();
    753         EastNorth enPoint = proj.latlon2eastNorth(new LatLon(lat, lon));
     762        EastNorth enPoint = tileProjection.latlon2eastNorth(new LatLon(lat, lon));
    754763        double scale = matrix.scaleDenominator * this.crsScale;
    755764        return new TileXY(
     
    766775    @Override
    767776    public int getTileXMax(int zoom) {
    768         return getTileXMax(zoom, Main.getProjection());
     777        return getTileXMax(zoom, tileProjection);
    769778    }
    770779
    771780    @Override
    772781    public int getTileYMax(int zoom) {
    773         return getTileYMax(zoom, Main.getProjection());
     782        return getTileYMax(zoom, tileProjection);
    774783    }
    775784
     
    781790        }
    782791        double scale = matrix.scaleDenominator * this.crsScale;
    783         EastNorth point = Main.getProjection().latlon2eastNorth(new LatLon(lat, lon));
     792        EastNorth point = tileProjection.latlon2eastNorth(new LatLon(lat, lon));
    784793        return new Point(
    785794                    (int) Math.round((point.east() - matrix.topLeftCorner.east()) / scale),
     
    805814        }
    806815        double scale = matrix.scaleDenominator * this.crsScale;
    807         Projection proj = Main.getProjection();
    808816        EastNorth ret = new EastNorth(
    809817                matrix.topLeftCorner.east() + x * scale,
    810818                matrix.topLeftCorner.north() - y * scale
    811819                );
    812         LatLon ll = proj.eastNorth2latlon(ret);
     820        LatLon ll = tileProjection.eastNorth2latlon(ret);
    813821        return new Coordinate(ll.lat(), ll.lon());
    814822    }
     
    857865     * @return set of projection codes that this TileSource supports
    858866     */
    859     public Set<String> getSupportedProjections() {
    860         Set<String> ret = new HashSet<>();
     867    public Collection<String> getSupportedProjections() {
     868        Collection<String> ret = new LinkedHashSet<>();
    861869        if (currentLayer == null) {
    862870            for (Layer layer: this.layers) {
     
    910918    public ScaleList getNativeScales() {
    911919        return nativeScaleList;
     920    }
     921
     922    public Projection getTileProjection() {
     923        return tileProjection;
    912924    }
    913925
     
    978990    @Override
    979991    public String getServerCRS() {
    980         return Main.getProjection().toCode();
     992        return tileProjection.toCode();
    981993    }
    982994}
  • trunk/src/org/openstreetmap/josm/data/projection/CustomProjection.java

    r11746 r11858  
    875875        return result;
    876876    }
     877
     878    @Override
     879    public ProjectionBounds getEastNorthBoundsBox(ProjectionBounds box, Projection boxProjection) {
     880        final int n = 8;
     881        ProjectionBounds result = null;
     882        for (int i = 0; i < 4*n; i++) {
     883            EastNorth en = latlon2eastNorth(boxProjection.eastNorth2latlon(getPointAlong(i, n, box)));
     884            if (result == null) {
     885                result = new ProjectionBounds(en);
     886            } else {
     887                result.extend(en);
     888            }
     889        }
     890        return result;
     891    }
    877892}
  • trunk/src/org/openstreetmap/josm/data/projection/Projection.java

    r10829 r11858  
    8787
    8888    /**
     89     * Get a box in east/north space of this projection, that fully contains an
     90     * east/north box of another projection.
     91     *
     92     * Reprojecting a rectangular box from one projection to another may distort/rotate
     93     * the shape of the box, so in general one needs to walk along the boundary
     94     * in small steps to get a reliable result.
     95     *
     96     * This is an approximate method.
     97     *
     98     * @param box the east/north box given in projection <code>boxProjection</code>
     99     * @param boxProjection the projection of <code>box</code>
     100     * @return an east/north box in this projection, containing the given box
     101     */
     102    ProjectionBounds getEastNorthBoundsBox(ProjectionBounds box, Projection boxProjection);
     103
     104    /**
    89105     * Get the number of meters per unit of this projection. This more
    90106     * defines the scale of the map, than real conversion of unit to meters
  • trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java

    r11840 r11858  
    638638        mvs = mvs.movedTo(mvs.getCenter(), newCenter);
    639639        Point2D enOrigin = mvs.getPointFor(new EastNorth(0, 0)).getInView();
    640         Point2D enOriginAligned = new Point2D.Double(Math.round(enOrigin.getX()), Math.round(enOrigin.getY()));
     640        // as a result of the alignment, it is common to round "half integer" values
     641        // like 1.49999, which is numerically unstable; add small epsilon to resolve this
     642        double EPSILON = 1e-3;
     643        Point2D enOriginAligned = new Point2D.Double(
     644                Math.round(enOrigin.getX()) + EPSILON,
     645                Math.round(enOrigin.getY()) + EPSILON);
    641646        EastNorth enShift = mvs.getForView(enOriginAligned.getX(), enOriginAligned.getY()).getEastNorth();
    642647        newCenter = newCenter.subtract(enShift);
  • trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java

    r11846 r11858  
    4949import javax.swing.AbstractAction;
    5050import javax.swing.Action;
    51 import javax.swing.BorderFactory;
    5251import javax.swing.JCheckBoxMenuItem;
    5352import javax.swing.JLabel;
     
    5756import javax.swing.JPopupMenu;
    5857import javax.swing.JSeparator;
    59 import javax.swing.JTextField;
    6058import javax.swing.Timer;
    6159
     
    8886import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
    8987import org.openstreetmap.josm.data.preferences.IntegerProperty;
     88import org.openstreetmap.josm.data.projection.Projection;
     89import org.openstreetmap.josm.data.projection.Projections;
    9090import org.openstreetmap.josm.gui.ExtendedDialog;
    9191import org.openstreetmap.josm.gui.MapFrame;
     
    9696import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
    9797import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings.FilterChangeListener;
     98import org.openstreetmap.josm.gui.layer.imagery.ReprojectionTile;
    9899import org.openstreetmap.josm.gui.layer.imagery.TileAnchor;
    99100import org.openstreetmap.josm.gui.layer.imagery.TileCoordinateConverter;
     
    109110import org.openstreetmap.josm.tools.MemoryManager.MemoryHandle;
    110111import org.openstreetmap.josm.tools.MemoryManager.NotEnoughMemoryException;
     112import org.openstreetmap.josm.tools.Utils;
    111113
    112114/**
     
    185187    private final ImageryAdjustAction adjustAction = new ImageryAdjustAction(this);
    186188    // prepared to be moved to the painter
    187     private TileCoordinateConverter coordinateConverter;
     189    protected TileCoordinateConverter coordinateConverter;
    188190
    189191    /**
     
    346348    public Object getInfoComponent() {
    347349        JPanel panel = (JPanel) super.getInfoComponent();
     350        List<List<String>> content = new ArrayList<>();
    348351        EastNorth offset = getDisplaySettings().getDisplacement();
    349352        if (offset.distanceSq(0, 0) > 1e-10) {
    350             panel.add(new JLabel(tr("Offset: ") + offset.east() + ';' + offset.north()), GBC.eol().insets(0, 5, 10, 0));
     353            content.add(Arrays.asList(tr("Offset"), offset.east() + ";" + offset.north()));
     354        }
     355        if (coordinateConverter.requiresReprojection()) {
     356            content.add(Arrays.asList(tr("Tile download projection"), tileSource.getServerCRS()));
     357            content.add(Arrays.asList(tr("Tile display projection"), Main.getProjection().toCode()));
     358        }
     359        content.add(Arrays.asList(tr("Current zoom"), Integer.toString(currentZoomLevel)));
     360        for (List<String> entry: content) {
     361            panel.add(new JLabel(entry.get(0) + ':'), GBC.std());
     362            panel.add(GBC.glue(5, 0), GBC.std());
     363            panel.add(createTextField(entry.get(1)), GBC.eol().fill(GBC.HORIZONTAL));
    351364        }
    352365        return panel;
     
    363376     * @return average number of screen pixels per tile pixel
    364377     */
    365     private double getScaleFactor(int zoom) {
     378    protected double getScaleFactor(int zoom) {
    366379        if (coordinateConverter != null) {
    367380            return coordinateConverter.getScaleFactor(zoom);
     
    384397         */
    385398        int intResult = (int) Math.round(result + 1 + ZOOM_OFFSET.get() / 1.9);
    386 
    387         intResult = Math.min(intResult, getMaxZoomLvl());
    388         intResult = Math.max(intResult, getMinZoomLvl());
     399        intResult = Utils.clamp(intResult, getMinZoomLvl(), getMaxZoomLvl());
    389400        return intResult;
    390401    }
     
    398409        private ShowTileInfoAction() {
    399410            super(tr("Show tile info"));
     411            setEnabled(clickedTileHolder.getTile() != null);
    400412        }
    401413
    402414        private String getSizeString(int size) {
    403415            return new StringBuilder().append(size).append('x').append(size).toString();
    404         }
    405 
    406         private JTextField createTextField(String text) {
    407             JTextField ret = new JTextField(text);
    408             ret.setEditable(false);
    409             ret.setBorder(BorderFactory.createEmptyBorder());
    410             return ret;
    411416        }
    412417
     
    426431                }
    427432
    428                 String[][] content = {
    429                         {"Tile name", clickedTile.getKey()},
    430                         {"Tile url", url},
    431                         {"Tile size", getSizeString(clickedTile.getTileSource().getTileSize()) },
    432                         {"Tile display size", new StringBuilder().append(displaySize.getWidth())
    433                                                                  .append('x')
    434                                                                  .append(displaySize.getHeight()).toString()},
    435                 };
    436 
    437                 for (String[] entry: content) {
    438                     panel.add(new JLabel(tr(entry[0]) + ':'), GBC.std());
     433                List<List<String>> content = new ArrayList<>();
     434                content.add(Arrays.asList(tr("Tile name"), clickedTile.getKey()));
     435                content.add(Arrays.asList(tr("Tile URL"), url));
     436                content.add(Arrays.asList(tr("Tile size"),
     437                        getSizeString(clickedTile.getTileSource().getTileSize())));
     438                content.add(Arrays.asList(tr("Tile display size"),
     439                        new StringBuilder().append(displaySize.getWidth())
     440                                .append('x')
     441                                .append(displaySize.getHeight()).toString()));
     442                if (coordinateConverter.requiresReprojection()) {
     443                    content.add(Arrays.asList(tr("Reprojection"),
     444                            clickedTile.getTileSource().getServerCRS() +
     445                            " -> " + Main.getProjection().toCode()));
     446                    BufferedImage img = clickedTile.getImage();
     447                    if (img != null) {
     448                        content.add(Arrays.asList(tr("Reprojected tile size"),
     449                            img.getWidth() + "x" + img.getHeight()));
     450
     451                    }
     452                }
     453                for (List<String> entry: content) {
     454                    panel.add(new JLabel(entry.get(0) + ':'), GBC.std());
    439455                    panel.add(GBC.glue(5, 0), GBC.std());
    440                     panel.add(createTextField(entry[1]), GBC.eol().fill(GBC.HORIZONTAL));
     456                    panel.add(createTextField(entry.get(1)), GBC.eol().fill(GBC.HORIZONTAL));
    441457                }
    442458
     
    462478        private LoadTileAction() {
    463479            super(tr("Load tile"));
     480            setEnabled(clickedTileHolder.getTile() != null);
    464481        }
    465482
     
    946963        Tile tile = getTile(x, y, zoom);
    947964        if (tile == null) {
    948             tile = new Tile(tileSource, x, y, zoom);
     965            if (coordinateConverter.requiresReprojection()) {
     966                tile = new ReprojectionTile(tileSource, x, y, zoom);
     967            } else {
     968                tile = new Tile(tileSource, x, y, zoom);
     969            }
    949970            tileCache.addTile(tile);
    950971        }
     
    10211042
    10221043    /**
    1023      * Invalidate the layer at a time in the future so taht the user still sees the interface responsive.
     1044     * Invalidate the layer at a time in the future so that the user still sees the interface responsive.
    10241045     */
    10251046    private void invalidateLater() {
     
    10551076    }
    10561077
    1057     /**
     1078     /**
    10581079     * Draw a tile image on screen.
    10591080     * @param g the Graphics2D
     
    10661087        AffineTransform imageToScreen = anchorImage.convert(anchorScreen);
    10671088        Point2D screen0 = imageToScreen.transform(new Point.Double(0, 0), null);
    1068         Point2D screen1 = imageToScreen.transform(new Point.Double(toDrawImg.getWidth(), toDrawImg.getHeight()), null);
     1089        Point2D screen1 = imageToScreen.transform(new Point.Double(
     1090                toDrawImg.getWidth(), toDrawImg.getHeight()), null);
     1091
    10691092        Shape oldClip = null;
    10701093        if (clip != null) {
     
    10851108            boolean miss = false;
    10861109            BufferedImage img = null;
     1110            TileAnchor anchorImage = null;
    10871111            if (!tile.isLoaded() || tile.hasError()) {
    10881112                miss = true;
    10891113            } else {
    1090                 img = getLoadedTileImage(tile);
    1091                 if (img == null) {
     1114                synchronized (tile) {
     1115                    img = getLoadedTileImage(tile);
     1116                    anchorImage = getAnchor(tile, img);
     1117                }
     1118                if (img == null || anchorImage == null) {
    10921119                    miss = true;
    10931120                }
     
    10971124                return;
    10981125            }
    1099             TileAnchor anchorImage = new TileAnchor(
    1100                     new Point.Double(0, 0),
    1101                     new Point.Double(img.getWidth(), img.getHeight()));
    1102             img = applyImageProcessors((BufferedImage) img);
     1126
     1127            img = applyImageProcessors(img);
     1128
    11031129            TileAnchor anchorScreen = coordinateConverter.getScreenAnchorForTile(tile);
    11041130            synchronized (paintMutex) {
     
    11061132                drawImageInside(g, img, anchorImage, anchorScreen, null);
    11071133            }
     1134            if (tile instanceof ReprojectionTile) {
     1135                // This means we have a reprojected tile in memory cache, but not at
     1136                // current scale. Generally, the positioning of the tile will still
     1137                // be correct, but for best image quality, the tile should be
     1138                // reprojected to the target scale. The original tile image should
     1139                // still be in disk cache, so this is fairly cheap.
     1140                if (((ReprojectionTile) tile).needsUpdate(Main.map.mapView.getScale())) {
     1141                    loadTile(tile, true);
     1142                }
     1143            }
     1144
    11081145        }, missed::add);
    11091146
     
    11281165            boolean miss = false;
    11291166            BufferedImage img = null;
     1167            TileAnchor anchorImage = null;
    11301168            if (!tile.isLoaded() || tile.hasError()) {
    11311169                miss = true;
    11321170            } else {
    1133                 img = getLoadedTileImage(tile);
    1134                 if (img == null) {
     1171                synchronized (tile) {
     1172                    img = getLoadedTileImage(tile);
     1173                    anchorImage = getAnchor(tile, img);
     1174                }
     1175
     1176                if (img == null || anchorImage == null) {
    11351177                    miss = true;
    11361178                }
     
    11401182                continue;
    11411183            }
    1142             TileAnchor anchorImage = new TileAnchor(
    1143                     new Point.Double(0, 0),
    1144                     new Point.Double(img.getWidth(), img.getHeight()));
    11451184
    11461185            // applying all filters to this layer
     
    11591198        }
    11601199        return missedTiles;
     1200    }
     1201
     1202    private TileAnchor getAnchor(Tile tile, BufferedImage image) {
     1203        if (tile instanceof ReprojectionTile) {
     1204            return ((ReprojectionTile) tile).getAnchor();
     1205        } else {
     1206            return new TileAnchor(new Point.Double(0, 0), new Point.Double(image.getWidth(), image.getHeight()));
     1207        }
    11611208    }
    11621209
     
    11881235    }
    11891236
    1190     private void paintTileText(Tile tile, Graphics g, MapView mv) {
     1237    private void paintTileText(Tile tile, Graphics2D g) {
    11911238        if (tile == null) {
    11921239            return;
     
    12181265        }
    12191266
    1220         int xCursor = -1;
    1221         int yCursor = -1;
    12221267        if (Main.isDebugEnabled()) {
    1223             if (yCursor < tile.getYtile()) {
    1224                 if (Math.abs(tile.getYtile() % 32) == 31) {
    1225                     g.fillRect(0, y - 1, mv.getWidth(), 3);
    1226                 } else {
    1227                     g.drawLine(0, y, mv.getWidth(), y);
    1228                 }
    1229                 //yCursor = t.getYtile();
    1230             }
    1231             // This draws the vertical lines for the entire column. Only draw them for the top tile in the column.
    1232             if (xCursor < tile.getXtile()) {
    1233                 if (tile.getXtile() % 32 == 0) {
    1234                     // level 7 tile boundary
    1235                     g.fillRect(x - 1, 0, 3, mv.getHeight());
    1236                 } else {
    1237                     g.drawLine(x, 0, x, mv.getHeight());
    1238                 }
    1239                 //xCursor = t.getXtile();
    1240             }
     1268            // draw tile outline in semi-transparent red
     1269            g.setColor(new Color(255, 0, 0, 50));
     1270            g.draw(coordinateConverter.getScreenQuadrilateralForTile(tile));
    12411271        }
    12421272    }
     
    13971427     */
    13981428    protected TileSet getTileSet(ProjectionBounds bounds, int zoom) {
    1399         IProjected topLeftUnshifted = coordinateConverter.shiftDisplayToServer(bounds.getMin());
    1400         IProjected botRightUnshifted = coordinateConverter.shiftDisplayToServer(bounds.getMax());
    1401         TileXY t1 = tileSource.projectedToTileXY(topLeftUnshifted, zoom);
    1402         TileXY t2 = tileSource.projectedToTileXY(botRightUnshifted, zoom);
     1429        if (zoom == 0)
     1430            return new TileSet();
     1431        TileXY t1, t2;
     1432        if (coordinateConverter.requiresReprojection()) {
     1433            Projection projCurrent = Main.getProjection();
     1434            Projection projServer = Projections.getProjectionByCode(tileSource.getServerCRS());
     1435            bounds = new ProjectionBounds(
     1436                    new EastNorth(coordinateConverter.shiftDisplayToServer(bounds.getMin())),
     1437                    new EastNorth(coordinateConverter.shiftDisplayToServer(bounds.getMax())));
     1438            bounds = projServer.getEastNorthBoundsBox(bounds, projCurrent);
     1439            t1 = tileSource.projectedToTileXY(bounds.getMin().toProjected(), zoom);
     1440            t2 = tileSource.projectedToTileXY(bounds.getMax().toProjected(), zoom);
     1441        } else {
     1442            IProjected topLeftUnshifted = coordinateConverter.shiftDisplayToServer(bounds.getMin());
     1443            IProjected botRightUnshifted = coordinateConverter.shiftDisplayToServer(bounds.getMax());
     1444            t1 = tileSource.projectedToTileXY(topLeftUnshifted, zoom);
     1445            t2 = tileSource.projectedToTileXY(botRightUnshifted, zoom);
     1446        }
    14031447        return new TileSet(t1, t2, zoom);
    14041448    }
     
    15931637        // The current zoom tileset should have all of its tiles due to the loadAllTiles(), unless it to tooLarge()
    15941638        for (Tile t : ts.allExistingTiles()) {
    1595             this.paintTileText(t, g, mv);
     1639            this.paintTileText(t, g);
    15961640        }
    15971641
     
    16401684            Main.debug("getTileForPixelpos("+px+", "+py+')');
    16411685        }
    1642         Point clicked = new Point(px, py);
    1643         TileSet ts = getVisibleTileSet();
    1644 
    1645         if (!ts.tooLarge()) {
    1646             ts.loadAllTiles(false); // make sure there are tile objects for all tiles
    1647         }
    1648         Stream<Tile> clickedTiles = ts.allExistingTiles().stream()
    1649                 .filter(t -> coordinateConverter.getRectangleForTile(t).contains(clicked));
    1650         if (Main.isTraceEnabled()) {
    1651             clickedTiles = clickedTiles.peek(t -> Main.trace("Clicked on tile: " + t.getXtile() + ' ' + t.getYtile() +
    1652                     " currentZoomLevel: " + currentZoomLevel));
    1653         }
    1654         return clickedTiles.findAny().orElse(null);
     1686        TileXY xy = coordinateConverter.getTileforPixel(px, py, currentZoomLevel);
     1687        return getTile(xy.getXIndex(), xy.getYIndex(), currentZoomLevel);
    16551688    }
    16561689
  • trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java

    r11785 r11858  
    22package org.openstreetmap.josm.gui.layer;
    33
    4 import static org.openstreetmap.josm.tools.I18n.tr;
    54import static org.openstreetmap.josm.tools.I18n.trc;
    65
     
    1110import java.awt.image.BufferedImageOp;
    1211import java.util.ArrayList;
     12import java.util.Arrays;
     13import java.util.Collection;
    1314import java.util.List;
    1415
    1516import javax.swing.AbstractAction;
    1617import javax.swing.Action;
     18import javax.swing.BorderFactory;
    1719import javax.swing.Icon;
    1820import javax.swing.JCheckBoxMenuItem;
     
    2426import javax.swing.JPopupMenu;
    2527import javax.swing.JSeparator;
     28import javax.swing.JTextField;
    2629
    2730import org.openstreetmap.josm.Main;
     
    3336import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
    3437import org.openstreetmap.josm.gui.layer.imagery.TileSourceDisplaySettings;
    35 import org.openstreetmap.josm.gui.widgets.UrlLabel;
    3638import org.openstreetmap.josm.tools.GBC;
     39import static org.openstreetmap.josm.tools.I18n.tr;
    3740import org.openstreetmap.josm.tools.ImageProvider;
    3841import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
     
    146149    public void mergeFrom(Layer from) {
    147150    }
     151   
     152    public abstract Collection<String> getNativeProjections();
    148153
    149154    @Override
     
    152157        panel.add(new JLabel(getToolTipText()), GBC.eol());
    153158        if (info != null) {
    154             String url = info.getUrl();
    155             if (url != null) {
    156                 panel.add(new JLabel(tr("URL: ")), GBC.std().insets(0, 5, 2, 0));
    157                 panel.add(new UrlLabel(url), GBC.eol().insets(2, 5, 10, 0));
     159            List<List<String>> content = new ArrayList<>();
     160            content.add(Arrays.asList(tr("Name"), info.getName()));
     161            content.add(Arrays.asList(tr("Type"), info.getImageryType().getTypeString().toUpperCase()));
     162            content.add(Arrays.asList(tr("URL"), info.getUrl()));
     163            content.add(Arrays.asList(tr("Id"), info.getId() == null ? "-" : info.getId()));
     164            if (info.getMinZoom() != 0) {
     165                content.add(Arrays.asList(tr("Min. zoom"), Integer.toString(info.getMinZoom())));
     166            }
     167            if (info.getMaxZoom() != 0) {
     168                content.add(Arrays.asList(tr("Max. zoom"), Integer.toString(info.getMaxZoom())));
     169            }
     170            if (info.getDescription() != null) {
     171                content.add(Arrays.asList(tr("Description"), info.getDescription()));
     172            }
     173            content.add(Arrays.asList(tr("Native projections"), Utils.join(", ", getNativeProjections())));
     174            for (List<String> entry: content) {
     175                panel.add(new JLabel(entry.get(0) + ':'), GBC.std());
     176                panel.add(GBC.glue(5, 0), GBC.std());
     177                panel.add(createTextField(entry.get(1)), GBC.eol().fill(GBC.HORIZONTAL));
    158178            }
    159179        }
    160180        return panel;
     181    }
     182
     183    protected JTextField createTextField(String text) {
     184        JTextField ret = new JTextField(text);
     185        ret.setEditable(false);
     186        ret.setBorder(BorderFactory.createEmptyBorder());
     187        return ret;
    161188    }
    162189
  • trunk/src/org/openstreetmap/josm/gui/layer/TMSLayer.java

    r11167 r11858  
    66import java.util.ArrayList;
    77import java.util.Collection;
     8import java.util.Collections;
     9import java.util.List;
    810
    911import org.apache.commons.jcs.access.CacheAccess;
     
    7981
    8082    @Override
    81     public final boolean isProjectionSupported(Projection proj) {
    82         return "EPSG:3857".equals(proj.toCode()) || "EPSG:4326".equals(proj.toCode());
    83     }
    84 
    85     @Override
    86     public final String nameSupportedProjections() {
    87         return tr("EPSG:4326 and Mercator projection are supported");
     83    public Collection<String> getNativeProjections() {
     84        return Collections.singletonList("EPSG:3857");
    8885    }
    8986
     
    161158        return new ScaleList(scales);
    162159    }
    163  }
     160}
  • trunk/src/org/openstreetmap/josm/gui/layer/WMSLayer.java

    r11848 r11858  
    77import java.util.ArrayList;
    88import java.util.Arrays;
     9import java.util.Collection;
    910import java.util.List;
    10 import java.util.Set;
    11 import java.util.TreeSet;
     11import java.util.Objects;
    1212
    1313import javax.swing.AbstractAction;
     
    2828import org.openstreetmap.josm.data.preferences.IntegerProperty;
    2929import org.openstreetmap.josm.data.projection.Projection;
     30import org.openstreetmap.josm.data.projection.Projections;
    3031import org.openstreetmap.josm.gui.ExtendedDialog;
    3132import org.openstreetmap.josm.gui.layer.imagery.TileSourceDisplaySettings;
     
    5556    private static final String CACHE_REGION_NAME = "WMS";
    5657
    57     private final Set<String> supportedProjections;
     58    private final List<String> serverProjections;
    5859
    5960    /**
     
    6667        CheckParameterUtil.ensureParameterNotNull(info.getUrl(), "info.url");
    6768        TemplatedWMSTileSource.checkUrl(info.getUrl());
    68         this.supportedProjections = new TreeSet<>(info.getServerProjections());
     69        this.serverProjections = new ArrayList<>(info.getServerProjections());
    6970    }
    7071
     
    8788    @Override
    8889    protected AbstractWMSTileSource getTileSource() {
    89         AbstractWMSTileSource tileSource = new TemplatedWMSTileSource(info);
     90        AbstractWMSTileSource tileSource = new TemplatedWMSTileSource(
     91                info, chooseProjection(Main.getProjection()));
    9092        info.setAttribution(tileSource);
    9193        return tileSource;
     
    112114
    113115    @Override
    114     public boolean isProjectionSupported(Projection proj) {
    115         return supportedProjections == null || supportedProjections.isEmpty() || supportedProjections.contains(proj.toCode()) ||
    116                 (info.isEpsg4326To3857Supported() && supportedProjections.contains("EPSG:4326")
    117                         && "EPSG:3857".equals(Main.getProjection().toCode()));
    118     }
    119 
    120     @Override
    121     public String nameSupportedProjections() {
    122         StringBuilder ret = new StringBuilder();
    123         for (String e: supportedProjections) {
    124             ret.append(e).append(", ");
    125         }
    126         String appendix = "";
    127 
    128         if (isReprojectionPossible()) {
    129             appendix = ". <p>" + tr("JOSM will use EPSG:4326 to query the server, but results may vary "
    130                     + "depending on the WMS server") + "</p>";
    131         }
    132         return ret.substring(0, ret.length()-2) + appendix;
     116    public Collection<String> getNativeProjections() {
     117        return serverProjections;
    133118    }
    134119
    135120    @Override
    136121    public void projectionChanged(Projection oldValue, Projection newValue) {
    137         // do not call super - we need custom warning dialog
     122        Projection tileProjection = chooseProjection(newValue);
     123        if (!Objects.equals(tileSource.getTileProjection(), tileProjection)) {
     124            tileSource.setTileProjection(tileProjection);
     125        }
     126    }
    138127
    139         if (!isProjectionSupported(newValue)) {
    140             String message =
    141                     "<html><body><p>" + tr("The layer {0} does not support the new projection {1}.",
    142                             Utils.escapeReservedCharactersHTML(getName()), newValue.toCode()) +
    143                     "<p style='width: 450px; position: absolute; margin: 0px;'>" +
    144                             tr("Supported projections are: {0}", nameSupportedProjections()) + "</p>" +
    145                     "<p>" + tr("Change the projection again or remove the layer.");
    146 
    147             ExtendedDialog warningDialog = new ExtendedDialog(Main.parent, tr("Warning"), new String[]{tr("OK")}).
    148                     setContent(message).
    149                     setIcon(JOptionPane.WARNING_MESSAGE);
    150 
    151             if (isReprojectionPossible()) {
    152                 warningDialog.toggleEnable("imagery.wms.projectionSupportWarnings." + tileSource.getBaseUrl());
     128    private Projection chooseProjection(Projection requested) {
     129        if (serverProjections.contains(requested.toCode())) {
     130            return requested;
     131        } else {
     132            for (String code : serverProjections) {
     133                Projection proj = Projections.getProjectionByCode(code);
     134                if (proj != null) {
     135                    Main.info(tr("Reprojecting layer {0} from {1} to {2}. For best image quality and performance,"
     136                            + " switch to one of the supported projections: {3}",
     137                            getName(), proj.toCode(), Main.getProjection().toCode(), Utils.join(", ", getNativeProjections())));
     138                    return proj;
     139                }
    153140            }
    154             warningDialog.showDialog();
    155         }
    156 
    157         if (!newValue.equals(oldValue)) {
    158             tileSource.initProjection(newValue);
     141            Main.warn(tr("Unable to find supported projection for layer {0}. Using {1}.", getName(), requested.toCode()));
     142            return requested;
    159143        }
    160144    }
     
    176160        return AbstractCachedTileSourceLayer.getCache(CACHE_REGION_NAME);
    177161    }
    178 
    179     private boolean isReprojectionPossible() {
    180         return supportedProjections.contains("EPSG:4326") && "EPSG:3857".equals(Main.getProjection().toCode());
    181     }
    182162}
  • trunk/src/org/openstreetmap/josm/gui/layer/WMTSLayer.java

    r11789 r11858  
    33
    44import java.io.IOException;
    5 import java.util.Set;
     5import java.util.Collection;
    66
    77import org.apache.commons.jcs.access.CacheAccess;
     
    1515import org.openstreetmap.josm.data.projection.Projection;
    1616import org.openstreetmap.josm.gui.layer.imagery.TileSourceDisplaySettings;
     17import org.openstreetmap.josm.tools.Utils;
    1718
    1819/**
     
    7576            return getMaxZoomLvl();
    7677        }
    77         double displayScale = Main.map.mapView.getScale() * Main.getProjection().getMetersPerUnit(); // meter per pixel
     78        double displayScale = Main.map.mapView.getScale();
     79        if (coordinateConverter.requiresReprojection()) {
     80            displayScale *= Main.getProjection().getMetersPerUnit();
     81        }
    7882        Scale snap = scaleList.getSnapScale(displayScale, false);
    79         return Math.max(
    80                 getMinZoomLvl(),
    81                 Math.min(
    82                         snap != null ? snap.getIndex() : getMaxZoomLvl(),
    83                         getMaxZoomLvl()
    84                         )
    85                 );
     83        return Utils.clamp(snap != null ? snap.getIndex() : getMaxZoomLvl(),
     84                getMinZoomLvl(), getMaxZoomLvl());
    8685    }
    8786
     
    9291
    9392    @Override
    94     public boolean isProjectionSupported(Projection proj) {
    95         Set<String> supportedProjections = tileSource.getSupportedProjections();
    96         return supportedProjections.contains(proj.toCode());
    97     }
    98 
    99     @Override
    100     public String nameSupportedProjections() {
    101         StringBuilder ret = new StringBuilder();
    102         for (String e: tileSource.getSupportedProjections()) {
    103             ret.append(e).append(", ");
    104         }
    105         return ret.length() > 2 ? ret.substring(0, ret.length()-2) : ret.toString();
     93    public Collection<String> getNativeProjections() {
     94        return tileSource.getSupportedProjections();
    10695    }
    10796
  • trunk/src/org/openstreetmap/josm/gui/layer/imagery/TileCoordinateConverter.java

    r11846 r11858  
    1212import org.openstreetmap.gui.jmapviewer.interfaces.IProjected;
    1313import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
     14import org.openstreetmap.josm.Main;
    1415import org.openstreetmap.josm.data.coor.EastNorth;
    1516import org.openstreetmap.josm.data.coor.LatLon;
     
    8586     */
    8687    public Point2D getPixelForTile(Tile tile) {
    87         return this.getPixelForTile(tile.getXtile(), tile.getYtile(), tile.getZoom());
     88        return getPixelForTile(tile.getXtile(), tile.getYtile(), tile.getZoom());
     89    }
     90
     91    /**
     92     * Convert screen pixel coordinate to tile position at certain zoom level.
     93     * @param sx x coordinate (screen pixel)
     94     * @param sy y coordinate (screen pixel)
     95     * @param zoom zoom level
     96     * @return the tile
     97     */
     98    public TileXY getTileforPixel(int sx, int sy, int zoom) {
     99        if (requiresReprojection()) {
     100            LatLon ll = getProjecting().eastNorth2latlonClamped(mapView.getEastNorth(sx, sy));
     101            return tileSource.latLonToTileXY(ll.toCoordinate(), zoom);
     102        } else {
     103            IProjected p = shiftDisplayToServer(mapView.getEastNorth(sx, sy));
     104            return tileSource.projectedToTileXY(p, zoom);
     105        }
    88106    }
    89107
     
    91109     * Gets the position of the tile inside the map view.
    92110     * @param tile The tile
    93      * @return The positon.
     111     * @return The positon as a rectangle in screen coordinates
    94112     */
    95113    public Rectangle2D getRectangleForTile(Tile tile) {
     
    130148     */
    131149    public double getScaleFactor(int zoom) {
    132         LatLon topLeft = mapView.getLatLon(0, 0);
    133         LatLon botRight = mapView.getLatLon(mapView.getWidth(), mapView.getHeight());
    134         TileXY t1 = tileSource.latLonToTileXY(topLeft.toCoordinate(), zoom);
    135         TileXY t2 = tileSource.latLonToTileXY(botRight.toCoordinate(), zoom);
    136 
     150        TileXY t1, t2;
     151        if (requiresReprojection()) {
     152            LatLon topLeft = mapView.getLatLon(0, 0);
     153            LatLon botRight = mapView.getLatLon(mapView.getWidth(), mapView.getHeight());
     154            t1 = tileSource.latLonToTileXY(topLeft.toCoordinate(), zoom);
     155            t2 = tileSource.latLonToTileXY(botRight.toCoordinate(), zoom);
     156        }  else {
     157            EastNorth topLeftEN = mapView.getEastNorth(0, 0);
     158            EastNorth botRightEN = mapView.getEastNorth(mapView.getWidth(), mapView.getHeight());
     159            t1 = tileSource.projectedToTileXY(topLeftEN.toProjected(), zoom);
     160            t2 = tileSource.projectedToTileXY(botRightEN.toProjected(), zoom);
     161        }
    137162        int screenPixels = mapView.getWidth()*mapView.getHeight();
    138163        double tilePixels = Math.abs((t2.getY()-t1.getY())*(t2.getX()-t1.getX())*tileSource.getTileSize()*tileSource.getTileSize());
     
    147172     */
    148173    public TileAnchor getScreenAnchorForTile(Tile tile) {
    149         IProjected p1 = tileSource.tileXYtoProjected(tile.getXtile(), tile.getYtile(), tile.getZoom());
    150         IProjected p2 = tileSource.tileXYtoProjected(tile.getXtile() + 1, tile.getYtile() + 1, tile.getZoom());
    151         return new TileAnchor(pos(p1).getInView(), pos(p2).getInView());
     174        if (requiresReprojection()) {
     175            ICoordinate c1 = tile.getTileSource().tileXYToLatLon(tile);
     176            ICoordinate c2 = tile.getTileSource().tileXYToLatLon(tile.getXtile() + 1, tile.getYtile() + 1, tile.getZoom());
     177            return new TileAnchor(pos(c1).getInView(), pos(c2).getInView());
     178        } else {
     179            IProjected p1 = tileSource.tileXYtoProjected(tile.getXtile(), tile.getYtile(), tile.getZoom());
     180            IProjected p2 = tileSource.tileXYtoProjected(tile.getXtile() + 1, tile.getYtile() + 1, tile.getZoom());
     181            return new TileAnchor(pos(p1).getInView(), pos(p2).getInView());
     182        }
     183    }
     184
     185    /**
     186     * Return true if tiles need to be reprojected from server projection to display projection.
     187     * @return true if tiles need to be reprojected from server projection to display projection
     188     */
     189    public boolean requiresReprojection() {
     190        return !tileSource.getServerCRS().equals(Main.getProjection().toCode());
    152191    }
    153192}
  • trunk/src/org/openstreetmap/josm/io/imagery/ImageryReader.java

    r11575 r11858  
    458458                    entry.setGeoreferenceValid(Boolean.parseBoolean(accumulator.toString()));
    459459                    break;
    460                 case "epsg4326to3857Supported":
    461                     entry.setEpsg4326To3857Supported(Boolean.parseBoolean(accumulator.toString()));
    462                     break;
    463460                default: // Do nothing
    464461                }
Note: See TracChangeset for help on using the changeset viewer.