add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / contrib / spatial / src / java / org / apache / lucene / spatial / geohash / GeoHashUtils.java
1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 package org.apache.lucene.spatial.geohash;
19
20 import java.util.HashMap;
21 import java.util.Map;
22
23 /**
24  * Utilities for encoding and decoding geohashes. Based on
25  * <a href="http://en.wikipedia.org/wiki/Geohash">http://en.wikipedia.org/wiki/Geohash</a>.
26  */
27 public class GeoHashUtils {
28
29   private static final char[] BASE_32 = {'0', '1', '2', '3', '4', '5', '6',
30       '7', '8', '9', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n',
31       'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
32
33   private final static Map<Character,Integer> DECODE_MAP = new HashMap<Character,Integer>();
34
35   private static final int PRECISION = 12;
36   private static final int[] BITS = {16, 8, 4, 2, 1};
37
38   static {
39     for (int i = 0; i < BASE_32.length; i++) {
40       DECODE_MAP.put(Character.valueOf(BASE_32[i]), Integer.valueOf(i));
41     }
42   }
43
44   private GeoHashUtils() {  
45   }
46
47   /**
48    * Encodes the given latitude and longitude into a geohash
49    *
50    * @param latitude Latitude to encode
51    * @param longitude Longitude to encode
52    * @return Geohash encoding of the longitude and latitude
53    */
54   public static String encode(double latitude, double longitude) {
55     double[] latInterval = {-90.0, 90.0};
56     double[] lngInterval = {-180.0, 180.0};
57
58     final StringBuilder geohash = new StringBuilder();
59     boolean isEven = true;
60
61     int bit = 0;
62     int ch = 0;
63
64     while (geohash.length() < PRECISION) {
65       double mid = 0.0;
66       if (isEven) {
67         mid = (lngInterval[0] + lngInterval[1]) / 2D;
68         if (longitude > mid) {
69           ch |= BITS[bit];
70           lngInterval[0] = mid;
71         } else {
72           lngInterval[1] = mid;
73         }
74       } else {
75         mid = (latInterval[0] + latInterval[1]) / 2D;
76         if (latitude > mid) {
77           ch |= BITS[bit];
78           latInterval[0] = mid;
79         } else {
80           latInterval[1] = mid;
81         }
82       }
83
84       isEven = !isEven;
85
86       if (bit < 4) {
87         bit++;
88       } else {
89         geohash.append(BASE_32[ch]);
90         bit = 0;
91         ch = 0;
92       }
93     }
94
95     return geohash.toString();
96   }
97
98   /**
99    * Decodes the given geohash into a latitude and longitude
100    *
101    * @param geohash Geohash to deocde
102    * @return Array with the latitude at index 0, and longitude at index 1
103    */
104   public static double[] decode(String geohash) {
105     final double[] latInterval = {-90.0, 90.0};
106     final double[] lngInterval = {-180.0, 180.0};
107
108     boolean isEven = true;
109
110     double latitude;
111     double longitude;
112     for (int i = 0; i < geohash.length(); i++) {
113       final int cd = DECODE_MAP.get(Character.valueOf(
114           geohash.charAt(i))).intValue();
115
116       for (int mask : BITS) {
117         if (isEven) {
118           if ((cd & mask) != 0) {
119             lngInterval[0] = (lngInterval[0] + lngInterval[1]) / 2D;
120           } else {
121             lngInterval[1] = (lngInterval[0] + lngInterval[1]) / 2D;
122           }
123         } else {
124           if ((cd & mask) != 0) {
125             latInterval[0] = (latInterval[0] + latInterval[1]) / 2D;
126           } else {
127             latInterval[1] = (latInterval[0] + latInterval[1]) / 2D;
128           }
129         }
130         isEven = !isEven;
131       }
132
133     }
134     latitude = (latInterval[0] + latInterval[1]) / 2D;
135     longitude = (lngInterval[0] + lngInterval[1]) / 2D;
136
137     return new double[] {latitude, longitude};
138         }
139 }