Changeset 5969 in josm


Ignore:
Timestamp:
2013-05-27T18:01:14+02:00 (11 years ago)
Author:
xeen
Message:

automatically zoom WMS sources (fixes #7563)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/layer/WMSLayer.java

    r5889 r5969  
    9797    }
    9898
    99     private static final ObjectFactory OBJECT_FACTORY = null; // Fake reference to keep build scripts from removing ObjectFactory class. This class is not used directly but it's necessary for jaxb to work
     99    // Fake reference to keep build scripts from removing ObjectFactory class. This class is not used directly but it's necessary for jaxb to work
     100    private static final ObjectFactory OBJECT_FACTORY = null;
     101
     102    // these values correspond to the zoom levels used throughout OSM and are in meters/pixel from zoom level 0 to 18.
     103    // taken from http://wiki.openstreetmap.org/wiki/Zoom_levels
     104    private static final Double[] snapLevels = { 156412.0, 78206.0, 39103.0, 19551.0, 9776.0, 4888.0,
     105        2444.0, 1222.0, 610.984, 305.492, 152.746, 76.373, 38.187, 19.093, 9.547, 4.773, 2.387, 1.193, 0.596 };
    100106
    101107    public static final BooleanProperty PROP_ALPHA_CHANNEL = new BooleanProperty("imagery.wms.alpha_channel", true);
     
    107113
    108114    public int messageNum = 5; //limit for messages per layer
    109     protected String resolution;
     115    protected double resolution;
     116    protected String resolutionText;
    110117    protected int imageSize;
    111118    protected int dax = 10;
     
    117124    protected final int serializeFormatVersion = 5;
    118125    protected boolean autoDownloadEnabled = true;
     126    protected boolean autoResolutionEnabled = true;
    119127    protected boolean settingsChanged;
    120128    public WmsCache cache;
     
    180188            }
    181189        }
    182         if(this.info.getPixelPerDegree() == 0.0) {
    183             this.info.setPixelPerDegree(getPPD());
    184         }
    185         resolution = Main.map.mapView.getDist100PixelText();
     190
     191        // if automatic resolution is enabled, ensure that the first zoom level
     192        // is already snapped. Otherwise it may load tiles that will never get
     193        // used again when zooming.
     194        updateResolutionSetting(this, autoResolutionEnabled);
    186195
    187196        final MouseAdapter adapter = new MouseAdapter() {
     
    287296    @Override public String getToolTipText() {
    288297        if(autoDownloadEnabled)
    289             return tr("WMS layer ({0}), automatically downloading in zoom {1}", getName(), resolution);
     298            return tr("WMS layer ({0}), automatically downloading in zoom {1}", getName(), resolutionText);
    290299        else
    291             return tr("WMS layer ({0}), downloading in zoom {1}", getName(), resolution);
     300            return tr("WMS layer ({0}), downloading in zoom {1}", getName(), resolutionText);
    292301    }
    293302
     
    303312    @Override public void paint(Graphics2D g, final MapView mv, Bounds b) {
    304313        if(info.getUrl() == null || (usesInvalidUrl && !isInvalidUrlConfirmed)) return;
     314
     315        if (autoResolutionEnabled && getBestZoom() != mv.getDist100Pixel()) {
     316            changeResolution(this, true);
     317        }
    305318
    306319        settingsChanged = false;
     
    478491                new BookmarkWmsAction(),
    479492                SeparatorLayerAction.INSTANCE,
    480                 new ZoomToNativeResolution(),
    481493                new StartStopAction(),
    482494                new ToggleAlphaAction(),
     495                new ToggleAutoResolutionAction(),
    483496                new ChangeResolutionAction(),
     497                new ZoomToNativeResolution(),
    484498                new ReloadErrorTilesAction(),
    485499                new DownloadAction(),
     
    667681    }
    668682
     683    /**
     684     * Finds the most suitable resolution for the current zoom level, but prefers
     685     * higher resolutions. Snaps to values defined in snapLevels.
     686     * @return
     687     */
     688    private static double getBestZoom() {
     689        // not sure why getDist100Pixel returns values corresponding to
     690        // the snapLevels, which are in meters per pixel. It works, though.
     691        double dist = Main.map.mapView.getDist100Pixel();
     692        for(int i = snapLevels.length-2; i >= 0; i--) {
     693            if(snapLevels[i+1]/3 + snapLevels[i]*2/3 > dist)
     694                return snapLevels[i+1];
     695        }
     696        return snapLevels[0];
     697    }
     698
     699    /**
     700     * Updates the given layer’s resolution settings to the current zoom level. Does
     701     * not update existing tiles, only new ones will be subject to the new settings.
     702     *
     703     * @param layer
     704     * @param snap  Set to true if the resolution should snap to certain values instead of
     705     *              matching the current zoom level perfectly
     706     */
     707    private static void updateResolutionSetting(WMSLayer layer, boolean snap) {
     708        if(snap) {
     709            layer.resolution = getBestZoom();
     710            layer.resolutionText = MapView.getDistText(layer.resolution);
     711        } else {
     712            layer.resolution = Main.map.mapView.getDist100Pixel();
     713            layer.resolutionText = Main.map.mapView.getDist100PixelText();
     714        }
     715        layer.info.setPixelPerDegree(layer.getPPD());
     716    }
     717
     718    /**
     719     * Updates the given layer’s resolution settings to the current zoom level and
     720     * updates existing tiles. If round is true, tiles will be updated gradually, if
     721     * false they will be removed instantly (and redrawn only after the new resolution
     722     * image has been loaded).
     723     * @param layer
     724     * @param snap  Set to true if the resolution should snap to certain values instead of
     725     *              matching the current zoom level perfectly
     726     */
     727    private static void changeResolution(WMSLayer layer, boolean snap) {
     728        updateResolutionSetting(layer, snap);
     729
     730        layer.settingsChanged = true;
     731
     732        // Don’t move tiles off screen when the resolution is rounded. This
     733        // prevents some flickering when zooming with auto-resolution enabled
     734        // and instead gradually updates each tile.
     735        if(!snap) {
     736            for(int x = 0; x<layer.dax; ++x) {
     737                for(int y = 0; y<layer.day; ++y) {
     738                    layer.images[x][y].changePosition(-1, -1);
     739                }
     740            }
     741        }
     742    }
     743
     744
    669745    public static class ChangeResolutionAction extends AbstractAction implements LayerAction {
    670746        public ChangeResolutionAction() {
     
    672748        }
    673749
    674         private void changeResolution(WMSLayer layer) {
    675             layer.resolution = Main.map.mapView.getDist100PixelText();
    676             layer.info.setPixelPerDegree(layer.getPPD());
    677             layer.settingsChanged = true;
    678             for(int x = 0; x<layer.dax; ++x) {
    679                 for(int y = 0; y<layer.day; ++y) {
    680                     layer.images[x][y].changePosition(-1, -1);
    681                 }
    682             }
    683         }
    684 
    685750        @Override
    686751        public void actionPerformed(ActionEvent ev) {
     
    691756            List<Layer> layers = LayerListDialog.getInstance().getModel().getSelectedLayers();
    692757            for (Layer l: layers) {
    693                 changeResolution((WMSLayer) l);
     758                changeResolution((WMSLayer) l, false);
    694759            }
    695760            Main.map.mapView.repaint();
     
    762827            return item;
    763828        }
     829        @Override
     830        public boolean supportLayers(List<Layer> layers) {
     831            return layers.size() == 1 && layers.get(0) instanceof WMSLayer;
     832        }
     833    }
     834
     835
     836    public class ToggleAutoResolutionAction extends AbstractAction implements LayerAction {
     837        public ToggleAutoResolutionAction() {
     838            super(tr("Automatically change resolution"));
     839        }
     840
     841        @Override
     842        public void actionPerformed(ActionEvent ev) {
     843            JCheckBoxMenuItem checkbox = (JCheckBoxMenuItem) ev.getSource();
     844            autoResolutionEnabled = checkbox.isSelected();
     845        }
     846
     847        @Override
     848        public Component createMenuComponent() {
     849            JCheckBoxMenuItem item = new JCheckBoxMenuItem(this);
     850            item.setSelected(autoResolutionEnabled);
     851            return item;
     852        }
     853
    764854        @Override
    765855        public boolean supportLayers(List<Layer> layers) {
Note: See TracChangeset for help on using the changeset viewer.