| | 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 | |