Changeset 14628 in josm for trunk/src


Ignore:
Timestamp:
2019-01-03T20:06:44+01:00 (6 years ago)
Author:
simon04
Message:

fix #16706 - Zoom to selection should not zoom out for zoom on a node

Simplify bound enlargements in org.openstreetmap.josm.actions.AutoScaleAction#modeSelectionOrConflict

Location:
trunk/src/org/openstreetmap/josm
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/AutoScaleAction.java

    r14397 r14628  
    292292                mapView.zoomNext();
    293293                break;
    294             default:
    295                 BoundingXYVisitor bbox = getBoundingBox();
    296                 if (bbox != null && bbox.getBounds() != null) {
    297                     mapView.zoomTo(bbox);
    298                 }
    299             }
    300         }
    301         putValue("active", Boolean.TRUE);
     294            case PROBLEM:
     295                modeProblem(new ValidatorBoundingXYVisitor());
     296                break;
     297            case DATA:
     298                modeData(new BoundingXYVisitor());
     299                break;
     300            case LAYER:
     301                modeLayer(new BoundingXYVisitor());
     302                break;
     303            case SELECTION:
     304            case CONFLICT:
     305                modeSelectionOrConflict(new BoundingXYVisitor());
     306                break;
     307            case DOWNLOAD:
     308                modeDownload(new BoundingXYVisitor());
     309                break;
     310            }
     311            putValue("active", Boolean.TRUE);
     312        }
    302313    }
    303314
     
    328339    }
    329340
    330     private BoundingXYVisitor getBoundingBox() {
    331         switch (mode) {
    332         case PROBLEM:
    333             return modeProblem(new ValidatorBoundingXYVisitor());
    334         case DATA:
    335             return modeData(new BoundingXYVisitor());
    336         case LAYER:
    337             return modeLayer(new BoundingXYVisitor());
    338         case SELECTION:
    339         case CONFLICT:
    340             return modeSelectionOrConflict(new BoundingXYVisitor());
    341         case DOWNLOAD:
    342             return modeDownload(new BoundingXYVisitor());
    343         default:
    344             return new BoundingXYVisitor();
    345         }
    346     }
    347 
    348     private static BoundingXYVisitor modeProblem(ValidatorBoundingXYVisitor v) {
     341    private static void modeProblem(ValidatorBoundingXYVisitor v) {
    349342        TestError error = MainApplication.getMap().validatorDialog.getSelectedError();
    350343        if (error == null)
    351             return null;
     344            return;
    352345        v.visit(error);
    353346        if (v.getBounds() == null)
    354             return null;
    355         v.enlargeBoundingBox(Config.getPref().getDouble("validator.zoom-enlarge-bbox", 0.0002));
    356         return v;
    357     }
    358 
    359     private static BoundingXYVisitor modeData(BoundingXYVisitor v) {
     347            return;
     348        MainApplication.getMap().mapView.zoomTo(v);
     349    }
     350
     351    private static void modeData(BoundingXYVisitor v) {
    360352        for (Layer l : MainApplication.getLayerManager().getLayers()) {
    361353            l.visitBoundingBox(v);
    362354        }
    363         return v;
    364     }
    365 
    366     private BoundingXYVisitor modeLayer(BoundingXYVisitor v) {
     355        MainApplication.getMap().mapView.zoomTo(v);
     356    }
     357
     358    private void modeLayer(BoundingXYVisitor v) {
    367359        // try to zoom to the first selected layer
    368360        Layer l = getFirstSelectedLayer();
    369361        if (l == null)
    370             return null;
     362            return;
    371363        l.visitBoundingBox(v);
    372         return v;
    373     }
    374 
    375     private BoundingXYVisitor modeSelectionOrConflict(BoundingXYVisitor v) {
     364        MainApplication.getMap().mapView.zoomTo(v);
     365    }
     366
     367    private void modeSelectionOrConflict(BoundingXYVisitor v) {
    376368        Collection<IPrimitive> sel = new HashSet<>();
    377369        if (AutoScaleMode.SELECTION == mode) {
     
    395387                    tr("Information"),
    396388                    JOptionPane.INFORMATION_MESSAGE);
    397             return null;
     389            return;
    398390        }
    399391        for (IPrimitive osm : sel) {
    400392            osm.accept(v);
    401393        }
    402 
    403         // Increase the bounding box by up to 100% to give more context.
    404         v.enlargeBoundingBoxLogarithmically(100);
    405         // Make the bounding box at least 100 meter wide to
    406         // ensure reasonable zoom level when zooming onto single nodes.
    407         v.enlargeToMinSize(Config.getPref().getDouble("zoom_to_selection_min_size_in_meter", 100));
    408         return v;
    409     }
    410 
    411     private BoundingXYVisitor modeDownload(BoundingXYVisitor v) {
     394        if (v.getBounds() == null) {
     395            return;
     396        }
     397
     398        // Do not zoom if the current scale covers the selection, #16706
     399        final MapView mapView = MainApplication.getMap().mapView;
     400        final double mapScale = mapView.getScale();
     401        final double minScale = v.getBounds().getScale(mapView.getWidth(), mapView.getHeight());
     402        v.enlargeBoundingBoxLogarithmically();
     403        final double maxScale = v.getBounds().getScale(mapView.getWidth(), mapView.getHeight());
     404        if (minScale <= mapScale && mapScale < maxScale) {
     405            mapView.zoomTo(v.getBounds().getCenter());
     406        } else {
     407            mapView.zoomTo(v);
     408        }
     409    }
     410
     411    private void modeDownload(BoundingXYVisitor v) {
    412412        if (lastZoomTime > 0 &&
    413413                System.currentTimeMillis() - lastZoomTime > Config.getPref().getLong("zoom.bounds.reset.time", TimeUnit.SECONDS.toMillis(10))) {
     
    438438            }
    439439        }
    440         return v;
     440        MainApplication.getMap().mapView.zoomTo(v);
    441441    }
    442442
  • trunk/src/org/openstreetmap/josm/data/ProjectionBounds.java

    r12818 r14628  
    192192        return !Utils.equalsEpsilon(minEast, maxEast) || !Utils.equalsEpsilon(minNorth, maxNorth);
    193193    }
     194
     195    /**
     196     * Computes the scale of this bounds with respect to the given width/height.
     197     * @param width the width
     198     * @param height the height
     199     * @return the computed scale
     200     */
     201    public double getScale(final int width, final int height) {
     202        // -20 to leave some border
     203        int w = width - 20;
     204        if (w < 20) {
     205            w = 20;
     206        }
     207        int h = height - 20;
     208        if (h < 20) {
     209            h = 20;
     210        }
     211
     212        double scaleX = getDeltaEast() / w;
     213        double scaleY = getDeltaNorth() / h;
     214        return Math.max(scaleX, scaleY);
     215    }
     216
     217    private double getDeltaNorth() {
     218        return maxNorth - minNorth;
     219    }
     220
     221    private double getDeltaEast() {
     222        return maxEast - minEast;
     223    }
    194224}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java

    r14379 r14628  
    33
    44import java.util.Collection;
     5import java.util.function.DoubleUnaryOperator;
    56
    67import org.openstreetmap.josm.data.Bounds;
     
    1920import org.openstreetmap.josm.data.osm.Way;
    2021import org.openstreetmap.josm.data.projection.ProjectionRegistry;
    21 import org.openstreetmap.josm.gui.MainApplication;
    22 import org.openstreetmap.josm.gui.MapFrame;
    2322import org.openstreetmap.josm.spi.preferences.Config;
    2423
     
    141140
    142141    /**
    143      * Enlarges the calculated bounding box by 0.002 degrees.
     142     * Enlarges the calculated bounding box by 0.001 degrees.
    144143     * If the bounding box has not been set (<code>min</code> or <code>max</code>
    145144     * equal <code>null</code>) this method does not do anything.
    146145     */
    147146    public void enlargeBoundingBox() {
    148         enlargeBoundingBox(Config.getPref().getDouble("edit.zoom-enlarge-bbox", 0.002));
     147        final double enlarge = Config.getPref().getDouble("edit.zoom-enlarge-bbox", 0.001);
     148        enlargeBoundingBox(enlarge, enlarge);
    149149    }
    150150
     
    154154     * equal <code>null</code>) this method does not do anything.
    155155     *
    156      * @param enlargeDegree number of degrees to enlarge on each side
    157      */
    158     public void enlargeBoundingBox(double enlargeDegree) {
     156     * @param enlargeDegreeX number of degrees to enlarge on each side along X
     157     * @param enlargeDegreeY number of degrees to enlarge on each side along Y
     158     */
     159    public void enlargeBoundingBox(double enlargeDegreeX, double enlargeDegreeY) {
    159160        if (bounds == null)
    160161            return;
     
    162163        LatLon maxLatlon = ProjectionRegistry.getProjection().eastNorth2latlon(bounds.getMax());
    163164        bounds = new ProjectionBounds(new LatLon(
    164                         Math.max(-90, minLatlon.lat() - enlargeDegree),
    165                         Math.max(-180, minLatlon.lon() - enlargeDegree)).getEastNorth(ProjectionRegistry.getProjection()),
     165                        Math.max(-90, minLatlon.lat() - enlargeDegreeY),
     166                        Math.max(-180, minLatlon.lon() - enlargeDegreeX)).getEastNorth(ProjectionRegistry.getProjection()),
    166167                new LatLon(
    167                         Math.min(90, maxLatlon.lat() + enlargeDegree),
    168                         Math.min(180, maxLatlon.lon() + enlargeDegree)).getEastNorth(ProjectionRegistry.getProjection()));
    169     }
    170 
    171     /**
    172      * Enlarges the bounding box up to <code>maxEnlargePercent</code>, depending on
     168                        Math.min(90, maxLatlon.lat() + enlargeDegreeY),
     169                        Math.min(180, maxLatlon.lon() + enlargeDegreeX)).getEastNorth(ProjectionRegistry.getProjection()));
     170    }
     171
     172    /**
     173     * Enlarges the bounding box up to 0.001 degrees, depending on
    173174     * its size. If the bounding box is small, it will be enlarged more in relation
    174175     * to its beginning size. The larger the bounding box, the smaller the change,
    175      * down to the minimum of 1% enlargement.
    176      *
    177      * Warning: if the bounding box only contains a single node, no expansion takes
    178      * place because a node has no width/height. Use {@link #enlargeBoundingBox(double)}
    179      * instead.
    180      *
    181      * Example: You specify enlargement to be up to 100%.
    182      *
    183      *          Bounding box is a small house: enlargement will be 95–100%, i.e.
    184      *          making enough space so that the house fits twice on the screen in
    185      *          each direction.
    186      *
    187      *          Bounding box is a large landuse, like a forest: Enlargement will
    188      *          be 1–10%, i.e. just add a little border around the landuse.
     176     * down to 0.0 degrees.
    189177     *
    190178     * If the bounding box has not been set (<code>min</code> or <code>max</code>
    191179     * equal <code>null</code>) this method does not do anything.
    192      *
    193      * @param maxEnlargePercent maximum enlargement in percentage (100.0 for 100%)
    194      */
    195     public void enlargeBoundingBoxLogarithmically(double maxEnlargePercent) {
     180     */
     181    public void enlargeBoundingBoxLogarithmically() {
    196182        if (bounds == null)
    197183            return;
    198 
    199         double diffEast = bounds.getMax().east() - bounds.getMin().east();
    200         double diffNorth = bounds.getMax().north() - bounds.getMin().north();
    201 
    202         double enlargeEast = Math.min(maxEnlargePercent - 10*Math.log(diffEast), 1)/100;
    203         double enlargeNorth = Math.min(maxEnlargePercent - 10*Math.log(diffNorth), 1)/100;
    204 
    205         visit(bounds.getMin().add(-enlargeEast/2, -enlargeNorth/2));
    206         visit(bounds.getMax().add(+enlargeEast/2, +enlargeNorth/2));
    207     }
    208 
    209     /**
    210      * Specify a degree larger than 0 in order to make the bounding box at least
    211      * the specified size in width and height. The value is ignored if the
    212      * bounding box is already larger than the specified amount.
    213      *
    214      * If the bounding box has not been set (<code>min</code> or <code>max</code>
    215      * equal <code>null</code>) this method does not do anything.
    216      *
    217      * If the bounding box contains objects and is to be enlarged, the objects
    218      * will be centered within the new bounding box.
    219      *
    220      * @param size minimum width and height in meter
    221      */
    222     public void enlargeToMinSize(double size) {
    223         if (bounds == null)
    224             return;
    225         // convert size from meters to east/north units
    226         MapFrame map = MainApplication.getMap();
    227         double enSize = size * map.mapView.getScale() / map.mapView.getDist100Pixel() * 100;
    228         visit(bounds.getMin().add(-enSize/2, -enSize/2));
    229         visit(bounds.getMax().add(+enSize/2, +enSize/2));
     184        final LatLon min = ProjectionRegistry.getProjection().eastNorth2latlon(bounds.getMin());
     185        final LatLon max = ProjectionRegistry.getProjection().eastNorth2latlon(bounds.getMax());
     186        final double deltaLat = max.lat() - min.lat();
     187        final double deltaLon = max.lon() - min.lon();
     188        // [0.001, 0.1] degree -> [0.001, 0.0] degree enlargement
     189        final DoubleUnaryOperator enlargement = deg -> deg < 0.001
     190                ? 0.001
     191                : deg < 0.1
     192                ? 0.001 - deg / 100
     193                : 0.0;
     194        enlargeBoundingBox(enlargement.applyAsDouble(deltaLon), enlargement.applyAsDouble(deltaLat));
    230195    }
    231196
  • trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java

    r14402 r14628  
    790790     */
    791791    public void zoomTo(ProjectionBounds box) {
    792         // -20 to leave some border
    793         int w = getWidth()-20;
    794         if (w < 20) {
    795             w = 20;
    796         }
    797         int h = getHeight()-20;
    798         if (h < 20) {
    799             h = 20;
    800         }
    801 
    802         double scaleX = (box.maxEast-box.minEast)/w;
    803         double scaleY = (box.maxNorth-box.minNorth)/h;
    804         double newScale = Math.max(scaleX, scaleY);
    805 
     792        double newScale = box.getScale(getWidth(), getHeight());
    806793        newScale = scaleFloor(newScale);
    807794        zoomTo(box.getCenter(), newScale);
Note: See TracChangeset for help on using the changeset viewer.