Ticket #2892: shortlinks.patch

File shortlinks.patch, 4.5 KB (added by plaicy, 15 years ago)
  • src/org/openstreetmap/josm/tools/OsmUrlToBounds.java

     
    22package org.openstreetmap.josm.tools;
    33
    44import java.util.HashMap;
     5import java.util.Map;
    56
    67import org.openstreetmap.josm.data.Bounds;
    78import org.openstreetmap.josm.data.coor.LatLon;
    89
    910public class OsmUrlToBounds {
     11    private static final String SHORTLINK_PREFIX = "http://osm.org/go/";
     12
    1013    public static Bounds parse(String url) {
     14        Bounds b = parseShortLink(url);
     15        if (b != null) {
     16            return b;
     17        }
    1118        int i = url.indexOf('?');
    1219        if (i == -1)
    1320            return null;
     
    2027            }
    2128        }
    2229
    23         Bounds b = null;
    2430        try {
    2531            if (map.containsKey("bbox")) {
    2632                String bbox[] = map.get("bbox").split(",");
     
    3844                Double maxlon = Double.parseDouble(s);
    3945                b = new Bounds(new LatLon(minlat, minlon), new LatLon(maxlat, maxlon));
    4046            } else {
    41                 double size = 180.0 / Math.pow(2, Integer.parseInt(map.get("zoom")));
    42                 b = new Bounds(
    43                     new LatLon(parseDouble(map, "lat") - size/2, parseDouble(map, "lon") - size),
    44                     new LatLon(parseDouble(map, "lat") + size/2, parseDouble(map, "lon") + size));
     47                b = positionToBounds(parseDouble(map, "lat"),
     48                                     parseDouble(map, "lon"),
     49                                     Integer.parseInt(map.get("zoom")));
    4550            }
    4651        } catch (NumberFormatException x) {
    4752        } catch (NullPointerException x) {
     
    5560        return Double.parseDouble(map.get("m"+key));
    5661    }
    5762
     63    private static final char[] SHORTLINK_CHARS = {
     64        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
     65        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
     66        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
     67        'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
     68        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
     69        'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
     70        'w', 'x', 'y', 'z', '0', '1', '2', '3',
     71        '4', '5', '6', '7', '8', '9', '_', '@'
     72    };
     73
     74    /**
     75     * p
     76     *
     77     * @param url string for parsing
     78     *
     79     * @return Bounds if shortlink, null otherwise
     80     *
     81     * @see http://trac.openstreetmap.org/browser/sites/rails_port/lib/short_link.rb
     82     */
     83    private static Bounds parseShortLink(final String url) {
     84        if (!url.startsWith(SHORTLINK_PREFIX)) {
     85            return null;
     86        }
     87        final String shortLink = url.substring(SHORTLINK_PREFIX.length());
     88
     89        final Map<Character, Integer> array = new HashMap<Character, Integer>();
     90
     91        for (int i=0; i<SHORTLINK_CHARS.length; ++i) {
     92            array.put(SHORTLINK_CHARS[i], i);
     93        }
     94
     95        // long is necessary (need 32 bit positive value is needed)
     96        long x = 0;
     97        long y = 0;
     98        int zoom = 0;
     99        int zoomOffset = 0;
     100
     101        for (final char ch : shortLink.toCharArray()) {
     102            if (array.containsKey(ch)) {
     103                int val = array.get(ch);
     104                for (int i=0; i<3; ++i) {
     105                    x <<= 1;
     106                    if ((val & 32) != 0) {
     107                        x |= 1;
     108                    }
     109                    val <<= 1;
     110
     111                    y <<= 1;
     112                    if ((val & 32) != 0) {
     113                        y |= 1;
     114                    }
     115                    val <<= 1;
     116                }
     117                zoom += 3;
     118            } else {
     119                zoomOffset--;
     120            }
     121        }
     122
     123        x <<= 32 - zoom;
     124        y <<= 32 - zoom;
     125
     126        // 2**32 == 4294967296
     127        return positionToBounds(y * 180.0 / 4294967296.0 - 90.0,
     128                                x * 360.0 / 4294967296.0 - 180.0,
     129                                // TODO: -2 was not in ruby code
     130                                zoom - 8 - (zoomOffset % 3) - 2);
     131    }
     132
     133    private static Bounds positionToBounds(final double lat, final double lon, final int zoom) {
     134        final double size = 180.0 / Math.pow(2, zoom);
     135        return new Bounds(
     136                          new LatLon(lat - size/2, lon - size),
     137                          new LatLon(lat + size/2, lon + size));
     138    }
     139
     140
    58141    static public int getZoom(Bounds b)
    59142    {
    60143        // convert to mercator (for calculation of zoom only)