Ticket #12350: NativeScaleLayer.patch
File NativeScaleLayer.patch, 39.4 KB (added by , 8 years ago) |
---|
-
src/org/openstreetmap/gui/jmapviewer/OsmMercator.java
diff --git a/images/dialogs/layerlist/scale.png b/images/dialogs/layerlist/scale.png new file mode 100644 index 0000000..f47f480 Binary files /dev/null and b/images/dialogs/layerlist/scale.png differ diff --git a/src/org/openstreetmap/gui/jmapviewer/OsmMercator.java b/src/org/openstreetmap/gui/jmapviewer/OsmMercator.java index fbd1028..7bfdff5 100644
a b public class OsmMercator { 21 21 /** minimum latitude (south) for mercator display */ 22 22 public static final double MIN_LAT = -85.05112877980659; 23 23 /** equatorial earth radius for EPSG:3857 (Mercator) */ 24 p rivate staticdouble EARTH_RADIUS = 6378137;24 public static final double EARTH_RADIUS = 6378137; 25 25 26 26 /** 27 27 * instance with tile size of 256 for easy conversions -
src/org/openstreetmap/josm/actions/ZoomInAction.java
diff --git a/src/org/openstreetmap/josm/actions/ZoomInAction.java b/src/org/openstreetmap/josm/actions/ZoomInAction.java index 3b32f49..20853e9 100644
a b public final class ZoomInAction extends JosmAction { 46 46 @Override 47 47 public void actionPerformed(ActionEvent e) { 48 48 if (!Main.isDisplayingMapView()) return; 49 Main.map.mapView.zoom ToFactor(1/Math.sqrt(2));49 Main.map.mapView.zoomIn(); 50 50 } 51 51 52 52 @Override -
src/org/openstreetmap/josm/actions/ZoomOutAction.java
diff --git a/src/org/openstreetmap/josm/actions/ZoomOutAction.java b/src/org/openstreetmap/josm/actions/ZoomOutAction.java index 33f4a84..98bb1c2 100644
a b public final class ZoomOutAction extends JosmAction { 32 32 @Override 33 33 public void actionPerformed(ActionEvent e) { 34 34 if (!Main.isDisplayingMapView()) return; 35 Main.map.mapView.zoom ToFactor(Math.sqrt(2));35 Main.map.mapView.zoomOut(); 36 36 } 37 37 38 38 @Override -
src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java
diff --git a/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java b/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java index 60217ae..4a66efd 100644
a b import org.openstreetmap.josm.data.coor.LatLon; 46 46 import org.openstreetmap.josm.data.projection.Projection; 47 47 import org.openstreetmap.josm.data.projection.Projections; 48 48 import org.openstreetmap.josm.gui.ExtendedDialog; 49 import org.openstreetmap.josm.gui.layer.NativeScaleLayer.Scale; 50 import org.openstreetmap.josm.gui.layer.NativeScaleLayer.ScaleList; 49 51 import org.openstreetmap.josm.io.CachedFile; 50 52 import org.openstreetmap.josm.tools.CheckParameterUtil; 51 53 import org.openstreetmap.josm.tools.GBC; … … public class WMTSTileSource extends AbstractTMSTileSource implements TemplatedTi 285 287 return output.toString(); 286 288 } 287 289 288 private Collection<Layer> getCapabilities() throws IOException{290 private Collection<Layer> getCapabilities() { 289 291 XMLInputFactory factory = XMLInputFactory.newFactory(); 290 292 // do not try to load external entities, nor validate the XML 291 293 factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); … … public class WMTSTileSource extends AbstractTMSTileSource implements TemplatedTi 708 710 if (zoom > getMaxZoom()) { 709 711 return null; 710 712 } 711 if (zoom < 1) {713 if (zoom < 0) { 712 714 return null; 713 715 } 714 return this.currentTileMatrixSet.tileMatrix.get(zoom - 1);716 return this.currentTileMatrixSet.tileMatrix.get(zoom); 715 717 } 716 718 717 719 @Override … … public class WMTSTileSource extends AbstractTMSTileSource implements TemplatedTi 829 831 @Override 830 832 public int getMaxZoom() { 831 833 if (this.currentTileMatrixSet != null) { 832 return this.currentTileMatrixSet.tileMatrix.size() ;834 return this.currentTileMatrixSet.tileMatrix.size()-1; 833 835 } 834 836 return 0; 835 837 } … … public class WMTSTileSource extends AbstractTMSTileSource implements TemplatedTi 910 912 EastNorth max = proj.latlon2eastNorth(proj.getWorldBoundsLatLon().getMax()); 911 913 return (int) Math.ceil(Math.abs(max.east() - min.east()) / scale); 912 914 } 915 916 /** 917 * Get native scales of tile source. 918 * @return {@link ScaleList} of native scales 919 */ 920 public ScaleList getNativeScales() { 921 ScaleList scales = new ScaleList(); 922 if (currentTileMatrixSet != null) { 923 for (TileMatrix tileMatrix : currentTileMatrixSet.tileMatrix) { 924 scales.add(new Scale(tileMatrix.scaleDenominator * 0.28e-03)); 925 } 926 } 927 return scales; 928 } 929 913 930 } -
new file src/org/openstreetmap/josm/data/preferences/DoubleProperty.java
diff --git a/src/org/openstreetmap/josm/data/preferences/DoubleProperty.java b/src/org/openstreetmap/josm/data/preferences/DoubleProperty.java new file mode 100644 index 0000000..44ca4c2
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.data.preferences; 3 4 import org.openstreetmap.josm.Main; 5 6 /** 7 * A property containing an {@code Double} value. 8 * @since 3246 9 */ 10 public class DoubleProperty extends AbstractProperty<Double> { 11 12 /** 13 * Constructs a new {@code DoubleProperty}. 14 * @param key The property key 15 * @param defaultValue The default value 16 */ 17 public DoubleProperty(String key, double defaultValue) { 18 super(key, defaultValue); 19 } 20 21 @Override 22 public Double get() { 23 return Main.pref.getDouble(getKey(), getDefaultValue()); 24 } 25 26 @Override 27 public boolean put(Double value) { 28 return Main.pref.putDouble(getKey(), value); 29 } 30 31 /** 32 * parses and saves a double precision value 33 * @param value the value to be parsed 34 * @return true - preference value has changed 35 * false - parsing failed or preference value has not changed 36 */ 37 public boolean parseAndPut(String value) { 38 try { 39 return put(Double.valueOf(value)); 40 } catch (NumberFormatException ex) { 41 return false; 42 } 43 } 44 } -
src/org/openstreetmap/josm/gui/MapMover.java
diff --git a/src/org/openstreetmap/josm/gui/MapMover.java b/src/org/openstreetmap/josm/gui/MapMover.java index 4de6049..5580884 100644
a b public class MapMover extends MouseAdapter implements MouseMotionListener, Mouse 213 213 */ 214 214 @Override 215 215 public void mouseWheelMoved(MouseWheelEvent e) { 216 nc.zoom ToFactor(e.getX(), e.getY(), Math.pow(Math.sqrt(2), e.getWheelRotation()));216 nc.zoomManyTimes(e.getX(), e.getY(), e.getWheelRotation()); 217 217 } 218 218 219 219 /** -
src/org/openstreetmap/josm/gui/MapSlider.java
diff --git a/src/org/openstreetmap/josm/gui/MapSlider.java b/src/org/openstreetmap/josm/gui/MapSlider.java index fab953d..f6f2fc1 100644
a b import javax.swing.JSlider; 10 10 import javax.swing.event.ChangeEvent; 11 11 import javax.swing.event.ChangeListener; 12 12 13 import org.openstreetmap.josm.data.ProjectionBounds;14 13 import org.openstreetmap.josm.gui.help.Helpful; 15 14 16 15 class MapSlider extends JSlider implements PropertyChangeListener, ChangeListener, Helpful { 17 16 17 private static final double zoomStep = 1.1; 18 18 private final MapView mv; 19 19 private boolean preventChange; 20 private int lastValue; 20 21 21 22 MapSlider(MapView mv) { 22 super( 35, 150);23 super(0, 150); 23 24 setOpaque(false); 24 25 this.mv = mv; 25 26 mv.addPropertyChangeListener("scale", this); … … class MapSlider extends JSlider implements PropertyChangeListener, ChangeListene 30 31 31 32 @Override 32 33 public void propertyChange(PropertyChangeEvent evt) { 33 if (getModel().getValueIsAdjusting()) return; 34 35 ProjectionBounds world = this.mv.getMaxProjectionBounds(); 36 ProjectionBounds current = this.mv.getProjectionBounds(); 37 38 double cur_e = current.maxEast-current.minEast; 39 double cur_n = current.maxNorth-current.minNorth; 40 double e = world.maxEast-world.minEast; 41 double n = world.maxNorth-world.minNorth; 42 int zoom = 0; 43 44 while (zoom <= 150) { 45 e /= 1.1; 46 n /= 1.1; 47 if (e < cur_e && n < cur_n) { 48 break; 49 } 50 ++zoom; 51 } 34 double maxScale = this.mv.getMaxScale(); 35 int zoom = (int) Math.round(Math.log(maxScale/mv.getScale())/Math.log(zoomStep)); 52 36 preventChange = true; 53 37 setValue(zoom); 38 lastValue = zoom; 54 39 preventChange = false; 55 40 } 56 41 … … class MapSlider extends JSlider implements PropertyChangeListener, ChangeListene 58 43 public void stateChanged(ChangeEvent e) { 59 44 if (preventChange) return; 60 45 61 ProjectionBounds world = this.mv.getMaxProjectionBounds(); 62 double fact = Math.pow(1.1, getValue()); 63 double es = world.maxEast-world.minEast; 64 double n = world.maxNorth-world.minNorth; 65 66 this.mv.zoomTo(new ProjectionBounds(this.mv.getCenter(), es/fact, n/fact)); 46 if (!getModel().getValueIsAdjusting() && mv.getNativeScaleLayer() != null) { 47 if (getValue() < lastValue) { 48 mv.zoomOut(); 49 } else if (getValue() > lastValue) { 50 mv.zoomIn(); 51 } 52 } else { 53 double maxScale = this.mv.getMaxScale(); 54 double scale = maxScale/Math.pow(zoomStep, getValue()); 55 double snapped = mv.scaleFloor(scale); 56 mv.zoomTo(this.mv.getCenter(), snapped); 57 } 58 propertyChange(null); 67 59 } 68 60 69 61 @Override -
src/org/openstreetmap/josm/gui/MapView.java
diff --git a/src/org/openstreetmap/josm/gui/MapView.java b/src/org/openstreetmap/josm/gui/MapView.java index 530856e..83e9b36 100644
a b import org.openstreetmap.josm.gui.layer.ImageryLayer; 59 59 import org.openstreetmap.josm.gui.layer.Layer; 60 60 import org.openstreetmap.josm.gui.layer.MapViewPaintable; 61 61 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 62 import org.openstreetmap.josm.gui.layer.NativeScaleLayer; 62 63 import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer; 63 64 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer; 64 65 import org.openstreetmap.josm.gui.layer.markerlayer.PlayHeadMarker; … … implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer 412 413 ((OsmDataLayer) layer).addLayerStateChangeListener(this); 413 414 } 414 415 416 if (layer instanceof NativeScaleLayer) { 417 Main.map.mapView.setNativeScaleLayer((NativeScaleLayer) layer); 418 } 419 415 420 layer.addPropertyChangeListener(this); 416 421 Main.addProjectionChangeListener(layer); 417 422 AudioPlayer.reset(); … … implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer 914 919 * of {@link OsmDataLayer} also sets {@link #editLayer} to <code>layer</code>. 915 920 * 916 921 * @param layer the layer to be activate; must be one of the layers in the list of layers 917 * @throws IllegalArgumentException if layer is not in the lis of layers922 * @throws IllegalArgumentException if layer is not in the list of layers 918 923 */ 919 924 public void setActiveLayer(Layer layer) { 920 925 EnumSet<LayerListenerType> listenersToFire; -
src/org/openstreetmap/josm/gui/NavigatableComponent.java
diff --git a/src/org/openstreetmap/josm/gui/NavigatableComponent.java b/src/org/openstreetmap/josm/gui/NavigatableComponent.java index cfdb495..1939de3 100644
a b import org.openstreetmap.josm.data.osm.Way; 44 44 import org.openstreetmap.josm.data.osm.WaySegment; 45 45 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; 46 46 import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors; 47 import org.openstreetmap.josm.data.preferences.BooleanProperty; 48 import org.openstreetmap.josm.data.preferences.DoubleProperty; 47 49 import org.openstreetmap.josm.data.preferences.IntegerProperty; 48 50 import org.openstreetmap.josm.data.projection.Projection; 49 51 import org.openstreetmap.josm.data.projection.Projections; 50 52 import org.openstreetmap.josm.gui.download.DownloadDialog; 51 53 import org.openstreetmap.josm.gui.help.Helpful; 54 import org.openstreetmap.josm.gui.layer.NativeScaleLayer; 55 import org.openstreetmap.josm.gui.layer.NativeScaleLayer.Scale; 56 import org.openstreetmap.josm.gui.layer.NativeScaleLayer.ScaleList; 52 57 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles; 53 58 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource; 54 59 import org.openstreetmap.josm.gui.util.CursorManager; … … public class NavigatableComponent extends JComponent implements Helpful { 89 94 }; 90 95 91 96 public static final IntegerProperty PROP_SNAP_DISTANCE = new IntegerProperty("mappaint.node.snap-distance", 10); 97 public static final DoubleProperty PROP_ZOOM_RATIO = new DoubleProperty("zoom.ratio", 2.0); 98 public static final BooleanProperty PROP_ZOOM_INTERMEDIATE_STEPS = new BooleanProperty("zoom.intermediate-steps", true); 92 99 93 100 public static final String PROPNAME_CENTER = "center"; 94 101 public static final String PROPNAME_SCALE = "scale"; 95 102 96 103 /** 104 * The layer which scale is set to. 105 */ 106 private transient NativeScaleLayer nativeScaleLayer; 107 108 /** 97 109 * the zoom listeners 98 110 */ 99 111 private static final CopyOnWriteArrayList<ZoomChangeListener> zoomChangeListeners = new CopyOnWriteArrayList<>(); … … public class NavigatableComponent extends JComponent implements Helpful { 143 155 */ 144 156 public NavigatableComponent() { 145 157 setLayout(null); 158 PROP_ZOOM_RATIO.get(); // make sure it is available in preferences 159 } 160 161 /** 162 * Choose a layer that scale will be snap to its native scales. 163 * @param nativeScaleLayer 164 */ 165 public void setNativeScaleLayer(NativeScaleLayer nativeScaleLayer) { 166 this.nativeScaleLayer = nativeScaleLayer; 167 zoomTo(center, scaleRound(scale)); 168 repaint(); 169 } 170 171 /** 172 * Replies the layer which scale is set to. 173 * @return the current scale layer (may be null) 174 */ 175 public NativeScaleLayer getNativeScaleLayer() { 176 return nativeScaleLayer; 177 } 178 179 /** 180 * Get a new scale that is zoomed in from previous scale 181 * and snapped to selected native scale layer. 182 * @return new scale 183 */ 184 public double scaleZoomIn() { 185 return scaleZoomManyTimes(-1); 186 } 187 188 /** 189 * Get a new scale that is zoomed out from previous scale 190 * and snapped to selected native scale layer. 191 * @return new scale 192 */ 193 public double scaleZoomOut() { 194 return scaleZoomManyTimes(1); 195 } 196 197 /** 198 * Get a new scale that is zoomed in/out a number of times 199 * from previous scale and snapped to selected native scale layer. 200 * @param times count of zoom operations, negative means zoom in 201 * @return new scale 202 */ 203 public double scaleZoomManyTimes(int times) { 204 if (nativeScaleLayer != null) { 205 ScaleList scaleList = nativeScaleLayer.getNativeScales(); 206 if (PROP_ZOOM_INTERMEDIATE_STEPS.get()) { 207 scaleList = scaleList.withIntermediateSteps(PROP_ZOOM_RATIO.get()); 208 } 209 Scale scale = scaleList.scaleZoomTimes(getScale(), PROP_ZOOM_RATIO.get(), times); 210 return scale.scale; 211 } else { 212 return getScale() * Math.pow(PROP_ZOOM_RATIO.get(), times); 213 } 214 } 215 216 /** 217 * Get a scale snapped to native resolutions, use round method. 218 * It gives nearest step from scale list. 219 * Use round method. 220 * @param scale to snap 221 * @return snapped scale 222 */ 223 public double scaleRound(double scale) { 224 return scaleSnap(scale, false); 225 } 226 227 /** 228 * Get a scale snapped to native resolutions. 229 * It gives nearest lower step from scale list, usable to fit objects. 230 * @param scale to snap 231 * @return snapped scale 232 */ 233 public double scaleFloor(double scale) { 234 return scaleSnap(scale, true); 235 } 236 237 /** 238 * Get a scale snapped to native resolutions. 239 * It gives nearest lower step from scale list, usable to fit objects. 240 * @param scale to snap 241 * @param floor use floor instead of round, set true when fitting view to objects 242 * @return new scale 243 */ 244 public double scaleSnap(double scale, boolean floor) { 245 if (nativeScaleLayer != null) { 246 ScaleList scaleList = nativeScaleLayer.getNativeScales(); 247 return scaleList.getSnapScale(scale, PROP_ZOOM_RATIO.get(), floor).scale; 248 } else { 249 return scale; 250 } 251 } 252 253 /** 254 * Zoom in current view. Use configured zoom step and scaling settings. 255 */ 256 public void zoomIn() { 257 zoomTo(center, scaleZoomIn()); 258 } 259 260 /** 261 * Zoom out current view. Use configured zoom step and scaling settings. 262 */ 263 public void zoomOut() { 264 zoomTo(center, scaleZoomOut()); 146 265 } 147 266 148 267 protected DataSet getCurrentDataSet() { … … public class NavigatableComponent extends JComponent implements Helpful { 435 554 } 436 555 } 437 556 557 // snap scale to imagery if needed 558 scale = scaleRound(scale); 559 438 560 if (!newCenter.equals(center) || !Utils.equalsEpsilon(scale, newScale)) { 439 561 if (!initial) { 440 562 pushZoomUndo(center, scale); … … public class NavigatableComponent extends JComponent implements Helpful { 516 638 } 517 639 } 518 640 641 public void zoomManyTimes(double x, double y, int times) { 642 double oldScale = scale; 643 double newScale = scaleZoomManyTimes(times); 644 zoomToFactor(x, y, newScale / oldScale); 645 } 646 519 647 public void zoomToFactor(double x, double y, double factor) { 520 648 double newScale = scale*factor; 521 649 // New center position so that point under the mouse pointer stays the same place as it was before zooming … … public class NavigatableComponent extends JComponent implements Helpful { 549 677 double scaleY = (box.maxNorth-box.minNorth)/h; 550 678 double newScale = Math.max(scaleX, scaleY); 551 679 680 newScale = scaleFloor(newScale); 552 681 zoomTo(box.getCenter(), newScale); 553 682 } 554 683 … … public class NavigatableComponent extends JComponent implements Helpful { 1504 1633 } 1505 1634 repaint(); 1506 1635 } 1636 1637 /** 1638 * Get a max scale for projection that describes world in 256 pixels 1639 * @return max scale 1640 */ 1641 public double getMaxScale() { 1642 ProjectionBounds world = getMaxProjectionBounds(); 1643 return Math.max( 1644 world.maxNorth-world.minNorth, 1645 world.maxEast-world.minEast 1646 )/256; 1647 } 1507 1648 } -
src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
diff --git a/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java b/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java index 4223c02..4031c5e 100644
a b import org.openstreetmap.josm.gui.layer.JumpToMarkerActions; 60 60 import org.openstreetmap.josm.gui.layer.Layer; 61 61 import org.openstreetmap.josm.gui.layer.Layer.LayerAction; 62 62 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 63 import org.openstreetmap.josm.gui.layer.NativeScaleLayer; 63 64 import org.openstreetmap.josm.gui.util.GuiHelper; 64 65 import org.openstreetmap.josm.gui.widgets.DisableShortcutsOnFocusGainedTextField; 65 66 import org.openstreetmap.josm.gui.widgets.JosmTextField; … … public class LayerListDialog extends ToggleDialog { 187 188 layerList.getColumnModel().getColumn(0).setMaxWidth(12); 188 189 layerList.getColumnModel().getColumn(0).setPreferredWidth(12); 189 190 layerList.getColumnModel().getColumn(0).setResizable(false); 190 layerList.getColumnModel().getColumn(1).setCellRenderer(new LayerVisibleCellRenderer()); 191 layerList.getColumnModel().getColumn(1).setCellEditor(new LayerVisibleCellEditor(new LayerVisibleCheckBox())); 192 layerList.getColumnModel().getColumn(1).setMaxWidth(16); 193 layerList.getColumnModel().getColumn(1).setPreferredWidth(16); 191 192 layerList.getColumnModel().getColumn(1).setCellRenderer(new NativeScaleLayerCellRenderer()); 193 layerList.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(new NativeScaleLayerCheckBox())); 194 layerList.getColumnModel().getColumn(1).setMaxWidth(12); 195 layerList.getColumnModel().getColumn(1).setPreferredWidth(12); 194 196 layerList.getColumnModel().getColumn(1).setResizable(false); 195 layerList.getColumnModel().getColumn(2).setCellRenderer(new LayerNameCellRenderer()); 196 layerList.getColumnModel().getColumn(2).setCellEditor(new LayerNameCellEditor(new DisableShortcutsOnFocusGainedTextField())); 197 198 layerList.getColumnModel().getColumn(2).setCellRenderer(new LayerVisibleCellRenderer()); 199 layerList.getColumnModel().getColumn(2).setCellEditor(new LayerVisibleCellEditor(new LayerVisibleCheckBox())); 200 layerList.getColumnModel().getColumn(2).setMaxWidth(16); 201 layerList.getColumnModel().getColumn(2).setPreferredWidth(16); 202 layerList.getColumnModel().getColumn(2).setResizable(false); 203 204 layerList.getColumnModel().getColumn(3).setCellRenderer(new LayerNameCellRenderer()); 205 layerList.getColumnModel().getColumn(3).setCellEditor(new LayerNameCellEditor(new DisableShortcutsOnFocusGainedTextField())); 197 206 // Disable some default JTable shortcuts to use JOSM ones (see #5678, #10458) 198 207 for (KeyStroke ks : new KeyStroke[] { 199 208 KeyStroke.getKeyStroke(KeyEvent.VK_C, GuiHelper.getMenuShortcutKeyMaskEx()), … … public class LayerListDialog extends ToggleDialog { 1025 1034 } 1026 1035 } 1027 1036 1037 private static class NativeScaleLayerCheckBox extends JCheckBox { 1038 NativeScaleLayerCheckBox() { 1039 setHorizontalAlignment(javax.swing.SwingConstants.CENTER); 1040 ImageIcon blank = ImageProvider.get("dialogs/layerlist", "blank"); 1041 ImageIcon active = ImageProvider.get("dialogs/layerlist", "scale"); 1042 setIcon(blank); 1043 setSelectedIcon(active); 1044 } 1045 } 1046 1028 1047 private static class ActiveLayerCellRenderer implements TableCellRenderer { 1029 1048 private final JCheckBox cb; 1030 1049 … … public class LayerListDialog extends ToggleDialog { 1037 1056 1038 1057 @Override 1039 1058 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 1040 boolean active = 1059 boolean active = value != null && (Boolean) value; 1041 1060 cb.setSelected(active); 1042 1061 cb.setToolTipText(active ? tr("this layer is the active layer") : tr("this layer is not currently active (click to activate)")); 1043 1062 return cb; … … public class LayerListDialog extends ToggleDialog { 1078 1097 } 1079 1098 } 1080 1099 1100 private static class NativeScaleLayerCellRenderer implements TableCellRenderer { 1101 private final JCheckBox cb; 1102 1103 /** 1104 * Constructs a new {@code ActiveLayerCellRenderer}. 1105 */ 1106 NativeScaleLayerCellRenderer() { 1107 cb = new NativeScaleLayerCheckBox(); 1108 } 1109 1110 @Override 1111 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 1112 Layer layer = (Layer) value; 1113 if (layer instanceof NativeScaleLayer) { 1114 boolean active = layer != null && layer == Main.map.mapView.getNativeScaleLayer(); 1115 cb.setSelected(active); 1116 cb.setToolTipText(active 1117 ? tr("scale follows native resolution of this layer") 1118 : tr("scale follows native resolution of another layer (click to set this layer)") 1119 ); 1120 } else { 1121 cb.setSelected(false); 1122 cb.setToolTipText(tr("this layer has no native resolution")); 1123 } 1124 return cb; 1125 } 1126 } 1127 1081 1128 private class LayerNameCellRenderer extends DefaultTableCellRenderer { 1082 1129 1083 1130 protected boolean isActiveLayer(Layer layer) { … … public class LayerListDialog extends ToggleDialog { 1549 1596 return Main.map.mapView.getActiveLayer(); 1550 1597 } 1551 1598 1599 /** 1600 * Replies the scale layer. null, if no active layer is available 1601 * 1602 * @return the scale layer. null, if no active layer is available 1603 */ 1604 protected NativeScaleLayer getNativeScaleLayer() { 1605 if (!Main.isDisplayingMapView()) return null; 1606 return Main.map.mapView.getNativeScaleLayer(); 1607 } 1608 1552 1609 /* ------------------------------------------------------------------------------ */ 1553 1610 /* Interface TableModel */ 1554 1611 /* ------------------------------------------------------------------------------ */ … … public class LayerListDialog extends ToggleDialog { 1562 1619 1563 1620 @Override 1564 1621 public int getColumnCount() { 1565 return 3;1622 return 4; 1566 1623 } 1567 1624 1568 1625 @Override … … public class LayerListDialog extends ToggleDialog { 1573 1630 case 0: return layers.get(row) == getActiveLayer(); 1574 1631 case 1: return layers.get(row); 1575 1632 case 2: return layers.get(row); 1633 case 3: return layers.get(row); 1576 1634 default: throw new RuntimeException(); 1577 1635 } 1578 1636 } … … public class LayerListDialog extends ToggleDialog { 1597 1655 l.setVisible(true); 1598 1656 break; 1599 1657 case 1: 1600 l.setVisible((Boolean) value); 1658 if (Main.map.mapView.getNativeScaleLayer() == l) { 1659 Main.map.mapView.setNativeScaleLayer(null); 1660 } else if (l instanceof NativeScaleLayer) { 1661 Main.map.mapView.setNativeScaleLayer((NativeScaleLayer) l); 1662 l.setVisible(true); 1663 // set above imagery layers invisible 1664 for (int i=0; i<row; i++) { 1665 Layer above = layers.get(i); 1666 if (above instanceof ImageryLayer && 1667 above.isVisible() && 1668 above.getOpacity() == 1) { 1669 above.setVisible(false); 1670 } 1671 } 1672 } 1601 1673 break; 1602 1674 case 2: 1675 l.setVisible((Boolean) value); 1676 break; 1677 case 3: 1603 1678 l.rename((String) value); 1604 1679 break; 1605 1680 default: throw new RuntimeException(); -
new file src/org/openstreetmap/josm/gui/layer/NativeScaleLayer.java
diff --git a/src/org/openstreetmap/josm/gui/layer/NativeScaleLayer.java b/src/org/openstreetmap/josm/gui/layer/NativeScaleLayer.java new file mode 100644 index 0000000..e12d2ac
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.layer; 3 4 import java.util.ArrayList; 5 6 import org.openstreetmap.josm.gui.NavigatableComponent; 7 8 /** 9 * Represents a layer that has native scales. 10 * @author András Kolesár 11 */ 12 public interface NativeScaleLayer { 13 14 /** 15 * Get native scales of this layer. 16 * @return {@link ScaleList} of native scales 17 */ 18 public ScaleList getNativeScales(); 19 20 /** 21 * Represents a scale with native flag, used in {@link ScaleList} 22 */ 23 public static class Scale { 24 /** 25 * Scale factor, same unit as in {@link NavigatableComponent} 26 */ 27 public double scale; 28 29 /** 30 * True if this scale is native resolution for data source. 31 */ 32 public boolean isNative; 33 34 private int index; 35 36 /** 37 * Constructs a new Scale with given scale, native defaults to true. 38 * @param scale 39 */ 40 public Scale(double scale) { 41 this.scale = scale; 42 this.isNative = true; 43 } 44 45 /** 46 * Constructs a new Scale with given scale and native values. 47 * @param scale 48 * @param isNative 49 */ 50 public Scale(double scale, boolean isNative) { 51 this.scale = scale; 52 this.isNative = isNative; 53 } 54 55 /** 56 * Constructs a new Scale with given scale, native and index values. 57 * @param scale 58 * @param isNative 59 * @param index 60 */ 61 public Scale(double scale, boolean isNative, int index) { 62 this.scale = scale; 63 this.isNative = isNative; 64 this.index = index; 65 } 66 67 @Override 68 public String toString() { 69 return String.format("%f [%s]", scale, isNative); 70 } 71 72 /** 73 * Get index of this scale in a {@link ScaleList} 74 * @return index 75 */ 76 public int getIndex() { 77 return index; 78 } 79 } 80 81 /** 82 * List of scales, may include intermediate steps 83 * between native resolutions 84 */ 85 public static class ScaleList extends ArrayList<Scale> { 86 87 /** 88 * Returns a ScaleList that has intermediate steps between native scales. 89 * Native steps are split to equal steps near given ratio. 90 * @param ratio user defined zoom ratio 91 * @return a {@link ScaleList} with intermediate steps 92 */ 93 public ScaleList withIntermediateSteps(double ratio) { 94 int size = size(); 95 ScaleList result = new ScaleList(); 96 Scale previous = null; 97 for (int i=0; i<size; i++) { 98 Scale current = this.get(i); 99 if (previous != null) { 100 double step = previous.scale / current.scale; 101 double factor = Math.log(step) / Math.log(ratio); 102 int steps = (int) Math.round(factor); 103 double smallStep = Math.pow(step, 1.0/steps); 104 for (int j=1; j<steps; j++) { 105 double intermediate = previous.scale / Math.pow(smallStep, j); 106 result.add(new Scale(intermediate, false)); 107 } 108 } 109 result.add(current); 110 previous = current; 111 } 112 return result; 113 } 114 115 /** 116 * Get a scale from this ScaleList or a new scale if zoomed outside. 117 * @param scale previous scale 118 * @param ratio zoom ratio from starting from previous scale 119 * @param floor use floor instead of round, set true when fitting view to objects 120 * @return new {@link Scale} 121 */ 122 public Scale getSnapScale(double scale, double ratio, boolean floor) { 123 int size = size(); 124 Scale first = get(0); 125 Scale last = get(size-1); 126 if (scale > first.scale) { 127 double step = scale / first.scale; 128 double factor = Math.log(step) / Math.log(ratio); 129 int steps = (int) (floor ? Math.floor(factor) : Math.round(factor)); 130 if (steps == 0) { 131 return new Scale(first.scale, first.isNative, steps); 132 } else { 133 return new Scale(first.scale * Math.pow(ratio, steps), false, steps); 134 } 135 } else if (scale < last.scale) { 136 double step = last.scale / scale; 137 double factor = Math.log(step) / Math.log(ratio); 138 int steps = (int) (floor ? Math.floor(factor) : Math.round(factor)); 139 if (steps == 0) { 140 return new Scale(last.scale, last.isNative, size-1+steps); 141 } else { 142 return new Scale(last.scale / Math.pow(ratio, steps), false, size-1+steps); 143 } 144 } else { 145 Scale previous = null; 146 for (int i=0; i<size; i++) { 147 Scale current = this.get(i); 148 if (previous != null) { 149 if (scale <= previous.scale && scale >= current.scale) { 150 if (floor || previous.scale / scale < scale / current.scale) { 151 return new Scale(previous.scale, previous.isNative, i-1); 152 } else { 153 return new Scale(current.scale, current.isNative, i); 154 } 155 } 156 } 157 previous = current; 158 } 159 return null; 160 } 161 } 162 163 /** 164 * Get new scale for zoom in/out with a ratio at a number of times. 165 * Used by mousewheel zoom where wheel can step more than one between events. 166 * @param scale previois scale 167 * @param ratio user defined zoom ratio 168 * @param times number of times to zoom 169 * @return new {@link Scale} object from {@link ScaleList} or outside 170 */ 171 public Scale scaleZoomTimes(double scale, double ratio, int times) { 172 Scale next = getSnapScale(scale, ratio, false); 173 int abs = Math.abs(times); 174 for (int i=0; i<abs; i++) { 175 if (times<0) { 176 next = getNextIn(next, ratio); 177 } else { 178 next = getNextOut(next, ratio); 179 } 180 } 181 return next; 182 } 183 184 /** 185 * Get new scale for zoom in. 186 * @param scale previous scale 187 * @param ratio user defined zoom ratio 188 * @return next scale in list or a new scale when zoomed outside 189 */ 190 public Scale scaleZoomIn(double scale, double ratio) { 191 Scale snap = getSnapScale(scale, ratio, false); 192 Scale next = getNextIn(snap, ratio); 193 return next; 194 } 195 196 /** 197 * Get new scale for zoom out. 198 * @param scale previous scale 199 * @param ratio user defined zoom ratio 200 * @return next scale in list or a new scale when zoomed outside 201 */ 202 public Scale scaleZoomOut(double scale, double ratio) { 203 Scale snap = getSnapScale(scale, ratio, false); 204 Scale next = getNextOut(snap, ratio); 205 return next; 206 } 207 208 @Override 209 public String toString() { 210 StringBuilder stringBuilder = new StringBuilder(); 211 int size = size(); 212 for (int i=0; i<size; i++) { 213 stringBuilder.append(get(i) + "\n"); 214 } 215 return stringBuilder.toString(); 216 } 217 218 private Scale getNextIn(Scale scale, double ratio) { 219 int nextIndex = scale.getIndex() + 1; 220 if (nextIndex <= 0 || nextIndex > size()-1) { 221 return new Scale(scale.scale / ratio, nextIndex == 0, nextIndex); 222 } else { 223 Scale nextScale = get(nextIndex); 224 return new Scale(nextScale.scale, nextScale.isNative, nextIndex); 225 } 226 } 227 228 private Scale getNextOut(Scale scale, double ratio) { 229 int nextIndex = scale.getIndex() - 1; 230 if (nextIndex < 0 || nextIndex >= size()-1) { 231 return new Scale(scale.scale * ratio, nextIndex == size()-1, nextIndex); 232 } else { 233 Scale nextScale = get(nextIndex); 234 return new Scale(nextScale.scale, nextScale.isNative, nextIndex); 235 } 236 } 237 } 238 } -
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 aad0c67..58561df 100644
a b package org.openstreetmap.josm.gui.layer; 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 6 import org.apache.commons.jcs.access.CacheAccess; 7 import org.openstreetmap.gui.jmapviewer.OsmMercator; 7 8 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader; 8 9 import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource; 9 10 import org.openstreetmap.gui.jmapviewer.tilesources.ScanexTileSource; … … import org.openstreetmap.josm.data.projection.Projection; 28 29 * @author Upliner <upliner@gmail.com> 29 30 * 30 31 */ 31 public class TMSLayer extends AbstractCachedTileSourceLayer {32 public class TMSLayer extends AbstractCachedTileSourceLayer implements NativeScaleLayer { 32 33 private static final String CACHE_REGION_NAME = "TMS"; 33 34 34 35 private static final String PREFERENCE_PREFIX = "imagery.tms"; … … public class TMSLayer extends AbstractCachedTileSourceLayer { 144 145 public static CacheAccess<String, BufferedImageCacheEntry> getCache() { 145 146 return AbstractCachedTileSourceLayer.getCache(CACHE_REGION_NAME); 146 147 } 148 149 @Override 150 public ScaleList getNativeScales() { 151 ScaleList scales = new ScaleList(); 152 for (int zoom = info.getMinZoom(); zoom <= info.getMaxZoom(); zoom++) { 153 double scale = OsmMercator.EARTH_RADIUS * Math.PI * 2 / Math.pow(2, zoom) / OsmMercator.DEFAUL_TILE_SIZE; 154 scales.add(new Scale(scale)); 155 } 156 return scales; 157 } 147 158 } -
src/org/openstreetmap/josm/gui/layer/WMTSLayer.java
diff --git a/src/org/openstreetmap/josm/gui/layer/WMTSLayer.java b/src/org/openstreetmap/josm/gui/layer/WMTSLayer.java index ad643e3..5da5d31 100644
a b import org.openstreetmap.josm.gui.MapView; 30 30 * @author Wiktor Niesiobędzki 31 31 * 32 32 */ 33 public class WMTSLayer extends AbstractCachedTileSourceLayer {33 public class WMTSLayer extends AbstractCachedTileSourceLayer implements NativeScaleLayer { 34 34 /** 35 35 * default setting of autozoom per layer 36 36 */ … … public class WMTSLayer extends AbstractCachedTileSourceLayer { 81 81 82 82 @Override 83 83 protected int getBestZoom() { 84 if (!Main.isDisplayingMapView()) return 1;85 86 for (int i = getMinZoomLvl() + 1; i <= getMaxZoomLvl(); i++) {87 double ret = getTileToScreenRatio(i);88 if ( ret < 1) {89 return i - 1;84 if (!Main.isDisplayingMapView()) return 0; 85 ScaleList scaleList = getNativeScales(); 86 for (int i = scaleList.size()-1; i >= 0; i--) { 87 Scale scale = scaleList.get(i); 88 if (scale.scale >= Main.map.mapView.getScale()) { 89 return i; 90 90 } 91 91 } 92 return getMaxZoomLvl(); 92 return 0; 93 } 94 95 @Override 96 protected int getMaxZoomLvl() { 97 return getNativeScales().size()-1; 98 } 99 100 @Override 101 protected int getMinZoomLvl() { 102 return 0; 93 103 } 94 104 95 105 @Override … … public class WMTSLayer extends AbstractCachedTileSourceLayer { 129 139 public static CacheAccess<String, BufferedImageCacheEntry> getCache() { 130 140 return AbstractCachedTileSourceLayer.getCache(CACHE_REGION_NAME); 131 141 } 142 143 @Override 144 public ScaleList getNativeScales() { 145 return ((WMTSTileSource) tileSource).getNativeScales(); 146 } 132 147 }